jenkins-bot has submitted this change and it was merged.
Change subject: Use wikimedia/wait-condition-loop
......................................................................
Use wikimedia/wait-condition-loop
Since the WaitConditionLoop class was first introduced in 1.28 (current
master), no back-compat alias is added.
Bug: T146256
Depends-On: Ia84774d83da79fea1e167fe065c69549981f753b
Change-Id: Ibd4f15c87105b8caccbd1f661b74b6efa012b77f
---
M RELEASE-NOTES-1.28
M autoload.php
M composer.json
D includes/libs/WaitConditionLoop.php
M includes/libs/lockmanager/LockManager.php
M includes/libs/lockmanager/MemcLockManager.php
M includes/libs/objectcache/BagOStuff.php
M includes/libs/rdbms/ChronologyProtector.php
M includes/libs/rdbms/database/DatabasePostgres.php
D tests/phpunit/includes/libs/WaitConditionLoopTest.php
10 files changed, 7 insertions(+), 366 deletions(-)
Approvals:
Reedy: Looks good to me, approved
jenkins-bot: Verified
diff --git a/RELEASE-NOTES-1.28 b/RELEASE-NOTES-1.28
index 4f687a1..4051987 100644
--- a/RELEASE-NOTES-1.28
+++ b/RELEASE-NOTES-1.28
@@ -68,6 +68,7 @@
==== New external libraries ====
* Added wikimedia/scoped-callback v1.0.0
+* Added wikimedia/wait-condition-loop v1.0.1
==== Removed and replaced external libraries ====
diff --git a/autoload.php b/autoload.php
index 323a01d..e614444 100644
--- a/autoload.php
+++ b/autoload.php
@@ -1516,7 +1516,6 @@
'VirtualRESTService' => __DIR__ .
'/includes/libs/virtualrest/VirtualRESTService.php',
'VirtualRESTServiceClient' => __DIR__ .
'/includes/libs/virtualrest/VirtualRESTServiceClient.php',
'WANObjectCache' => __DIR__ .
'/includes/libs/objectcache/WANObjectCache.php',
- 'WaitConditionLoop' => __DIR__ . '/includes/libs/WaitConditionLoop.php',
'WantedCategoriesPage' => __DIR__ .
'/includes/specials/SpecialWantedcategories.php',
'WantedFilesPage' => __DIR__ .
'/includes/specials/SpecialWantedfiles.php',
'WantedPagesPage' => __DIR__ .
'/includes/specials/SpecialWantedpages.php',
diff --git a/composer.json b/composer.json
index c827c0f..4d71c66 100644
--- a/composer.json
+++ b/composer.json
@@ -41,6 +41,7 @@
"wikimedia/running-stat": "1.1.0",
"wikimedia/scoped-callback": "1.0.0",
"wikimedia/utfnormal": "1.0.3",
+ "wikimedia/wait-condition-loop": "1.0.1",
"wikimedia/wrappedstring": "2.2.0",
"zordius/lightncandy": "0.23"
},
diff --git a/includes/libs/WaitConditionLoop.php
b/includes/libs/WaitConditionLoop.php
deleted file mode 100644
index 969e86e..0000000
--- a/includes/libs/WaitConditionLoop.php
+++ /dev/null
@@ -1,186 +0,0 @@
-<?php
-/**
- * Wait loop that reaches a condition or times out.
- *
- * This program 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 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @author Aaron Schulz
- */
-
-/**
- * Wait loop that reaches a condition or times out
- * @since 1.28
- */
-class WaitConditionLoop {
- /** @var callable */
- private $condition;
- /** @var callable[] */
- private $busyCallbacks = [];
- /** @var float Seconds */
- private $timeout;
- /** @var float Seconds */
- private $lastWaitTime;
- /** @var integer|null */
- private $rusageMode;
-
- const CONDITION_REACHED = 1;
- const CONDITION_CONTINUE = 0; // evaluates as falsey
- const CONDITION_FAILED = -1;
- const CONDITION_TIMED_OUT = -2;
- const CONDITION_ABORTED = -3;
-
- /**
- * @param callable $condition Callback that returns a
WaitConditionLoop::CONDITION_ constant
- * @param float $timeout Timeout in seconds
- * @param array &$busyCallbacks List of callbacks to do useful work (by
reference)
- */
- public function __construct( callable $condition, $timeout = 5.0,
&$busyCallbacks = [] ) {
- $this->condition = $condition;
- $this->timeout = $timeout;
- $this->busyCallbacks =& $busyCallbacks;
-
- if ( defined( 'HHVM_VERSION' ) && PHP_OS === 'Linux' ) {
- $this->rusageMode = 2; // RUSAGE_THREAD
- } elseif ( function_exists( 'getrusage' ) ) {
- $this->rusageMode = 0; // RUSAGE_SELF
- }
- }
-
- /**
- * Invoke the loop and continue until either:
- * - a) The condition callback returns neither CONDITION_CONTINUE nor
false
- * - b) The timeout is reached
- * This a condition callback can return true (stop) or false (continue)
for convenience.
- * In such cases, the halting result of "true" will be converted to
CONDITION_REACHED.
- *
- * If $timeout is 0, then only the condition callback will be called
(no busy callbacks),
- * and this will immediately return CONDITION_FAILED if the condition
was not met.
- *
- * Exceptions in callbacks will be caught and the callback will be
swapped with
- * one that simply rethrows that exception back to the caller when
invoked.
- *
- * @return integer WaitConditionLoop::CONDITION_* constant
- * @throws Exception Any error from the condition callback
- */
- public function invoke() {
- $elapsed = 0.0; // seconds
- $sleepUs = 0; // microseconds to sleep each time
- $lastCheck = false;
- $finalResult = self::CONDITION_TIMED_OUT;
- do {
- $checkStartTime = $this->getWallTime();
- // Check if the condition is met yet
- $realStart = $this->getWallTime();
- $cpuStart = $this->getCpuTime();
- $checkResult = call_user_func( $this->condition );
- $cpu = $this->getCpuTime() - $cpuStart;
- $real = $this->getWallTime() - $realStart;
- // Exit if the condition is reached, and error occurs,
or this is non-blocking
- if ( $this->timeout <= 0 ) {
- $finalResult = $checkResult ?
self::CONDITION_REACHED : self::CONDITION_FAILED;
- break;
- } elseif ( (int)$checkResult !==
self::CONDITION_CONTINUE ) {
- if ( is_int( $checkResult ) ) {
- $finalResult = $checkResult;
- } else {
- $finalResult = self::CONDITION_REACHED;
- }
- break;
- } elseif ( $lastCheck ) {
- break; // timeout reached
- }
- // Detect if condition callback seems to block or if
justs burns CPU
- $conditionUsesInterrupts = ( $real > 0.100 && $cpu <=
$real * .03 );
- if ( !$this->popAndRunBusyCallback() &&
!$conditionUsesInterrupts ) {
- // 10 queries = 10(10+100)/2 ms = 550ms, 14
queries = 1050ms
- $sleepUs = min( $sleepUs + 10 * 1e3, 1e6 ); //
stop incrementing at ~1s
- $this->usleep( $sleepUs );
- }
- $checkEndTime = $this->getWallTime();
- // The max() protects against the clock getting set back
- $elapsed += max( $checkEndTime - $checkStartTime, 0.010
);
- // Do not let slow callbacks timeout without checking
the condition one more time
- $lastCheck = ( $elapsed >= $this->timeout );
- } while ( true );
-
- $this->lastWaitTime = $elapsed;
-
- return $finalResult;
- }
-
- /**
- * @return float Seconds
- */
- public function getLastWaitTime() {
- return $this->lastWaitTime;
- }
-
- /**
- * @param integer $microseconds
- */
- protected function usleep( $microseconds ) {
- usleep( $microseconds );
- }
-
- /**
- * @return float
- */
- protected function getWallTime() {
- return microtime( true );
- }
-
- /**
- * @return float Returns 0.0 if not supported (Windows on PHP < 7)
- */
- protected function getCpuTime() {
- if ( $this->rusageMode === null ) {
- return microtime( true ); // assume worst case (all
time is CPU)
- }
-
- $ru = getrusage( $this->rusageMode );
- $time = $ru['ru_utime.tv_sec'] + $ru['ru_utime.tv_usec'] / 1e6;
- $time += $ru['ru_stime.tv_sec'] + $ru['ru_stime.tv_usec'] / 1e6;
-
- return $time;
- }
-
- /**
- * Run one of the callbacks that does work ahead of time for another
caller
- *
- * @return bool Whether a callback was executed
- */
- private function popAndRunBusyCallback() {
- if ( $this->busyCallbacks ) {
- reset( $this->busyCallbacks );
- $key = key( $this->busyCallbacks );
- /** @var callable $workCallback */
- $workCallback =& $this->busyCallbacks[$key];
- try {
- $workCallback();
- } catch ( Exception $e ) {
- $workCallback = function () use ( $e ) {
- throw $e;
- };
- }
- unset( $this->busyCallbacks[$key] ); // consume
-
- return true;
- }
-
- return false;
- }
-}
diff --git a/includes/libs/lockmanager/LockManager.php
b/includes/libs/lockmanager/LockManager.php
index e89a9c7..bee34dc 100644
--- a/includes/libs/lockmanager/LockManager.php
+++ b/includes/libs/lockmanager/LockManager.php
@@ -4,6 +4,7 @@
* @ingroup FileBackend
*/
use Psr\Log\LoggerInterface;
+use Wikimedia\WaitConditionLoop;
/**
* Resource locking handling.
diff --git a/includes/libs/lockmanager/MemcLockManager.php
b/includes/libs/lockmanager/MemcLockManager.php
index 83334fe..aecdf60 100644
--- a/includes/libs/lockmanager/MemcLockManager.php
+++ b/includes/libs/lockmanager/MemcLockManager.php
@@ -20,6 +20,7 @@
* @file
* @ingroup LockManager
*/
+use Wikimedia\WaitConditionLoop;
/**
* Manage locks using memcached servers.
diff --git a/includes/libs/objectcache/BagOStuff.php
b/includes/libs/objectcache/BagOStuff.php
index cd79b67..d3deefb 100644
--- a/includes/libs/objectcache/BagOStuff.php
+++ b/includes/libs/objectcache/BagOStuff.php
@@ -29,6 +29,7 @@
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
+use Wikimedia\WaitConditionLoop;
/**
* interface is intended to be more or less compatible with
diff --git a/includes/libs/rdbms/ChronologyProtector.php
b/includes/libs/rdbms/ChronologyProtector.php
index 1f9aff1..88af1db 100644
--- a/includes/libs/rdbms/ChronologyProtector.php
+++ b/includes/libs/rdbms/ChronologyProtector.php
@@ -22,6 +22,7 @@
*/
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface;
+use Wikimedia\WaitConditionLoop;
/**
* Class for ensuring a consistent ordering of events as seen by the user,
despite replication.
diff --git a/includes/libs/rdbms/database/DatabasePostgres.php
b/includes/libs/rdbms/database/DatabasePostgres.php
index f58628e..f82d76d 100644
--- a/includes/libs/rdbms/database/DatabasePostgres.php
+++ b/includes/libs/rdbms/database/DatabasePostgres.php
@@ -20,6 +20,7 @@
* @file
* @ingroup Database
*/
+use Wikimedia\WaitConditionLoop;
/**
* @ingroup Database
diff --git a/tests/phpunit/includes/libs/WaitConditionLoopTest.php
b/tests/phpunit/includes/libs/WaitConditionLoopTest.php
deleted file mode 100644
index 9ce93d6..0000000
--- a/tests/phpunit/includes/libs/WaitConditionLoopTest.php
+++ /dev/null
@@ -1,179 +0,0 @@
-<?php
-
-class WaitConditionLoopFakeTime extends WaitConditionLoop {
- protected $wallClock = 1;
-
- function __construct( callable $condition, $timeout, array
$busyCallbacks ) {
- parent::__construct( $condition, $timeout, $busyCallbacks );
- }
-
- function usleep( $microseconds ) {
- $this->wallClock += $microseconds / 1e6;
- }
-
- function getCpuTime() {
- return 0.0;
- }
-
- function getWallTime() {
- return $this->wallClock;
- }
-
- public function setWallClock( &$timestamp ) {
- $this->wallClock =& $timestamp;
- }
-}
-
-class WaitConditionLoopTest extends PHPUnit_Framework_TestCase {
- public function testCallbackReached() {
- $wallClock = microtime( true );
-
- $count = 0;
- $status = new StatusValue();
- $loop = new WaitConditionLoopFakeTime(
- function () use ( &$count, $status ) {
- ++$count;
- $status->value = 'cookie';
-
- return WaitConditionLoop::CONDITION_REACHED;
- },
- 10.0,
- $this->newBusyWork( $x, $y, $z )
- );
- $this->assertEquals( $loop::CONDITION_REACHED, $loop->invoke()
);
- $this->assertEquals( 1, $count );
- $this->assertEquals( 'cookie', $status->value );
- $this->assertEquals( [ 0, 0, 0 ], [ $x, $y, $z ], "No busy work
done" );
-
- $count = 0;
- $loop = new WaitConditionLoopFakeTime(
- function () use ( &$count, &$wallClock ) {
- $wallClock += 1;
- ++$count;
-
- return $count >= 2 ?
WaitConditionLoop::CONDITION_REACHED : false;
- },
- 7.0,
- $this->newBusyWork( $x, $y, $z, $wallClock )
- );
- $this->assertEquals( $loop::CONDITION_REACHED, $loop->invoke(),
- "Busy work did not cause timeout" );
- $this->assertEquals( [ 1, 0, 0 ], [ $x, $y, $z ] );
-
- $count = 0;
- $loop = new WaitConditionLoopFakeTime(
- function () use ( &$count, &$wallClock ) {
- $wallClock += .1;
- ++$count;
-
- return $count > 80 ? true : false;
- },
- 50.0,
- $this->newBusyWork( $x, $y, $z, $wallClock,
$dontCallMe, $badCalls )
- );
- $this->assertEquals( 0, $badCalls, "Callback exception not yet
called" );
- $this->assertEquals( $loop::CONDITION_REACHED, $loop->invoke()
);
- $this->assertEquals( [ 1, 1, 1 ], [ $x, $y, $z ], "Busy work
done" );
- $this->assertEquals( 1, $badCalls, "Bad callback ran and was
exception caught" );
-
- try {
- $e = null;
- $dontCallMe();
- } catch ( Exception $e ) {
- }
-
- $this->assertInstanceOf( 'RunTimeException', $e );
- $this->assertEquals( 1, $badCalls, "Callback exception cached"
);
- }
-
- public function testCallbackTimeout() {
- $count = 0;
- $wallClock = microtime( true );
- $loop = new WaitConditionLoopFakeTime(
- function () use ( &$count, &$wallClock ) {
- $wallClock += 3;
- ++$count;
-
- return $count > 300 ? true : false;
- },
- 50.0,
- $this->newBusyWork( $x, $y, $z, $wallClock )
- );
- $loop->setWallClock( $wallClock );
- $this->assertEquals( $loop::CONDITION_TIMED_OUT,
$loop->invoke() );
- $this->assertEquals( [ 1, 1, 1 ], [ $x, $y, $z ], "Busy work
done" );
-
- $loop = new WaitConditionLoopFakeTime(
- function () use ( &$count, &$wallClock ) {
- $wallClock += 3;
- ++$count;
-
- return true;
- },
- 0.0,
- $this->newBusyWork( $x, $y, $z, $wallClock )
- );
- $this->assertEquals( $loop::CONDITION_REACHED, $loop->invoke()
);
-
- $count = 0;
- $loop = new WaitConditionLoopFakeTime(
- function () use ( &$count, &$wallClock ) {
- $wallClock += 3;
- ++$count;
-
- return $count > 10 ? true : false;
- },
- 0,
- $this->newBusyWork( $x, $y, $z, $wallClock )
- );
- $this->assertEquals( $loop::CONDITION_FAILED, $loop->invoke() );
- }
-
- public function testCallbackAborted() {
- $x = 0;
- $wallClock = microtime( true );
- $loop = new WaitConditionLoopFakeTime(
- function () use ( &$x, &$wallClock ) {
- $wallClock += 2;
- ++$x;
-
- return $x > 2 ?
WaitConditionLoop::CONDITION_ABORTED : false;
- },
- 10.0,
- $this->newBusyWork( $x, $y, $z, $wallClock )
- );
- $loop->setWallClock( $wallClock );
- $this->assertEquals( $loop::CONDITION_ABORTED, $loop->invoke()
);
- }
-
- private function newBusyWork(
- &$x, &$y, &$z, &$wallClock = 1, &$dontCallMe = null, &$badCalls
= 0
- ) {
- $x = $y = $z = 0;
- $badCalls = 0;
-
- $list = [];
- $list[] = function () use ( &$x, &$wallClock ) {
- $wallClock += 1;
-
- return ++$x;
- };
- $dontCallMe = function () use ( &$badCalls ) {
- ++$badCalls;
- throw new RuntimeException( "TrollyMcTrollFace" );
- };
- $list[] =& $dontCallMe;
- $list[] = function () use ( &$y, &$wallClock ) {
- $wallClock += 15;
-
- return ++$y;
- };
- $list[] = function () use ( &$z, &$wallClock ) {
- $wallClock += 0.1;
-
- return ++$z;
- };
-
- return $list;
- }
-}
--
To view, visit https://gerrit.wikimedia.org/r/313647
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: Ibd4f15c87105b8caccbd1f661b74b6efa012b77f
Gerrit-PatchSet: 2
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Legoktm <[email protected]>
Gerrit-Reviewer: Aaron Schulz <[email protected]>
Gerrit-Reviewer: Reedy <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits