diff options
author | 2023-09-10 21:50:15 +0200 | |
---|---|---|
committer | 2023-09-10 21:50:15 +0200 | |
commit | 4b9f6f7e53e0b2e9aae59df2bbffc0bdd6805aea (patch) | |
tree | 40bc3e62a343df8bd0076b609d57248f7bd9448b /caches/SQLiteCache.php | |
parent | a786bbd4e0d45a98446ed0384ed57705a17b89d3 (diff) | |
download | rss-bridge-4b9f6f7e53e0b2e9aae59df2bbffc0bdd6805aea.tar.gz rss-bridge-4b9f6f7e53e0b2e9aae59df2bbffc0bdd6805aea.tar.zst rss-bridge-4b9f6f7e53e0b2e9aae59df2bbffc0bdd6805aea.zip |
fix: rewrite and improve caching (#3594)
Diffstat (limited to 'caches/SQLiteCache.php')
-rw-r--r-- | caches/SQLiteCache.php | 92 |
1 files changed, 42 insertions, 50 deletions
diff --git a/caches/SQLiteCache.php b/caches/SQLiteCache.php index 92235862..beb33e88 100644 --- a/caches/SQLiteCache.php +++ b/caches/SQLiteCache.php @@ -1,10 +1,10 @@ <?php +declare(strict_types=1); + class SQLiteCache implements CacheInterface { private \SQLite3 $db; - private string $scope; - private string $key; private array $config; public function __construct(array $config) @@ -31,85 +31,77 @@ class SQLiteCache implements CacheInterface $this->db->exec("CREATE TABLE storage ('key' BLOB PRIMARY KEY, 'value' BLOB, 'updated' INTEGER)"); } $this->db->busyTimeout($config['timeout']); + // https://www.sqlite.org/pragma.html#pragma_journal_mode + $this->db->exec('PRAGMA journal_mode = wal'); + // https://www.sqlite.org/pragma.html#pragma_synchronous + $this->db->exec('PRAGMA synchronous = NORMAL'); } - public function loadData(int $timeout = 86400) + public function get(string $key, $default = null) { + $cacheKey = $this->createCacheKey($key); $stmt = $this->db->prepare('SELECT value, updated FROM storage WHERE key = :key'); - $stmt->bindValue(':key', $this->getCacheKey()); + $stmt->bindValue(':key', $cacheKey); $result = $stmt->execute(); if (!$result) { - return null; + return $default; } $row = $result->fetchArray(\SQLITE3_ASSOC); if ($row === false) { - return null; + return $default; } - $value = $row['value']; - $modificationTime = $row['updated']; - if (time() - $timeout < $modificationTime) { - $data = unserialize($value); - if ($data === false) { - Logger::error(sprintf("Failed to unserialize: '%s'", mb_substr($value, 0, 100))); - return null; + $expiration = $row['updated']; + if ($expiration === 0 || $expiration > time()) { + $blob = $row['value']; + $value = unserialize($blob); + if ($value === false) { + Logger::error(sprintf("Failed to unserialize: '%s'", mb_substr($blob, 0, 100))); + // delete? + return $default; } - return $data; + return $value; } - // It's a good idea to delete expired cache items. - // However I'm seeing lots of SQLITE_BUSY errors so commented out for now - // $stmt = $this->db->prepare('DELETE FROM storage WHERE key = :key'); - // $stmt->bindValue(':key', $this->getCacheKey()); - // $stmt->execute(); - return null; + // delete? + return $default; } - - public function saveData($data): void + public function set(string $key, $value, int $ttl = null): void { - $blob = serialize($data); - + $cacheKey = $this->createCacheKey($key); + $blob = serialize($value); + $expiration = $ttl === null ? 0 : time() + $ttl; $stmt = $this->db->prepare('INSERT OR REPLACE INTO storage (key, value, updated) VALUES (:key, :value, :updated)'); - $stmt->bindValue(':key', $this->getCacheKey()); + $stmt->bindValue(':key', $cacheKey); $stmt->bindValue(':value', $blob, \SQLITE3_BLOB); - $stmt->bindValue(':updated', time()); - $stmt->execute(); + $stmt->bindValue(':updated', $expiration); + $result = $stmt->execute(); + // Unclear whether we should $result->finalize(); here? } - public function getTime(): ?int + public function delete(string $key): void { - $stmt = $this->db->prepare('SELECT updated FROM storage WHERE key = :key'); - $stmt->bindValue(':key', $this->getCacheKey()); + $key = $this->createCacheKey($key); + $stmt = $this->db->prepare('DELETE FROM storage WHERE key = :key'); + $stmt->bindValue(':key', $key); $result = $stmt->execute(); - if ($result) { - $row = $result->fetchArray(\SQLITE3_ASSOC); - if ($row !== false) { - return $row['updated']; - } - } - return null; } - public function purgeCache(int $timeout = 86400): void + public function prune(): void { if (!$this->config['enable_purge']) { return; } - $stmt = $this->db->prepare('DELETE FROM storage WHERE updated < :expired'); - $stmt->bindValue(':expired', time() - $timeout); - $stmt->execute(); - } - - public function setScope(string $scope): void - { - $this->scope = $scope; + $stmt = $this->db->prepare('DELETE FROM storage WHERE updated <= :now'); + $stmt->bindValue(':now', time()); + $result = $stmt->execute(); } - public function setKey(array $key): void + public function clear(): void { - $this->key = json_encode($key); + $this->db->query('DELETE FROM storage'); } - private function getCacheKey() + private function createCacheKey($key) { - return hash('sha1', $this->scope . $this->key, true); + return hash('sha1', $key, true); } } |