FileCachedValue utilise Delay

This commit is contained in:
Jephté Clain 2024-05-13 17:59:15 +04:00
parent cf89396467
commit 4494c8ecc3
5 changed files with 83 additions and 33 deletions

View File

@ -44,7 +44,7 @@ Application::run(new class extends Application {
protected $args;
function setActionUpdate(int $action, int $updateDuration): void {
function setActionUpdate(int $action, $updateDuration): void {
$this->action = self::ACTION_UPDATE;
switch ($action) {
case self::ACTION_UPDATE_SUB: $this->updateAction = -1; break;
@ -81,7 +81,7 @@ Application::run(new class extends Application {
case self::ACTION_READ:
if ($showSection) msg::section($file);
$cache = new CacheFile($file, [
"duration" => PHP_INT_MAX,
"duration" => "INF",
"override_duration" => true,
]);
yaml::dump($cache->get());

View File

@ -7,15 +7,14 @@ use Exception;
use Generator;
use nur\A;
use nur\b\coll\TBaseArray;
use nur\b\date\Date;
use nur\b\date\Datetime;
use nur\b\IllegalAccessException;
use nur\b\params\Parametrable;
use nur\b\params\Tparametrable;
use nur\data\types\Tmd;
use nur\file;
use nur\os;
use nur\ref\ref_cache;
use nur\sery\php\time\DateTime;
use nur\sery\php\time\Delay;
/**
* Class FileCachedValue: un fichier utilisé pour mettre en cache certaines
@ -28,8 +27,8 @@ abstract class FileCachedValue extends Parametrable implements ArrayAccess, Coun
/** @var string chemin vers le fichier cache par défaut */
const FILE = null;
/** @var int durée de vie par défaut du cache en secondes */
const DURATION = 8 * ref_cache::HOUR;
/** @var int durée de vie par défaut du cache */
const DURATION = "1D"; // jusqu'au lendemain
/** @var bool faut-il mettre en cache la valeur nulle? */
const CACHE_NULL = false;
@ -50,7 +49,7 @@ abstract class FileCachedValue extends Parametrable implements ArrayAccess, Coun
const PARAMETRABLE_PARAMS_SCHEMA = [
"file" => ["?string", null, "chemin vers le fichier"],
"duration" => ["int", null, "durée de vie du cache en secondes"],
"duration" => [Delay::class, null, "durée de vie du cache"],
"override_duration" => ["bool", false, "faut-il ignorer la duration inscrite dans le fichier et prendre la valeur locale?"],
"cache_null" => ["bool", false, "faut-il mettre en cache la valeur null?"],
"data" => ["array", null, "données supplémentaires"]
@ -67,7 +66,7 @@ abstract class FileCachedValue extends Parametrable implements ArrayAccess, Coun
return $cacheFile;
}
/** @var int */
/** @var Delay */
protected $ppDuration;
/** @var bool */
@ -94,8 +93,8 @@ abstract class FileCachedValue extends Parametrable implements ArrayAccess, Coun
$outf = file::open($file, "wb");
try {
$contents = $this->serialize($data);
$tstart = time();
$duration = $this->ppDuration;
$tstart = new DateTime();
$duration = Delay::with($this->ppDuration, $tstart);
fwrite($outf, serialize([$tstart, $duration])."\n");
fwrite($outf, $contents);
} finally {
@ -150,19 +149,25 @@ abstract class FileCachedValue extends Parametrable implements ArrayAccess, Coun
protected function loadInfos(): array {
[$tstart, $duration] = unserialize(fgets($this->fp));
if ($this->ppOverrideDuration) $duration = $this->ppDuration;
if (is_int($tstart)) {
$tstart = new DateTime($tstart);
$duration = new Delay($duration, $tstart);
}
if ($this->ppOverrideDuration) {
$duration = Delay::with($this->ppDuration, $tstart);
}
return [$tstart, $duration];
}
protected function shouldUpdate(bool $noCache=false) {
/** @var Delay $duration */
$this->_open();
$cleanup = true;
try {
$this->_lock(LOCK_SH);
if ($this->isValidFile()) {
$now = time();
[$tstart, $duration] = $this->loadInfos();
$expired = $now - $tstart > $duration;
$expired = $duration->isElapsed();
} else {
$expired = false;
$noCache = true;
@ -234,16 +239,18 @@ abstract class FileCachedValue extends Parametrable implements ArrayAccess, Coun
$this->_lock(LOCK_SH);
if (!$this->isValidFile()) return ["valid" => false];
$size = filesize($this->ppFile);
/**
* @var DateTime $tstart
* @var Delay $duration
*/
[$tstart, $duration] = $this->loadInfos();
$dateStart = new Datetime($tstart);
$dateEnd = new Datetime($tstart + $duration);
return [
"valid" => true,
"size" => $size,
"tstart" => $tstart,
"duration" => $duration,
"date_start" => $dateStart->format(),
"date_end" => $dateEnd->format(),
"duration" => strval($duration),
"date_start" => $tstart->format(),
"date_end" => $duration->getDest()->format(),
];
} finally {
$this->cleanup();
@ -253,17 +260,21 @@ abstract class FileCachedValue extends Parametrable implements ArrayAccess, Coun
const UPDATE_SUB = -1, UPDATE_SET = 0, UPDATE_ADD = 1;
/** mettre à jour la durée de validité du fichier */
function updateDuration(int $duration, int $action=1): void {
function updateDuration($nduration, int $action=1): void {
$this->_open();
try {
$this->_lock(LOCK_SH);
if (!$this->isValidFile()) return;
$this->_lock(LOCK_EX);
$fp = $this->fp;
[$tstart, $oduration] = $this->loadInfos();
/**
* @var DateTime $tstart
* @var Delay $duration
*/
[$tstart, $duration] = $this->loadInfos();
$contents = stream_get_contents($fp);
if ($action < 0) $duration = $oduration - $duration;
elseif ($action > 0) $duration = $oduration + $duration;
if ($action < 0) $duration->subDuration($nduration);
elseif ($action > 0) $duration->addDuration($nduration);
fseek($fp, 0);
ftruncate($fp, 0);
fwrite($fp, serialize([$tstart, $duration])."\n");

View File

@ -4,6 +4,11 @@ namespace nur\sery\php\time;
use InvalidArgumentException;
class DateInterval extends \DateInterval {
static function with($interval): self {
if ($interval instanceof static) return $interval;
else return new static($interval);
}
protected static function to_string(DateInterval $interval) {
$string = "P";
$y = $interval->y;
@ -24,6 +29,7 @@ class DateInterval extends \DateInterval {
}
function __construct($duration) {
if (is_int($duration)) $duration = "PT${duration}S";
if ($duration instanceof \DateInterval) {
$this->y = $duration->y;
$this->m = $duration->m;

View File

@ -24,6 +24,11 @@ use InvalidArgumentException;
* @property-read string $YmdHMSZ
*/
class DateTime extends \DateTime {
static function with($datetime): self {
if ($datetime instanceof static) return $datetime;
else return new static($datetime);
}
const DMY_PATTERN = '/^(\d+)\/(\d+)(?:\/(\d+))?$/';
const YMD_PATTERN = '/^((?:\d{2})?\d{2})(\d{2})(\d{2})$/';
const DMYHIS_PATTERN = '/^(\d+)\/(\d+)(?:\/(\d+))? +(\d+)[h:.](\d+)(?:[:.](\d+))?$/';

View File

@ -13,6 +13,7 @@ use InvalidArgumentException;
* - une chaine de la forme "x[WDHMS]y" x et y sont des nombres et la lettre
* est l'unité de temps: W représente une semaine, D une journée, H une heure,
* M une minute et S une seconde.
* - la chaine "INF" qui représente une durée infinie
*
* Dans cette dernière forme, le timestamp destination est calculé en ajoutant x
* unités. puis l'unité inférieure est ramenée à (0 + y)
@ -24,6 +25,11 @@ use InvalidArgumentException;
* NB: la valeur y pour l'unité S est ignorée
*/
class Delay {
static function with($delay, ?DateTimeInterface $from=null): self {
if ($delay instanceof static) return $delay;
else return new static($delay, $from);
}
/** valeurs par défaut de x et y pour les unités supportées */
const DEFAULTS = [
"w" => [0, 5],
@ -35,6 +41,7 @@ class Delay {
static function compute_dest(int $x, string $u, ?int $y, DateTime $from): array {
$dest = DateTime::clone($from);
$yu = null;
switch ($u) {
case "w":
if ($x > 0) {
@ -43,29 +50,28 @@ class Delay {
}
$w = 7 - intval($dest->format("w"));
$dest->add(new \DateInterval("P${w}D"));
$u = "h";
$yu = "h";
break;
case "d":
$dest->add(new \DateInterval("P${x}D"));
$u = "h";
$yu = "h";
break;
case "h":
$dest->add(new \DateInterval("PT${x}H"));
$u = "m";
$yu = "m";
break;
case "m":
$dest->add(new \DateInterval("PT${x}M"));
$u = "s";
$yu = "s";
break;
case "s":
$dest->add(new \DateInterval("PT${x}S"));
$u = null;
break;
}
if ($y !== null && $u !== null) {
if ($y !== null && $yu !== null) {
$h = intval($dest->format("H"));
$m = intval($dest->format("i"));
switch ($u) {
switch ($yu) {
case "h":
$dest->setTime($y, 0, 0, 0);
break;
@ -77,13 +83,18 @@ class Delay {
break;
}
}
$repr = $y !== null? "$x$y$y": "$x";
$u = strtoupper($u);
$repr = $y !== null? "$x$u$y": "$x";
return [$dest, $repr];
}
function __construct($delay, ?DateTimeInterface $from=null) {
if ($from === null) $from = new DateTime();
if (is_int($delay)) {
if ($delay === "INF") {
$dest = DateTime::clone($from);
$dest->add(new DateInterval("P9999Y"));
$repr = "INF";
} elseif (is_int($delay)) {
[$dest, $repr] = self::compute_dest($delay, "s", null, $from);
} elseif (is_string($delay) && preg_match('/^\d+$/', $delay)) {
$x = intval($delay);
@ -111,6 +122,22 @@ class Delay {
return $this->dest;
}
function addDuration($duration) {
if (is_int($duration) && $duration < 0) {
$this->dest->sub(DateInterval::with(-$duration));
} else {
$this->dest->add(DateInterval::with($duration));
}
}
function subDuration($duration) {
if (is_int($duration) && $duration < 0) {
$this->dest->add(DateInterval::with(-$duration));
} else {
$this->dest->sub(DateInterval::with($duration));
}
}
/** @var string */
protected $repr;
@ -125,7 +152,8 @@ class Delay {
/** retourner true si le délai imparti est écoulé */
function isElapsed(?DateTimeInterface $now=null): bool {
return $this->_getDiff($now)->invert == 0;
if ($this->repr === "INF") return false;
else return $this->_getDiff($now)->invert == 0;
}
/**