CapacityTracker.php in Purge 8.3
File
src/Plugin/Purge/Purger/CapacityTracker.php
View source
<?php
namespace Drupal\purge\Plugin\Purge\Purger;
use Drupal\purge\Counter\Counter;
use Drupal\purge\Plugin\Purge\Purger\Exception\BadBehaviorException;
use Drupal\purge\Plugin\Purge\Purger\Exception\BadPluginBehaviorException;
class CapacityTracker implements CapacityTrackerInterface {
protected $cooldownTimes;
protected $cooldownTimeTotal;
protected $idealConditionsLimit;
protected $leaseTimeHints = [];
protected $maxExecutionTime;
protected $purgers = NULL;
protected $remainingInvalidationsLimits = [];
protected $spentExecutionTime;
protected $spentInvalidations;
protected $timeHints;
protected $timeHintTotal;
protected function gatherCooldownTimes() {
if (is_null($this->cooldownTimes)) {
if (is_null($this->purgers)) {
throw new \LogicException("::setPurgers() hasn't been called!");
}
$this->cooldownTimes = [];
foreach ($this->purgers as $id => $purger) {
$cooldown_time = $purger
->getCooldownTime();
if (!is_float($cooldown_time)) {
$method = sprintf("%s::getCooldownTime()", get_class($purger));
throw new BadPluginBehaviorException("{$method} did not return a floating point value.");
}
if ($cooldown_time < 0.0) {
$method = sprintf("%s::getCooldownTime()", get_class($purger));
throw new BadPluginBehaviorException("{$method} returned {$cooldown_time}, a value lower than 0.0.");
}
if ($cooldown_time > 3.0) {
$method = sprintf("%s::getCooldownTime()", get_class($purger));
throw new BadPluginBehaviorException("{$method} returned {$cooldown_time}, a value higher than 3.0.");
}
$this->cooldownTimes[$id] = $cooldown_time;
}
}
}
protected function gatherTimeHints() {
if (is_null($this->timeHints)) {
if (is_null($this->purgers)) {
throw new \LogicException("::setPurgers() hasn't been called!");
}
$this->timeHints = [];
if (count($this->purgers)) {
foreach ($this->purgers as $id => $purger) {
$hint = $purger
->getTimeHint();
if (!is_float($hint)) {
$method = sprintf("%s::getTimeHint()", get_class($purger));
throw new BadPluginBehaviorException("{$method} did not return a floating point value.");
}
if ($hint < 0.1) {
$method = sprintf("%s::getTimeHint()", get_class($purger));
throw new BadPluginBehaviorException("{$method} returned {$hint}, a value lower than 0.1.");
}
if ($hint > 10.0) {
$method = sprintf("%s::getTimeHint()", get_class($purger));
throw new BadPluginBehaviorException("{$method} returned {$hint}, a value higher than 10.0.");
}
$this->timeHints[$id] = $hint;
}
}
}
}
public function getCooldownTime($purger_instance_id) {
$this
->gatherCooldownTimes();
if (!isset($this->cooldownTimes[$purger_instance_id])) {
throw new BadBehaviorException("Instance id '{$purger_instance_id}' does not exist!");
}
return $this->cooldownTimes[$purger_instance_id];
}
public function getCooldownTimeTotal() {
if (is_null($this->cooldownTimeTotal)) {
$this
->gatherCooldownTimes();
$this->cooldownTimeTotal = array_sum($this->cooldownTimes);
}
return $this->cooldownTimeTotal;
}
public function getIdealConditionsLimit() {
if (is_null($this->idealConditionsLimit)) {
if (is_null($this->purgers)) {
throw new \LogicException("::setPurgers() hasn't been called!");
}
if (empty($this->purgers)) {
$this->idealConditionsLimit = 0;
return $this->idealConditionsLimit;
}
$this->idealConditionsLimit = [];
foreach ($this->purgers as $purger) {
$limit = $purger
->getIdealConditionsLimit();
if (!is_int($limit) || $limit < 1) {
$method = sprintf("%s::getIdealConditionsLimit()", get_class($purger));
throw new BadPluginBehaviorException("{$method} returned {$limit}, which has to be a integer higher than 0.");
}
$this->idealConditionsLimit[] = $limit;
}
$this->idealConditionsLimit = (int) min($this->idealConditionsLimit);
}
return $this->idealConditionsLimit;
}
public function getLeaseTimeHint($items) {
if ($items < 1 || !is_int($items)) {
throw new BadPluginBehaviorException('$items is below 1 or no integer.');
}
$calculate = function ($items) {
$s = $items * $this
->getTimeHintTotal() + $this
->getCooldownTimeTotal();
$s++;
return (int) ceil($s);
};
if (!isset($this->leaseTimeHints[$items])) {
$this->leaseTimeHints[$items] = $calculate($items);
}
return $this->leaseTimeHints[$items];
}
public function getMaxExecutionTime() {
if (is_null($this->maxExecutionTime)) {
$this->maxExecutionTime = (int) ini_get('max_execution_time');
if ($this->maxExecutionTime !== 0) {
$this->maxExecutionTime = intval(0.8 * $this->maxExecutionTime);
}
}
return $this->maxExecutionTime;
}
public function getRemainingInvalidationsLimit() {
if (is_null($this->purgers)) {
throw new \LogicException("::setPurgers() hasn't been called!");
}
$calculate = function ($spent_inv) {
if (empty($this->purgers)) {
return 0;
}
$time_max = $this
->getMaxExecutionTime();
if ($time_max === 0) {
return (int) ($this
->getIdealConditionsLimit() - $spent_inv);
}
$time_left = $time_max - $this
->spentExecutionTime()
->get() - $this
->getCooldownTimeTotal();
$limit = intval(floor($time_left / $this
->getTimeHintTotal()) - $spent_inv);
if ($limit > $this
->getIdealConditionsLimit()) {
return (int) $this
->getIdealConditionsLimit();
}
return (int) ($limit < 0 ? 0 : $limit);
};
$spent_inv = $this
->spentInvalidations()
->get();
if (!isset($this->remainingInvalidationsLimits[$spent_inv])) {
$this->remainingInvalidationsLimits[$spent_inv] = $calculate($spent_inv);
}
return $this->remainingInvalidationsLimits[$spent_inv];
}
public function getTimeHint($purger_instance_id) {
$this
->gatherTimeHints();
if (!isset($this->timeHints[$purger_instance_id])) {
throw new BadBehaviorException("Instance id '{$purger_instance_id}' does not exist!");
}
return $this->timeHints[$purger_instance_id];
}
public function getTimeHintTotal() {
if (is_null($this->timeHintTotal)) {
$this
->gatherTimeHints();
$this->timeHintTotal = 1.0;
if (count($this->timeHints)) {
$hints_per_type = [];
foreach ($this->timeHints as $id => $hint) {
foreach ($this->purgers[$id]
->getTypes() as $type) {
if (!isset($hints_per_type[$type])) {
$hints_per_type[$type] = 0.0;
}
$hints_per_type[$type] = $hints_per_type[$type] + $hint;
}
}
$this->timeHintTotal = max($hints_per_type);
}
}
return $this->timeHintTotal;
}
public function setPurgers(array $purgers) {
$this->purgers = $purgers;
}
public function spentExecutionTime() {
if (is_null($this->spentExecutionTime)) {
$this->spentExecutionTime = new Counter(0);
$this->spentExecutionTime
->disableDecrement();
$this->spentExecutionTime
->disableSet();
}
return $this->spentExecutionTime;
}
public function spentInvalidations() {
if (is_null($this->spentInvalidations)) {
$this->spentInvalidations = new Counter(0);
$this->spentInvalidations
->disableDecrement();
$this->spentInvalidations
->disableSet();
}
return $this->spentInvalidations;
}
public function waitCooldownTime($purger_instance_id) {
$seconds = $this
->getCooldownTime($purger_instance_id);
if (!($seconds == 0)) {
$fractions = explode('.', (string) $seconds);
if (isset($fractions[1])) {
call_user_func_array('time_nanosleep', $fractions);
}
else {
sleep($seconds);
}
}
}
}