suite implémentation cache

This commit is contained in:
Jephté Clain 2025-05-23 07:16:27 +04:00
parent ec0c0eef3e
commit c80d99e829
2 changed files with 81 additions and 24 deletions

View File

@ -12,10 +12,9 @@ class CacheData {
/** @var callable une fonction permettant de calculer la donnée */ /** @var callable une fonction permettant de calculer la donnée */
const COMPUTE = null; const COMPUTE = null;
function __construct(?array $params=null) { function __construct(?string $name=null, $compute=null) {
$this->name = $params["name"] ?? static::NAME; $this->name = $name ?? static::NAME ?? bin2hex(random_bytes(8));
$this->name ??= bin2hex(random_bytes(8)); $this->compute = func::withn($compute ?? static::COMPUTE);
$this->compute = func::withn($params["compute"] ?? static::COMPUTE);
} }
protected string $name; protected string $name;
@ -27,9 +26,12 @@ class CacheData {
return $compute !== null? $compute->invoke(): null; return $compute !== null? $compute->invoke(): null;
} }
function getName() : string {
return $this->name;
}
/** obtenir la donnée, en l'itérant au préalable si elle est traversable */ /** obtenir la donnée, en l'itérant au préalable si elle est traversable */
function get(?string &$name, $compute=null) { function get($compute=null) {
$name = $this->name;
$this->compute ??= func::withn($compute); $this->compute ??= func::withn($compute);
$data = $this->compute(); $data = $this->compute();
if ($data instanceof Traversable) { if ($data instanceof Traversable) {
@ -39,8 +41,7 @@ class CacheData {
} }
/** obtenir un itérateur sur la donnée ou null s'il n'y a pas de données */ /** obtenir un itérateur sur la donnée ou null s'il n'y a pas de données */
function all(?string &$name, $compute=null): ?iterable { function all($compute=null): ?iterable {
$name = $this->name;
$this->compute ??= func::withn($compute); $this->compute ??= func::withn($compute);
$data = $this->compute(); $data = $this->compute();
if ($data !== null && !is_iterable($data)) $data = [$data]; if ($data !== null && !is_iterable($data)) $data = [$data];

View File

@ -1,6 +1,8 @@
<?php <?php
namespace nulib\file\cache; namespace nulib\file\cache;
use Exception;
use nulib\file;
use nulib\file\SharedFile; use nulib\file\SharedFile;
use nulib\os\path; use nulib\os\path;
use nulib\php\time\DateTime; use nulib\php\time\DateTime;
@ -23,7 +25,6 @@ class CacheFile extends SharedFile {
$this->duration = Delay::with($params["duration"] ?? static::DURATION); $this->duration = Delay::with($params["duration"] ?? static::DURATION);
$this->overrideDuration = $params["override_duration"] ?? false; $this->overrideDuration = $params["override_duration"] ?? false;
$this->cacheNull = $params["cache_null"] ?? false; $this->cacheNull = $params["cache_null"] ?? false;
$this->datafiles = [];
parent::__construct($file); parent::__construct($file);
} }
@ -39,8 +40,6 @@ class CacheFile extends SharedFile {
protected bool $cacheNull; protected bool $cacheNull;
protected array $datafiles;
/** /**
* vérifier si le fichier est valide. s'il est invalide, il faut le recréer. * vérifier si le fichier est valide. s'il est invalide, il faut le recréer.
* *
@ -52,7 +51,7 @@ class CacheFile extends SharedFile {
} }
/** charger les données. le fichier a déjà été verrouillé en lecture */ /** charger les données. le fichier a déjà été verrouillé en lecture */
protected function loadData(): ?array { protected function loadMetadata(): ?array {
$this->rewind(); $this->rewind();
[ [
"start" => $start, "start" => $start,
@ -74,7 +73,7 @@ class CacheFile extends SharedFile {
if ($this->isValid()) { if ($this->isValid()) {
/** @var Delay $duration */ /** @var Delay $duration */
["duration" => $duration, ["duration" => $duration,
] = $this->loadData(); ] = $this->loadMetadata();
$expired = $duration->isElapsed(); $expired = $duration->isElapsed();
} else { } else {
$expired = false; $expired = false;
@ -84,7 +83,7 @@ class CacheFile extends SharedFile {
} }
/** sauvegarder les données. le fichier a déjà été verrouillé en écriture */ /** sauvegarder les données. le fichier a déjà été verrouillé en écriture */
protected function saveData(?DateTime $start=null, ?Delay $duration=null): void { protected function saveMetadata(?DateTime $start, ?Delay $duration, array $datafiles): void {
$duration ??= $this->duration; $duration ??= $this->duration;
if ($start === null) { if ($start === null) {
$start = new DateTime(); $start = new DateTime();
@ -94,15 +93,76 @@ class CacheFile extends SharedFile {
$this->serialize([ $this->serialize([
"start" => $start, "start" => $start,
"duration" => $duration, "duration" => $duration,
"datafiles" => $this->datafiles, "datafiles" => $datafiles,
], false, true); ], false, true);
} }
function loadData(string $datafile) {
$datafile = path::join($this->basedir, $datafile);
return file::reader($datafile)->unserialize();
}
function saveData(string $datafile, $data): void {
$datafile = path::join($this->basedir, $datafile);
file::writer($datafile)->serialize($data);
}
protected function unlinkDatafile(string $datafile): void {
@unlink(path::join($this->basedir, $datafile));
}
protected function unlinkFiles(?array $datafiles): void {
if ($datafiles === null && $this->isValid()) {
$this->lockRead();
try {
["datafiles" => $datafiles
] = $this->loadMetadata();
} finally {
$this->unlock();
}
}
@unlink($this->file);
if ($datafiles !== null) {
foreach ($datafiles as $datafile) {
$this->unlinkDatafile($datafile);
}
}
}
/** tester si $value peut être mis en cache */ /** tester si $value peut être mis en cache */
function shouldCache($value): bool { protected function shouldCache($value): bool {
return $this->cacheNull || $value !== null; return $this->cacheNull || $value !== null;
} }
function get(?CacheData $data=null, bool $noCache=false) {
$this->lockRead();
try {
$datafile = $data->getName();
$datafile = "{$this->basename}.data.{$datafile}.cache";
#XXX mettre à jour datafiles dans metadata
if ($this->shouldUpdate($noCache)) {
$this->lockWrite();
try {
$data = $data->get();
if ($this->shouldCache($data)) {
$this->saveData($datafile, $data);
} else {
# ne pas garder le fichier s'il ne faut pas mettre en cache
$this->unlinkDatafile($datafile);
}
} catch (Exception $e) {
$this->unlinkDatafile($datafile);
throw $e;
}
} else {
$data = $this->loadData($datafile);
}
return $data;
} finally {
$this->unlock();
}
}
/** obtenir les informations sur le fichier */ /** obtenir les informations sur le fichier */
function getInfos(): array { function getInfos(): array {
$this->lockRead(); $this->lockRead();
@ -118,7 +178,7 @@ class CacheFile extends SharedFile {
"start" => $start, "start" => $start,
"duration" => $duration, "duration" => $duration,
"datafiles" => $datafiles, "datafiles" => $datafiles,
] = $this->loadData(); ] = $this->loadMetadata();
return [ return [
"valid" => true, "valid" => true,
"size" => $this->getSize(), "size" => $this->getSize(),
@ -148,10 +208,10 @@ class CacheFile extends SharedFile {
[ [
"start" => $start, "start" => $start,
"duration" => $duration, "duration" => $duration,
] = $this->loadData(); ] = $this->loadMetadata();
if ($action < 0) $duration->subDuration($nduration); if ($action < 0) $duration->subDuration($nduration);
elseif ($action > 0) $duration->addDuration($nduration); elseif ($action > 0) $duration->addDuration($nduration);
$this->saveData($start, $duration); $this->saveMetadata($start, $duration);
} finally { } finally {
$this->unlock(); $this->unlock();
} }
@ -163,11 +223,7 @@ class CacheFile extends SharedFile {
try { try {
if ($force || $this->shouldUpdate()) { if ($force || $this->shouldUpdate()) {
$this->lockWrite(); $this->lockWrite();
@unlink($this->file); $this->unlinkFiles();
$basedir = $this->basedir;
foreach ($this->datafiles as $datafile) {
@unlink(path::join($basedir, $datafile));
}
return true; return true;
} }
} finally { } finally {