jenkins-bot has submitted this change and it was merged. ( 
https://gerrit.wikimedia.org/r/393630 )

Change subject: Use time forcing methods to avoid WANObjectCacheTest flakeiness
......................................................................


Use time forcing methods to avoid WANObjectCacheTest flakeiness

Use of microtime() is now just for baselines, and it is no longer
assumed to be increasing with each call. Such an assumption is
particuliarly bad on Windows.

I've done 100X run rounds with now failures on Windows.

Change-Id: Ica2a47982495bc95b10ca507414972744ea9507e
---
M includes/libs/objectcache/WANObjectCache.php
M tests/phpunit/includes/libs/objectcache/WANObjectCacheTest.php
2 files changed, 102 insertions(+), 65 deletions(-)

Approvals:
  Krinkle: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/includes/libs/objectcache/WANObjectCache.php 
b/includes/libs/objectcache/WANObjectCache.php
index b8d90d9..fc3a727 100644
--- a/includes/libs/objectcache/WANObjectCache.php
+++ b/includes/libs/objectcache/WANObjectCache.php
@@ -1662,6 +1662,9 @@
 
                $ageStale = abs( $curTTL ); // seconds of staleness
                $curGTTL = ( $graceTTL - $ageStale ); // current 
grace-time-to-live
+               if ( $curGTTL <= 0 ) {
+                       return false; //  already out of grace period
+               }
 
                // Chance of using a stale value is the complement of the 
chance of refreshing it
                return !$this->worthRefreshExpiring( $curGTTL, $graceTTL );
diff --git a/tests/phpunit/includes/libs/objectcache/WANObjectCacheTest.php 
b/tests/phpunit/includes/libs/objectcache/WANObjectCacheTest.php
index d94c546..a518cee 100644
--- a/tests/phpunit/includes/libs/objectcache/WANObjectCacheTest.php
+++ b/tests/phpunit/includes/libs/objectcache/WANObjectCacheTest.php
@@ -17,7 +17,7 @@
  * @covers WANObjectCache::setInterimValue
  */
 class WANObjectCacheTest extends PHPUnit_Framework_TestCase {
-       /** @var WANObjectCache */
+       /** @var TimeAdjustableWANObjectCache */
        private $cache;
        /** @var BagOStuff */
        private $internalCache;
@@ -25,8 +25,8 @@
        protected function setUp() {
                parent::setUp();
 
-               $this->cache = new WANObjectCache( [
-                       'cache' => new HashBagOStuff(),
+               $this->cache = new TimeAdjustableWANObjectCache( [
+                       'cache' => new TimeAdjustableHashBagOStuff(),
                        'pool' => 'testcache-hash',
                        'relayer' => new EventRelayerNull( [] )
                ] );
@@ -215,15 +215,16 @@
                $this->assertGreaterThanOrEqual( 19, $curTTL, 'Current TTL 
between 19-20 (overriden)' );
 
                $wasSet = 0;
-               $v = $cache->getWithSetCallback( $key, 30, $func, [
-                               'lowTTL' => 0,
-                               'lockTSE' => 5,
-                       ] + $extOpts );
+               $v = $cache->getWithSetCallback(
+                       $key, 30, $func, [ 'lowTTL' => 0, 'lockTSE' => 5 ] + 
$extOpts );
                $this->assertEquals( $value, $v, "Value returned" );
                $this->assertEquals( 0, $wasSet, "Value not regenerated" );
 
-               $priorTime = microtime( true );
-               usleep( 1 );
+               $priorTime = microtime( true ); // reference time
+               $cache->setTime( $priorTime );
+
+               $cache->addTime( 1 );
+
                $wasSet = 0;
                $v = $cache->getWithSetCallback(
                        $key, 30, $func, [ 'checkKeys' => [ $cKey1, $cKey2 ] ] 
+ $extOpts
@@ -237,7 +238,8 @@
                $t2 = $cache->getCheckKeyTime( $cKey2 );
                $this->assertGreaterThanOrEqual( $priorTime, $t2, 'Check keys 
generated on miss' );
 
-               $priorTime = microtime( true );
+               $priorTime = $cache->addTime( 0.01 );
+
                $wasSet = 0;
                $v = $cache->getWithSetCallback(
                        $key, 30, $func, [ 'checkKeys' => [ $cKey1, $cKey2 ] ] 
+ $extOpts
@@ -267,11 +269,6 @@
                $this->assertEquals( $value, $v, "Value still returned after 
deleted" );
                $this->assertEquals( 1, $wasSet, "Value process cached while 
deleted" );
 
-               $timeyCache = new TimeAdjustableWANObjectCache( [
-                       'cache'   => new TimeAdjustableHashBagOStuff(),
-                       'pool'    => 'empty'
-               ] );
-
                $oldValReceived = -1;
                $oldAsOfReceived = -1;
                $checkFunc = function ( $oldVal, &$ttl, array $setOpts, 
$oldAsOf )
@@ -287,23 +284,22 @@
 
                $wasSet = 0;
                $key = wfRandomString();
-               $timeyCache->setTime( $now );
-               $v = $timeyCache->getWithSetCallback(
+               $v = $cache->getWithSetCallback(
                        $key, 30, $checkFunc, [ 'staleTTL' => 50 ] + $extOpts );
                $this->assertEquals( 'xxx1', $v, "Value returned" );
                $this->assertEquals( false, $oldValReceived, "Callback got no 
stale value" );
                $this->assertEquals( null, $oldAsOfReceived, "Callback got no 
stale value" );
 
-               $timeyCache->setTime( $now + 40 );
-               $v = $timeyCache->getWithSetCallback(
+               $cache->addTime( 40 );
+               $v = $cache->getWithSetCallback(
                        $key, 30, $checkFunc, [ 'staleTTL' => 50 ] + $extOpts );
                $this->assertEquals( 'xxx2', $v, "Value still returned after 
expired" );
                $this->assertEquals( 2, $wasSet, "Value recalculated while 
expired" );
                $this->assertEquals( 'xxx1', $oldValReceived, "Callback got 
stale value" );
                $this->assertNotEquals( null, $oldAsOfReceived, "Callback got 
stale value" );
 
-               $timeyCache->setTime( $now + 300 );
-               $v = $timeyCache->getWithSetCallback(
+               $cache->addTime( 260 );
+               $v = $cache->getWithSetCallback(
                        $key, 30, $checkFunc, [ 'staleTTL' => 50 ] + $extOpts );
                $this->assertEquals( 'xxx3', $v, "Value still returned after 
expired" );
                $this->assertEquals( 3, $wasSet, "Value recalculated while 
expired" );
@@ -312,39 +308,51 @@
 
                $wasSet = 0;
                $key = wfRandomString();
-               $checkKey = $timeyCache->makeKey( 'template', 'X' );
-               $timeyCache->setTime( $now - $timeyCache::HOLDOFF_TTL - 1 );
-               $timeyCache->touchCheckKey( $checkKey ); // init check key
-               $timeyCache->setTime( $now );
-               $v = $timeyCache->getWithSetCallback(
+               $checkKey = $cache->makeKey( 'template', 'X' );
+               $cache->setTime( $now - $cache::HOLDOFF_TTL - 1 );
+               $cache->touchCheckKey( $checkKey ); // init check key
+               $cache->setTime( $now );
+               $v = $cache->getWithSetCallback(
                        $key,
-                       $timeyCache::TTL_WEEK,
+                       $cache::TTL_INDEFINITE,
                        $checkFunc,
-                       [ 'graceTTL' => $timeyCache::TTL_DAY, 'checkKeys' => [ 
$checkKey ] ] + $extOpts
+                       [ 'graceTTL' => $cache::TTL_WEEK, 'checkKeys' => [ 
$checkKey ] ] + $extOpts
                );
                $this->assertEquals( 'xxx1', $v, "Value returned" );
                $this->assertEquals( 1, $wasSet, "Value computed" );
                $this->assertEquals( false, $oldValReceived, "Callback got no 
stale value" );
                $this->assertEquals( null, $oldAsOfReceived, "Callback got no 
stale value" );
 
-               $timeyCache->setTime( $now + 300 ); // some time passes
-               $timeyCache->touchCheckKey( $checkKey ); // make key stale
-               $timeyCache->setTime( $now + 3600 ); // ~23 hours left of grace
-               $v = $timeyCache->getWithSetCallback(
+               $cache->addTime( $cache::TTL_HOUR ); // some time passes
+               $v = $cache->getWithSetCallback(
                        $key,
-                       $timeyCache::TTL_WEEK,
+                       $cache::TTL_INDEFINITE,
                        $checkFunc,
-                       [ 'graceTTL' => $timeyCache::TTL_DAY, 'checkKeys' => [ 
$checkKey ] ] + $extOpts
+                       [ 'graceTTL' => $cache::TTL_WEEK, 'checkKeys' => [ 
$checkKey ] ] + $extOpts
+               );
+               $this->assertEquals( 'xxx1', $v, "Cached value returned" );
+               $this->assertEquals( 1, $wasSet, "Cached value returned" );
+
+               $cache->touchCheckKey( $checkKey ); // make key stale
+               $cache->addTime( 0.01 ); // ~1 week left of grace (barely stale 
to avoid refreshes)
+
+               $v = $cache->getWithSetCallback(
+                       $key,
+                       $cache::TTL_INDEFINITE,
+                       $checkFunc,
+                       [ 'graceTTL' => $cache::TTL_WEEK, 'checkKeys' => [ 
$checkKey ] ] + $extOpts
                );
                $this->assertEquals( 'xxx1', $v, "Value still returned after 
expired (in grace)" );
                $this->assertEquals( 1, $wasSet, "Value still returned after 
expired (in grace)" );
 
-               $timeyCache->setTime( $now + $timeyCache::TTL_DAY );
-               $v = $timeyCache->getWithSetCallback(
+               // Change of refresh increase to unity as staleness approaches 
graceTTL
+
+               $cache->addTime( $cache::TTL_WEEK ); // 8 days of being stale
+               $v = $cache->getWithSetCallback(
                        $key,
-                       $timeyCache::TTL_WEEK,
+                       $cache::TTL_INDEFINITE,
                        $checkFunc,
-                       [ 'graceTTL' => $timeyCache::TTL_DAY, 'checkKeys' => [ 
$checkKey ] ] + $extOpts
+                       [ 'graceTTL' => $cache::TTL_WEEK, 'checkKeys' => [ 
$checkKey ] ] + $extOpts
                );
                $this->assertEquals( 'xxx2', $v, "Value was recomputed (past 
grace)" );
                $this->assertEquals( 2, $wasSet, "Value was recomputed (past 
grace)" );
@@ -487,8 +495,11 @@
                $this->assertEquals( 1, $wasSet, "Value not regenerated" );
                $this->assertEquals( 0, $cache->getWarmupKeyMisses(), "Keys 
warmed in process cache" );
 
-               $priorTime = microtime( true );
-               usleep( 1 );
+               $priorTime = microtime( true ); // reference time
+               $cache->setTime( $priorTime );
+
+               $cache->addTime( 1 );
+
                $wasSet = 0;
                $keyedIds = new ArrayIterator( [ $keyB => 'efef' ] );
                $v = $cache->getMultiWithSetCallback(
@@ -503,7 +514,7 @@
                $t2 = $cache->getCheckKeyTime( $cKey2 );
                $this->assertGreaterThanOrEqual( $priorTime, $t2, 'Check keys 
generated on miss' );
 
-               $priorTime = microtime( true );
+               $priorTime = $cache->addTime( 0.01 );
                $value = "@43636$";
                $wasSet = 0;
                $keyedIds = new ArrayIterator( [ $keyC => 43636 ] );
@@ -653,8 +664,11 @@
                $this->assertEquals( 1, $wasSet, "Value not regenerated" );
                $this->assertEquals( 0, $cache->getWarmupKeyMisses(), "Keys 
warmed in process cache" );
 
-               $priorTime = microtime( true );
-               usleep( 1 );
+               $priorTime = microtime( true ); // reference time
+               $cache->setTime( $priorTime );
+
+               $cache->addTime( 1 );
+
                $wasSet = 0;
                $keyedIds = new ArrayIterator( [ $keyB => 'efef' ] );
                $v = $cache->getMultiWithUnionSetCallback(
@@ -667,7 +681,7 @@
                $t2 = $cache->getCheckKeyTime( $cKey2 );
                $this->assertGreaterThanOrEqual( $priorTime, $t2, 'Check keys 
generated on miss' );
 
-               $priorTime = microtime( true );
+               $priorTime = $cache->addTime( 0.01 );
                $value = "@43636$";
                $wasSet = 0;
                $keyedIds = new ArrayIterator( [ $keyC => 43636 ] );
@@ -904,8 +918,11 @@
                $cKey1 = wfRandomString();
                $cKey2 = wfRandomString();
 
-               $priorTime = microtime( true );
-               usleep( 1 );
+               $priorTime = microtime( true ); // reference time
+               $cache->setTime( $priorTime );
+
+               $cache->addTime( 1 );
+
                $curTTLs = [];
                $this->assertEquals(
                        [ $key1 => $value1, $key2 => $value2 ],
@@ -920,7 +937,8 @@
                $this->assertLessThanOrEqual( 0, $curTTLs[$key1], 'Key 1 has 
current TTL <= 0' );
                $this->assertLessThanOrEqual( 0, $curTTLs[$key2], 'Key 2 has 
current TTL <= 0' );
 
-               usleep( 1 );
+               $cache->addTime( 1 );
+
                $curTTLs = [];
                $this->assertEquals(
                        [ $key1 => $value1, $key2 => $value2 ],
@@ -946,12 +964,15 @@
                $value1 = wfRandomString();
                $value2 = wfRandomString();
 
+               $cache->setTime( microtime( true ) );
+
                // Fake initial check key to be set in the past. Otherwise we'd 
have to sleep for
                // several seconds during the test to assert the behaviour.
                foreach ( [ $checkAll, $check1, $check2 ] as $checkKey ) {
                        $cache->touchCheckKey( $checkKey, 
WANObjectCache::HOLDOFF_NONE );
                }
-               usleep( 100 );
+
+               $cache->addTime( 0.100 );
 
                $cache->set( 'key1', $value1, 10 );
                $cache->set( 'key2', $value2, 10 );
@@ -973,6 +994,7 @@
                $this->assertGreaterThanOrEqual( 9.5, $curTTLs['key2'], 
'Initial ttls' );
                $this->assertLessThanOrEqual( 10.5, $curTTLs['key2'], 'Initial 
ttls' );
 
+               $cache->addTime( 0.100 );
                $cache->touchCheckKey( $check1 );
 
                $curTTLs = [];
@@ -1157,36 +1179,39 @@
         * @covers WANObjectCache::parsePurgeValue
         */
        public function testTouchKeys() {
+               $cache = $this->cache;
                $key = wfRandomString();
 
-               $priorTime = microtime( true );
-               usleep( 100 );
-               $t0 = $this->cache->getCheckKeyTime( $key );
+               $priorTime = microtime( true ); // reference time
+               $cache->setTime( $priorTime );
+
+               $newTime = $cache->addTime( 0.100 );
+               $t0 = $cache->getCheckKeyTime( $key );
                $this->assertGreaterThanOrEqual( $priorTime, $t0, 'Check key 
auto-created' );
 
-               $priorTime = microtime( true );
-               usleep( 100 );
-               $this->cache->touchCheckKey( $key );
-               $t1 = $this->cache->getCheckKeyTime( $key );
+               $priorTime = $newTime;
+               $newTime = $cache->addTime( 0.100 );
+               $cache->touchCheckKey( $key );
+               $t1 = $cache->getCheckKeyTime( $key );
                $this->assertGreaterThanOrEqual( $priorTime, $t1, 'Check key 
created' );
 
-               $t2 = $this->cache->getCheckKeyTime( $key );
+               $t2 = $cache->getCheckKeyTime( $key );
                $this->assertEquals( $t1, $t2, 'Check key time did not change' 
);
 
-               usleep( 100 );
-               $this->cache->touchCheckKey( $key );
-               $t3 = $this->cache->getCheckKeyTime( $key );
+               $cache->addTime( 0.100 );
+               $cache->touchCheckKey( $key );
+               $t3 = $cache->getCheckKeyTime( $key );
                $this->assertGreaterThan( $t2, $t3, 'Check key time increased' 
);
 
-               $t4 = $this->cache->getCheckKeyTime( $key );
+               $t4 = $cache->getCheckKeyTime( $key );
                $this->assertEquals( $t3, $t4, 'Check key time did not change' 
);
 
-               usleep( 100 );
-               $this->cache->resetCheckKey( $key );
-               $t5 = $this->cache->getCheckKeyTime( $key );
+               $cache->addTime( 0.100 );
+               $cache->resetCheckKey( $key );
+               $t5 = $cache->getCheckKeyTime( $key );
                $this->assertGreaterThan( $t4, $t5, 'Check key time increased' 
);
 
-               $t6 = $this->cache->getCheckKeyTime( $key );
+               $t6 = $cache->getCheckKeyTime( $key );
                $this->assertEquals( $t5, $t6, 'Check key time did not change' 
);
        }
 
@@ -1513,6 +1538,15 @@
                }
        }
 
+       public function addTime( $time ) {
+               $this->timeOverride += $time;
+               if ( $this->cache instanceof TimeAdjustableHashBagOStuff ) {
+                       $this->cache->setTime( $this->timeOverride );
+               }
+
+               return $this->timeOverride;
+       }
+
        protected function getCurrentTime() {
                return $this->timeOverride ?: parent::getCurrentTime();
        }
@@ -1522,7 +1556,7 @@
        const CLOCK_SKEW = 1;
 
        protected function worthRefreshExpiring( $curTTL, $lowTTL ) {
-               return ( ( $curTTL + self::CLOCK_SKEW ) < $lowTTL );
+               return ( $curTTL > 0 && ( $curTTL + self::CLOCK_SKEW ) < 
$lowTTL );
        }
 }
 

-- 
To view, visit https://gerrit.wikimedia.org/r/393630
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ica2a47982495bc95b10ca507414972744ea9507e
Gerrit-PatchSet: 5
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Aaron Schulz <[email protected]>
Gerrit-Reviewer: Krinkle <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to