diff --git a/src/file/cache/CacheData.php b/src/file/cache/CacheData.php index ec96a14..a680f9e 100644 --- a/src/file/cache/CacheData.php +++ b/src/file/cache/CacheData.php @@ -12,10 +12,9 @@ class CacheData { /** @var callable une fonction permettant de calculer la donnée */ const COMPUTE = null; - function __construct(?array $params=null) { - $this->name = $params["name"] ?? static::NAME; - $this->name ??= bin2hex(random_bytes(8)); - $this->compute = func::withn($params["compute"] ?? static::COMPUTE); + function __construct(?string $name=null, $compute=null) { + $this->name = $name ?? static::NAME ?? bin2hex(random_bytes(8)); + $this->compute = func::withn($compute ?? static::COMPUTE); } protected string $name; @@ -27,9 +26,12 @@ class CacheData { 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 */ - function get(?string &$name, $compute=null) { - $name = $this->name; + function get($compute=null) { $this->compute ??= func::withn($compute); $data = $this->compute(); 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 */ - function all(?string &$name, $compute=null): ?iterable { - $name = $this->name; + function all($compute=null): ?iterable { $this->compute ??= func::withn($compute); $data = $this->compute(); if ($data !== null && !is_iterable($data)) $data = [$data]; diff --git a/src/file/cache/CacheFile.php b/src/file/cache/CacheFile.php index 07b30cc..0c9e810 100644 --- a/src/file/cache/CacheFile.php +++ b/src/file/cache/CacheFile.php @@ -1,6 +1,8 @@ duration = Delay::with($params["duration"] ?? static::DURATION); $this->overrideDuration = $params["override_duration"] ?? false; $this->cacheNull = $params["cache_null"] ?? false; - $this->datafiles = []; parent::__construct($file); } @@ -39,8 +40,6 @@ class CacheFile extends SharedFile { protected bool $cacheNull; - protected array $datafiles; - /** * 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 */ - protected function loadData(): ?array { + protected function loadMetadata(): ?array { $this->rewind(); [ "start" => $start, @@ -74,7 +73,7 @@ class CacheFile extends SharedFile { if ($this->isValid()) { /** @var Delay $duration */ ["duration" => $duration, - ] = $this->loadData(); + ] = $this->loadMetadata(); $expired = $duration->isElapsed(); } else { $expired = false; @@ -84,7 +83,7 @@ class CacheFile extends SharedFile { } /** 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; if ($start === null) { $start = new DateTime(); @@ -94,15 +93,76 @@ class CacheFile extends SharedFile { $this->serialize([ "start" => $start, "duration" => $duration, - "datafiles" => $this->datafiles, + "datafiles" => $datafiles, ], 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 */ - function shouldCache($value): bool { + protected function shouldCache($value): bool { 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 */ function getInfos(): array { $this->lockRead(); @@ -118,7 +178,7 @@ class CacheFile extends SharedFile { "start" => $start, "duration" => $duration, "datafiles" => $datafiles, - ] = $this->loadData(); + ] = $this->loadMetadata(); return [ "valid" => true, "size" => $this->getSize(), @@ -148,10 +208,10 @@ class CacheFile extends SharedFile { [ "start" => $start, "duration" => $duration, - ] = $this->loadData(); + ] = $this->loadMetadata(); if ($action < 0) $duration->subDuration($nduration); elseif ($action > 0) $duration->addDuration($nduration); - $this->saveData($start, $duration); + $this->saveMetadata($start, $duration); } finally { $this->unlock(); } @@ -163,11 +223,7 @@ class CacheFile extends SharedFile { try { if ($force || $this->shouldUpdate()) { $this->lockWrite(); - @unlink($this->file); - $basedir = $this->basedir; - foreach ($this->datafiles as $datafile) { - @unlink(path::join($basedir, $datafile)); - } + $this->unlinkFiles(); return true; } } finally {