aboutsummaryrefslogtreecommitdiff
path: root/caches/SQLiteCache.php
diff options
context:
space:
mode:
authorGravatar Dag <me@dvikan.no> 2023-09-10 21:50:15 +0200
committerGravatar GitHub <noreply@github.com> 2023-09-10 21:50:15 +0200
commit4b9f6f7e53e0b2e9aae59df2bbffc0bdd6805aea (patch)
tree40bc3e62a343df8bd0076b609d57248f7bd9448b /caches/SQLiteCache.php
parenta786bbd4e0d45a98446ed0384ed57705a17b89d3 (diff)
downloadrss-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.php92
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);
}
}