diff --git a/src/Invalidator/MemcacheTimestampInvalidator.php b/src/Invalidator/MemcacheTimestampInvalidator.php index 316e19f..1d541e7 100644 --- a/src/Invalidator/MemcacheTimestampInvalidator.php +++ b/src/Invalidator/MemcacheTimestampInvalidator.php @@ -12,8 +12,8 @@ class MemcacheTimestampInvalidator extends TimestampInvalidatorBase { */ protected $memcache; - public function __construct($memcache, $tolerance = 1.0) { - parent::__construct($tolerance); + public function __construct($memcache, $tolerance = 1.0, $cooldown = FALSE) { + parent::__construct($tolerance, $cooldown); $this->memcache = $memcache; } diff --git a/src/Invalidator/TimestampInvalidatorBase.php b/src/Invalidator/TimestampInvalidatorBase.php index 9c20924..4f4fa2c 100644 --- a/src/Invalidator/TimestampInvalidatorBase.php +++ b/src/Invalidator/TimestampInvalidatorBase.php @@ -17,13 +17,31 @@ abstract class TimestampInvalidatorBase implements TimestampInvalidatorInterface protected $tolerance; /** + * @var float Amount of time to ignore repeated invalidations for the same tag. + * MUST be 0 or smaller than $tolerance. + */ + protected $cooldown; + + /** + * @var array Tracking for invalidated items, for use with the cooldown logic. + */ + protected $invalidated_timestamps; + + /** * TimestampInvalidatorBase constructor. * * @param $tolerance float Tolerance value to use. Cluster clocks must be * synchronized to within this tolerance to ensure correct operation. + * @param float | FALSE $cooldown Amount of time to ignore repeated invalidations of + * the same tag. */ - function __construct($tolerance = 1.0) { + function __construct($tolerance = 1.0, $cooldown = FALSE) { + if ($cooldown > 0 && $cooldown > $tolerance) { + throw new \DomainException("Cooldown must not exceed tolerance."); + } $this->tolerance = $tolerance; + $this->cooldown = $cooldown; + $this->invalidated_timestamps = []; } /** @@ -37,11 +55,20 @@ abstract class TimestampInvalidatorBase implements TimestampInvalidatorInterface // @todo Eventually we might want to use a time service instead of microtime(). // Unfortunately, TimeInterface needs a request object and we don't have that // in the bootstrap container. - $now = round(microtime(TRUE) + $this->tolerance, 3); + $timestamp = microtime(TRUE); + if ($this->cooldown && isset($this->invalidated_timestamps[$tag]) + && $timestamp < $this->invalidated_timestamps[$tag] + $this->cooldown) { + // We have already invalidated this item inside the cooldown window. + return $this->invalidated_timestamps[$tag]; + } + $now = round($timestamp + $this->tolerance, 3); $current = $this ->getLastInvalidationTimestamp($tag); if ($now > $current) { $this->writeTimestamp($tag, $now); + if ($this->cooldown) { + $this->invalidated_timestamps[$tag] = $now; + } return $now; } else {