feat(sqlite cache): add config options (#3499)

* refactor: sqlite cache

* refactor

* feat: add config options to sqlite cache

* refactor
This commit is contained in:
Dag 2023-07-06 15:59:38 +02:00 committed by GitHub
parent 21c8d8775e
commit 965d7d44c5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 69 additions and 54 deletions

View file

@ -9,8 +9,8 @@ class FileCache implements CacheInterface
public function __construct(array $config = [])
{
$default = [
'path' => null,
'enable_purge' => true,
'path' => null,
'enable_purge' => true,
];
$this->config = array_merge($default, $config);
if (!$this->config['path']) {

View file

@ -5,51 +5,43 @@
*/
class SQLiteCache implements CacheInterface
{
protected string $scope;
protected string $key;
private \SQLite3 $db;
private string $scope;
private string $key;
private array $config;
private $db = null;
public function __construct()
public function __construct(array $config)
{
if (!extension_loaded('sqlite3')) {
throw new \Exception('"sqlite3" extension not loaded. Please check "php.ini"');
$default = [
'file' => null,
'timeout' => 5000,
'enable_purge' => true,
];
$config = array_merge($default, $config);
$this->config = $config;
if (!$config['file']) {
throw new \Exception('sqlite cache needs a file');
}
if (!is_writable(PATH_CACHE)) {
throw new \Exception('The cache folder is not writable');
}
$section = 'SQLiteCache';
$file = Configuration::getConfig($section, 'file');
if (!$file) {
throw new \Exception(sprintf('Configuration for %s missing.', $section));
}
if (dirname($file) == '.') {
$file = PATH_CACHE . $file;
} elseif (!is_dir(dirname($file))) {
throw new \Exception(sprintf('Invalid configuration for %s', $section));
}
if (!is_file($file)) {
// The instantiation creates the file
$this->db = new \SQLite3($file);
if (is_file($config['file'])) {
$this->db = new \SQLite3($config['file']);
$this->db->enableExceptions(true);
} else {
// Create the file and create sql schema
$this->db = new \SQLite3($config['file']);
$this->db->enableExceptions(true);
$this->db->exec("CREATE TABLE storage ('key' BLOB PRIMARY KEY, 'value' BLOB, 'updated' INTEGER)");
} else {
$this->db = new \SQLite3($file);
$this->db->enableExceptions(true);
}
$this->db->busyTimeout(5000);
$this->db->busyTimeout($config['timeout']);
}
public function loadData()
{
$Qselect = $this->db->prepare('SELECT value FROM storage WHERE key = :key');
$Qselect->bindValue(':key', $this->getCacheKey());
$result = $Qselect->execute();
if ($result instanceof \SQLite3Result) {
$stmt = $this->db->prepare('SELECT value FROM storage WHERE key = :key');
$stmt->bindValue(':key', $this->getCacheKey());
$result = $stmt->execute();
if ($result) {
$data = $result->fetchArray(\SQLITE3_ASSOC);
if (isset($data['value'])) {
return unserialize($data['value']);
@ -61,20 +53,20 @@ class SQLiteCache implements CacheInterface
public function saveData($data): void
{
$Qupdate = $this->db->prepare('INSERT OR REPLACE INTO storage (key, value, updated) VALUES (:key, :value, :updated)');
$Qupdate->bindValue(':key', $this->getCacheKey());
$Qupdate->bindValue(':value', serialize($data));
$Qupdate->bindValue(':updated', time());
$Qupdate->execute();
$stmt = $this->db->prepare('INSERT OR REPLACE INTO storage (key, value, updated) VALUES (:key, :value, :updated)');
$stmt->bindValue(':key', $this->getCacheKey());
$stmt->bindValue(':value', serialize($data));
$stmt->bindValue(':updated', time());
$stmt->execute();
}
public function getTime(): ?int
{
$Qselect = $this->db->prepare('SELECT updated FROM storage WHERE key = :key');
$Qselect->bindValue(':key', $this->getCacheKey());
$result = $Qselect->execute();
if ($result instanceof \SQLite3Result) {
$data = $result->fetchArray(SQLITE3_ASSOC);
$stmt = $this->db->prepare('SELECT updated FROM storage WHERE key = :key');
$stmt->bindValue(':key', $this->getCacheKey());
$result = $stmt->execute();
if ($result) {
$data = $result->fetchArray(\SQLITE3_ASSOC);
if (isset($data['updated'])) {
return $data['updated'];
}
@ -85,9 +77,12 @@ class SQLiteCache implements CacheInterface
public function purgeCache(int $seconds): void
{
$Qdelete = $this->db->prepare('DELETE FROM storage WHERE updated < :expired');
$Qdelete->bindValue(':expired', time() - $seconds);
$Qdelete->execute();
if (!$this->config['enable_purge']) {
return;
}
$stmt = $this->db->prepare('DELETE FROM storage WHERE updated < :expired');
$stmt->bindValue(':expired', time() - $seconds);
$stmt->execute();
}
public function setScope(string $scope): void
@ -102,10 +97,6 @@ class SQLiteCache implements CacheInterface
private function getCacheKey()
{
if (is_null($this->key)) {
throw new \Exception('Call "setKey" first!');
}
return hash('sha1', $this->scope . $this->key, true);
}
}

View file

@ -125,7 +125,12 @@ path = ""
enable_purge = true
[SQLiteCache]
; Filepath of the sqlite db file
file = "cache.sqlite"
; Whether to actually delete data when purging
enable_purge = true
; Busy wait in ms before timing out
timeout = 5000
[MemcachedCache]
host = "localhost"

View file

@ -51,7 +51,26 @@ class CacheFactory
}
return new FileCache($fileCacheConfig);
case SQLiteCache::class:
return new SQLiteCache();
if (!extension_loaded('sqlite3')) {
throw new \Exception('"sqlite3" extension not loaded. Please check "php.ini"');
}
if (!is_writable(PATH_CACHE)) {
throw new \Exception('The cache folder is not writable');
}
$file = Configuration::getConfig('SQLiteCache', 'file');
if (!$file) {
throw new \Exception(sprintf('Configuration for %s missing.', 'SQLiteCache'));
}
if (dirname($file) == '.') {
$file = PATH_CACHE . $file;
} elseif (!is_dir(dirname($file))) {
throw new \Exception(sprintf('Invalid configuration for %s', 'SQLiteCache'));
}
return new SQLiteCache([
'file' => $file,
'timeout' => Configuration::getConfig('SQLiteCache', 'timeout'),
'enable_purge' => Configuration::getConfig('SQLiteCache', 'enable_purge'),
]);
case MemcachedCache::class:
return new MemcachedCache();
default: