cache: implement cache locking for filesystem cache and give it multiprocess support

This commit is contained in:
Zankaria 2024-04-11 19:20:19 +02:00
parent 82ea1815fd
commit b57d9bfbb3

View File

@ -122,7 +122,7 @@ class CacheDrivers {
}; };
} }
public static function filesystem(string $prefix, string $base_path) { public static function filesystem(string $prefix, string $base_path, string $lock_file) {
if ($base_path[strlen($base_path) - 1] !== '/') { if ($base_path[strlen($base_path) - 1] !== '/') {
$base_path = "$base_path/"; $base_path = "$base_path/";
} }
@ -135,9 +135,17 @@ class CacheDrivers {
throw new RuntimeException("$base_path is not writable!"); throw new RuntimeException("$base_path is not writable!");
} }
return new class($prefix, $base_path) implements CacheDriver { $lock_file = $base_path . $lock_file;
$lock_fd = fopen($lock_file, 'w');
if ($lock_fd === false) {
throw new RuntimeException('Unable to open the lock file!');
}
$ret = new class($prefix, $base_path, $lock_file) implements CacheDriver {
private string $prefix; private string $prefix;
private string $base_path; private string $base_path;
private mixed $lock_fd;
private function prepareKey(string $key): string { private function prepareKey(string $key): string {
@ -146,21 +154,38 @@ class CacheDrivers {
return $this->prefix . $key; return $this->prefix . $key;
} }
public function __construct(string $prefix, string $base_path) { private function sharedLockCache(): void {
flock($this->lock_fd, LOCK_SH);
}
private function exclusiveLockCache(): void {
flock($this->lock_fd, LOCK_EX);
}
private function unlockCache(): void {
flock($this->lock_fd, LOCK_UN);
}
public function __construct(string $prefix, string $base_path, mixed $lock_fd) {
$this->prefix = $prefix; $this->prefix = $prefix;
$this->base_path = $base_path; $this->base_path = $base_path;
$this->lock_fd = $lock_fd;
} }
public function get(string $key): mixed { public function get(string $key): mixed {
$key = $this->prepareKey($key); $key = $this->prepareKey($key);
$fd = fopen("$this->base_path/$key", 'r'); $this->sharedLockCache();
$fd = fopen($this->base_path . $key, 'r');
if ($fd === false) { if ($fd === false) {
$this->unlockCache();
return null; return null;
} }
$data = stream_get_contents("$this->base_path/$key"); $data = stream_get_contents($fd);
fclose($fd); fclose($fd);
$this->unlockCache();
return json_decode($data, true); return json_decode($data, true);
} }
@ -168,22 +193,36 @@ class CacheDrivers {
$key = $this->prepareKey($key); $key = $this->prepareKey($key);
$data = json_encode($value); $data = json_encode($value);
file_put_contents("$this->base_path/$key", $data); $this->exclusiveLockCache();
file_put_contents($this->base_path . $key, $data);
$this->unlockCache();
} }
public function delete(string $key): void { public function delete(string $key): void {
$key = $this->prepareKey($key); $key = $this->prepareKey($key);
@unlink("$this->base_path/$key"); $this->exclusiveLockCache();
@unlink($this->base_path . $key);
$this->unlockCache();
} }
public function flush(): void { public function flush(): void {
$files = glob("$this->base_path/$this->prefix*"); $this->exclusiveLockCache();
$files = glob($this->base_path . $this->prefix . '*', GLOB_NOSORT);
foreach ($files as $file) { foreach ($files as $file) {
@unlink($file); @unlink($file);
} }
$this->unlockCache();
}
public function close() {
fclose($this->lock_fd);
} }
}; };
register_shutdown_function([$ret, 'close']);
return $ret;
} }
public static function phpArray() { public static function phpArray() {