File "Loop.php"
Full path: /home/webcknlt/admissiontell.com/wp-content/plugins/vibes/includes/libraries/lock/util/Loop.php
File
size: 3.49 B (3.49 KB bytes)
MIME-type: text/x-php
Charset: utf-8
Download Open Edit Advanced Editor &nnbsp; Back
<?php
declare(strict_types=1);
namespace malkusch\lock\util;
use LengthException;
use malkusch\lock\exception\TimeoutException;
/**
* Repeats executing a code until it was successful.
*
* @author Markus Malkusch <markus@malkusch.de>
* @link bitcoin:1P5FAZ4QhXCuwYPnLZdk3PJsqePbu1UDDA Donations
* @license WTFPL
* @internal
*/
class Loop
{
/**
* Minimum time that we want to wait, between lock checks. In micro seconds.
*
* @var double
*/
private const MINIMUM_WAIT_US = 1e4; // 0.01 seconds
/**
* Maximum time that we want to wait, between lock checks. In micro seconds.
*
* @var double
*/
private const MAXIMUM_WAIT_US = 5e5; // 0.50 seconds
/**
* @var int The timeout in seconds.
*/
private $timeout;
/**
* @var bool True while code execution is repeating.
*/
private $looping;
/**
* Sets the timeout. The default is 3 seconds.
*
* @param int $timeout The timeout in seconds. The default is 3 seconds.
* @throws \LengthException The timeout must be greater than 0.
*/
public function __construct(int $timeout = 3)
{
if ($timeout <= 0) {
throw new LengthException(\sprintf(
'The timeout must be greater than 0. %d was given.',
$timeout
));
}
$this->timeout = $timeout;
$this->looping = false;
}
/**
* Notifies that this was the last iteration.
*
* @return void
*/
public function end(): void
{
$this->looping = false;
}
/**
* Repeats executing a code until it was successful.
*
* The code has to be designed in a way that it can be repeated without any
* side effects. When execution was successful it should notify that event
* by calling {@link \malkusch\lock\util\Loop::end()}. I.e. the only side
* effects of the code may happen after a successful execution.
*
* If the code throws an exception it will stop repeating the execution.
*
* @param callable $code The to be executed code callback.
* @throws \Exception The execution callback threw an exception.
* @throws \malkusch\lock\exception\TimeoutException The timeout has been
* reached.
* @return mixed The return value of the executed code callback.
*
*/
public function execute(callable $code)
{
$this->looping = true;
// At this time, the lock will time out.
$deadline = microtime(true) + $this->timeout;
$result = null;
for ($i = 0; $this->looping && microtime(true) < $deadline; ++$i) {
$result = $code();
if (!$this->looping) { // @phpstan-ignore-line
break;
}
// Calculate max time remaining, don't sleep any longer than that.
$usecRemaining = intval(($deadline - microtime(true)) * 1e6);
// We've ran out of time.
if ($usecRemaining <= 0) {
throw TimeoutException::create($this->timeout);
}
$min = min(
(int) self::MINIMUM_WAIT_US * 1.25 ** $i,
self::MAXIMUM_WAIT_US
);
$max = min($min * 2, self::MAXIMUM_WAIT_US);
$usecToSleep = min($usecRemaining, random_int((int)$min, (int)$max));
usleep($usecToSleep);
}
if (microtime(true) >= $deadline) {
throw TimeoutException::create($this->timeout);
}
return $result;
}
}