024e36be17
Note: This does not impact third-party libraries.
192 lines
6.4 KiB
PHP
192 lines
6.4 KiB
PHP
<?php
|
|
// This file is part of Moodle - http://moodle.org/
|
|
//
|
|
// Moodle is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Moodle is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
namespace core\lock;
|
|
|
|
use coding_exception;
|
|
|
|
/**
|
|
* Timing wrapper around a lock factory.
|
|
*
|
|
* This passes all calls through to the underlying lock factory, but adds timing information on how
|
|
* long it takes to get a lock and how long the lock is held for.
|
|
*
|
|
* @package core
|
|
* @category lock
|
|
* @copyright 2022 The Open University
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
*/
|
|
class timing_wrapper_lock_factory implements lock_factory {
|
|
|
|
/** @var lock_factory Real lock factory */
|
|
protected $factory;
|
|
|
|
/** @var string Type (Frankenstyle) used for these locks */
|
|
protected $type;
|
|
|
|
/**
|
|
* Constructor required by interface.
|
|
*
|
|
* @param string $type Type (should be same as passed to real lock factory)
|
|
* @param lock_factory $factory Real lock factory
|
|
*/
|
|
public function __construct($type, ?lock_factory $factory = null) {
|
|
$this->type = $type;
|
|
if (!$factory) {
|
|
// This parameter has to be optional because of the interface, but it is actually
|
|
// required.
|
|
throw new \coding_exception('The $factory parameter must be specified');
|
|
}
|
|
$this->factory = $factory;
|
|
}
|
|
|
|
/**
|
|
* Gets the real lock factory that this is wrapping.
|
|
*
|
|
* @return lock_factory ReaL lock factory
|
|
*/
|
|
public function get_real_factory(): lock_factory {
|
|
return $this->factory;
|
|
}
|
|
|
|
/**
|
|
* Implementation of lock_factory::get_lock that defers to function inner_get_lock and keeps
|
|
* track of how long it took.
|
|
*
|
|
* @param string $resource Identifier for the lock
|
|
* @param int $timeout Number of seconds to wait for a lock before giving up
|
|
* @param int $maxlifetime Number of seconds to wait before reclaiming a stale lock
|
|
* @return \core\lock\lock|boolean - An instance of \core\lock\lock if the lock was obtained, or false.
|
|
*/
|
|
public function get_lock($resource, $timeout, $maxlifetime = 86400) {
|
|
$before = microtime(true);
|
|
|
|
$result = $this->factory->get_lock($resource, $timeout, $maxlifetime);
|
|
|
|
$after = microtime(true);
|
|
self::record_lock_data($after, $before, $this->type, $resource, (bool)$result, $result);
|
|
if ($result) {
|
|
$result->init_factory($this);
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Records statistics about a lock to the performance data.
|
|
*
|
|
* @param float $after The time after the lock was achieved.
|
|
* @param float $before The time before the lock was requested.
|
|
* @param string $type The type of lock.
|
|
* @param string $resource The resource being locked.
|
|
* @param bool $result Whether the lock was successful.
|
|
* @param lock|string $lock A value uniquely identifying the lock.
|
|
* @return void
|
|
*/
|
|
public static function record_lock_data(float $after, float $before, string $type, string $resource, bool $result, $lock) {
|
|
global $PERF;
|
|
$duration = $after - $before;
|
|
if (empty($PERF->locks)) {
|
|
$PERF->locks = [];
|
|
}
|
|
$lockdata = (object) [
|
|
'type' => $type,
|
|
'resource' => $resource,
|
|
'wait' => $duration,
|
|
'success' => $result
|
|
];
|
|
if ($result) {
|
|
$lockdata->lock = $lock;
|
|
$lockdata->timestart = $after;
|
|
}
|
|
$PERF->locks[] = $lockdata;
|
|
}
|
|
|
|
/**
|
|
* Release a lock that was previously obtained with {@see get_lock}.
|
|
*
|
|
* @param lock $lock - The lock to release.
|
|
* @return boolean - True if the lock is no longer held (including if it was never held).
|
|
*/
|
|
public function release_lock(lock $lock) {
|
|
self::record_lock_released_data($lock);
|
|
return $this->factory->release_lock($lock);
|
|
}
|
|
|
|
/**
|
|
* Find the lock in the performance info and update it with the time held.
|
|
*
|
|
* @param lock|string $lock A value uniquely identifying the lock.
|
|
* @return void
|
|
*/
|
|
public static function record_lock_released_data($lock) {
|
|
global $PERF;
|
|
|
|
// Find this lock in the list of locks we got, looking backwards since it is probably
|
|
// the last one.
|
|
for ($index = count($PERF->locks) - 1; $index >= 0; $index--) {
|
|
$lockdata = $PERF->locks[$index];
|
|
if (!empty($lockdata->lock) && $lockdata->lock === $lock) {
|
|
// Update the time held.
|
|
unset($lockdata->lock);
|
|
$lockdata->held = microtime(true) - $lockdata->timestart;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Calls parent factory to check if it supports timeout.
|
|
*
|
|
* @return boolean False if attempting to get a lock will block indefinitely.
|
|
*/
|
|
public function supports_timeout() {
|
|
return $this->factory->supports_timeout();
|
|
}
|
|
|
|
/**
|
|
* Calls parent factory to check if it auto-releases locks.
|
|
*
|
|
* @return boolean True if this lock type will be automatically released when the current process ends.
|
|
*/
|
|
public function supports_auto_release() {
|
|
return $this->factory->supports_auto_release();
|
|
}
|
|
|
|
/**
|
|
* @deprecated since Moodle 3.10.
|
|
*/
|
|
public function supports_recursion() {
|
|
throw new coding_exception('The function supports_recursion() has been removed, please do not use it anymore.');
|
|
}
|
|
|
|
/**
|
|
* Calls parent factory to check if it is available.
|
|
*
|
|
* @return boolean True if this lock type is available in this environment.
|
|
*/
|
|
public function is_available() {
|
|
return $this->factory->is_available();
|
|
}
|
|
|
|
/**
|
|
* @deprecated since Moodle 3.10.
|
|
*/
|
|
public function extend_lock() {
|
|
throw new coding_exception('The function extend_lock() has been removed, please do not use it anymore.');
|
|
}
|
|
}
|