objectcache: Remove WANObjectCacheReaper feature

Introduced in 2017 with I7f14b9ca2533032 (2e5eb693) but remains
unused at WMF, and disabled by default.

Follows-up I62107789fa (9e49260fc9) which added reap to LinkCache
test cases in 2021.

Change-Id: I0654c29a671467dd6b366f462d1c09b90a273413
This commit is contained in:
Timo Tijhof 2022-09-18 15:31:51 +02:00
parent 8fabc7abb8
commit 1cf6f04768
17 changed files with 8 additions and 688 deletions

View file

@ -136,6 +136,8 @@ because of Phabricator reports.
It had no known usages.
* BagOStuff::makeKeyInternal(), deprecated for public use in 1.36, is now a
protected method of MediumSpecificBagOStuff.
* WANObjectCache::reap() and WANObjectCache::reapCheckKey(), deprecated since
1.39, have been removed.
* The EnqueueJob class, unused since 1.31, has been removed without
deprecation.
* ContextSource::getStats, deprecated since 1.27, has been removed.

View file

@ -1725,9 +1725,7 @@ $wgAutoloadLocalClasses = [
'VirtualRESTService' => __DIR__ . '/includes/libs/virtualrest/VirtualRESTService.php',
'VirtualRESTServiceClient' => __DIR__ . '/includes/libs/virtualrest/VirtualRESTServiceClient.php',
'VueComponentParser' => __DIR__ . '/includes/ResourceLoader/VueComponentParser.php',
'WANCacheReapUpdate' => __DIR__ . '/includes/deferred/WANCacheReapUpdate.php',
'WANObjectCache' => __DIR__ . '/includes/libs/objectcache/wancache/WANObjectCache.php',
'WANObjectCacheReaper' => __DIR__ . '/includes/libs/objectcache/wancache/WANObjectCacheReaper.php',
'WantedFilesPage' => __DIR__ . '/includes/specials/SpecialWantedfiles.php',
'WantedPagesPage' => __DIR__ . '/includes/specials/SpecialWantedpages.php',
'WantedQueryPage' => __DIR__ . '/includes/specialpage/WantedQueryPage.php',

View file

@ -2429,16 +2429,6 @@ config-schema:
];
```
@since 1.26
EnableWANCacheReaper:
default: false
type: boolean
description: |-
Verify and enforce WAN cache purges using reliable DB sources as streams.
These secondary cache purges are de-duplicated via simple cache mutexes.
This improves consistency when cache purges are lost, which becomes more likely
as more cache servers are added or if there are multiple datacenters. Only keys
related to important mutable content will be checked.
@since 1.29
MainStash:
default: db-replicated
description: |-

View file

@ -1489,12 +1489,6 @@ class MainConfigNames {
*/
public const WANObjectCaches = 'WANObjectCaches';
/**
* Name constant for the EnableWANCacheReaper setting, for use with Config::get()
* @see MainConfigSchema::EnableWANCacheReaper
*/
public const EnableWANCacheReaper = 'EnableWANCacheReaper';
/**
* Name constant for the MainStash setting, for use with Config::get()
* @see MainConfigSchema::MainStash

View file

@ -3932,21 +3932,6 @@ class MainConfigSchema {
'type' => 'map',
];
/**
* Verify and enforce WAN cache purges using reliable DB sources as streams.
*
* These secondary cache purges are de-duplicated via simple cache mutexes.
* This improves consistency when cache purges are lost, which becomes more likely
* as more cache servers are added or if there are multiple datacenters. Only keys
* related to important mutable content will be checked.
*
* @since 1.29
*/
public const EnableWANCacheReaper = [
'default' => false,
'type' => 'boolean',
];
/**
* The object store type of the main stash.
*

View file

@ -516,27 +516,6 @@ class LinkCache implements LoggerAwareInterface {
return $row ?: null;
}
/**
* @param WANObjectCache $cache
* @param LinkTarget|Pagereference $page
* In MediaWiki 1.36 and earlier, only LinkTarget was accepted.
* @return string[]
* @since 1.28
*/
public function getMutableCacheKeys( WANObjectCache $cache, $page ) {
$key = $this->getCacheKey( $page );
// if no key can be derived, the page isn't cacheable
if ( $key === null ) {
return [];
}
if ( $this->usePersistentCache( $page ) ) {
return [ $cache->makeKey( 'page', $page->getNamespace(), sha1( $page->getDBkey() ) ) ];
}
return [];
}
/**
* @param LinkTarget|PageReference|int $pageOrNamespace
*

View file

@ -506,7 +506,6 @@ return [
'cacheId' => 0,
],
],
'EnableWANCacheReaper' => false,
'MainStash' => 'db-replicated',
'ParsoidCacheConfig' => [
'StashType' => null,
@ -2601,7 +2600,6 @@ return [
2 => 'boolean',
],
'WANObjectCaches' => 'object',
'EnableWANCacheReaper' => 'boolean',
'ParsoidCacheConfig' => 'object',
'ChronologyProtectorStash' => [
0 => 'string',

View file

@ -1473,12 +1473,6 @@ $wgMainWANCache = null;
*/
$wgWANObjectCaches = null;
/**
* Config variable stub for the EnableWANCacheReaper setting, for use by phpdoc and IDEs.
* @see MediaWiki\MainConfigSchema::EnableWANCacheReaper
*/
$wgEnableWANCacheReaper = null;
/**
* Config variable stub for the MainStash setting, for use by phpdoc and IDEs.
* @see MediaWiki\MainConfigSchema::MainStash

View file

@ -1,137 +0,0 @@
<?php
use MediaWiki\Linker\LinkTarget;
use MediaWiki\MediaWikiServices;
use Psr\Log\LoggerInterface;
use Wikimedia\Rdbms\IDatabase;
/**
* Class for fixing stale WANObjectCache keys using a purge event source
*
* This is useful for expiring keys that missed fire-and-forget purges. This uses the
* recentchanges table as a reliable stream to make certain keys reach consistency
* as soon as the underlying replica database catches up. These means that critical
* keys will not escape getting purged simply due to brief hiccups in the network,
* which are more prone to happen across datacenters.
*
* ----
* "I was trying to cheat death. I was only trying to surmount for a little while the
* darkness that all my life I surely knew was going to come rolling in on me some day
* and obliterate me. I was only to stay alive a little brief while longer, after I was
* already gone. To stay in the light, to be with the living, a little while past my time."
* -- Notes for "Blues of a Lifetime", by [[Cornell Woolrich]]
*
* @since 1.28
*/
class WANCacheReapUpdate implements DeferrableUpdate {
/** @var IDatabase */
private $db;
/** @var LoggerInterface */
private $logger;
/**
* @param IDatabase $db
* @param LoggerInterface $logger
*/
public function __construct( IDatabase $db, LoggerInterface $logger ) {
$this->db = $db;
$this->logger = $logger;
}
public function doUpdate() {
$reaper = new WANObjectCacheReaper(
MediaWikiServices::getInstance()->getMainWANObjectCache(),
ObjectCache::getLocalClusterInstance(),
[ $this, 'getTitleChangeEvents' ],
[ $this, 'getEventAffectedKeys' ],
[
'channel' => 'table:recentchanges:' . $this->db->getDomainID(),
'logger' => $this->logger
]
);
$reaper->invoke( 100 );
}
/**
* @see WANObjectCacheRepear
*
* @param int $start
* @param int $id
* @param int $end
* @param int $limit
* @return TitleValue[]
*/
public function getTitleChangeEvents( $start, $id, $end, $limit ) {
$db = $this->db;
$encStart = $db->addQuotes( $db->timestamp( $start ) );
$encEnd = $db->addQuotes( $db->timestamp( $end ) );
$id = (int)$id; // cast NULL => 0 since rc_id is an integer
$res = $db->select(
'recentchanges',
[ 'rc_namespace', 'rc_title', 'rc_timestamp', 'rc_id' ],
[
$db->makeList( [
"rc_timestamp > $encStart",
"rc_timestamp = $encStart AND rc_id > " . $db->addQuotes( $id )
], LIST_OR ),
"rc_timestamp < $encEnd"
],
__METHOD__,
[ 'ORDER BY' => [ 'rc_timestamp ASC', 'rc_id ASC' ], 'LIMIT' => $limit ]
);
$events = [];
foreach ( $res as $row ) {
$events[] = [
'id' => (int)$row->rc_id,
'pos' => (int)wfTimestamp( TS_UNIX, $row->rc_timestamp ),
'item' => new TitleValue( (int)$row->rc_namespace, $row->rc_title )
];
}
return $events;
}
/**
* Gets a list of important cache keys associated with a title
*
* @see WANObjectCacheRepear
* @param WANObjectCache $cache
* @param LinkTarget $t
* @return string[]
*/
public function getEventAffectedKeys( WANObjectCache $cache, LinkTarget $t ) {
/** @var WikiPage[]|LocalFile[]|User[] $entities */
$entities = [];
// You can't create a WikiPage for special pages (-1) or other virtual
// namespaces, but special pages do appear in RC sometimes, e.g. for logs
// of AbuseFilter filter changes.
if ( $t->getNamespace() >= 0 ) {
$entities[] = MediaWikiServices::getInstance()->getWikiPageFactory()
->newFromLinkTarget( $t );
}
if ( $t->inNamespace( NS_FILE ) ) {
$entities[] = MediaWikiServices::getInstance()->getRepoGroup()->getLocalRepo()
->newFile( $t->getText() );
}
if ( $t->inNamespace( NS_USER ) ) {
$entities[] = User::newFromName( $t->getText(), false );
}
$keys = [];
foreach ( $entities as $entity ) {
if ( $entity ) {
$keys = array_merge( $keys, $entity->getMutableCacheKeys( $cache ) );
}
}
if ( $keys ) {
$this->logger->debug( __CLASS__ . ': got key(s) ' . implode( ', ', $keys ) );
}
return $keys;
}
}

View file

@ -341,15 +341,6 @@ class LocalFile extends File {
return $this->repo->getSharedCacheKey( 'file', sha1( $this->getName() ) );
}
/**
* @param WANObjectCache $cache
* @return string[]
* @since 1.28
*/
public function getMutableCacheKeys( WANObjectCache $cache ) {
return [ $this->getCacheKey() ];
}
/**
* Try to load file metadata from memcached, falling back to the database
*/

View file

@ -2244,75 +2244,6 @@ class WANObjectCache implements
return $values;
}
/**
* Set a key to soon expire in the local cluster if it pre-dates $purgeTimestamp
*
* This sets stale keys' time-to-live at HOLDOFF_TTL seconds, which both avoids
* broadcasting in mcrouter setups and also avoids races with new tombstones.
*
* @deprecated since 1.39 No longer supported.
* @param string $key Cache key made with makeKey()/makeGlobalKey()
* @param int|float $purgeTimestamp UNIX timestamp of purge
* @param bool &$isStale Whether the key is stale
* @return bool Success
* @since 1.28
*/
final public function reap( $key, $purgeTimestamp, &$isStale = false ) {
wfDeprecated( __METHOD__, '1.39' );
$valueSisterKey = $this->makeSisterKey( $key, self::TYPE_VALUE );
$minAsOf = $purgeTimestamp + self::HOLDOFF_TTL;
$wrapped = $this->cache->get( $valueSisterKey );
if ( is_array( $wrapped ) && $wrapped[self::FLD_TIME] < $minAsOf ) {
$isStale = true;
$this->logger->warning( "Reaping stale value key '$key'." );
// avoids races with tombstone creation
$ttlReap = self::HOLDOFF_TTL;
$ok = $this->cache->changeTTL( $valueSisterKey, $ttlReap );
if ( !$ok ) {
$this->logger->error( "Could not complete reap of key '$key'." );
}
return $ok;
}
$isStale = false;
return true;
}
/**
* Set a "check" key to soon expire in the local cluster if it pre-dates $purgeTimestamp
*
* @deprecated since 1.39 No longer supported.
* @param string $key Cache key made with makeKey()/makeGlobalKey()
* @param int $purgeTimestamp UNIX timestamp of purge
* @param bool &$isStale Whether the key is stale
* @return bool Success
* @since 1.28
*/
final public function reapCheckKey( $key, $purgeTimestamp, &$isStale = false ) {
wfDeprecated( __METHOD__, '1.39' );
$checkSisterKey = $this->makeSisterKey( $key, self::TYPE_TIMESTAMP );
$wrapped = $this->cache->get( $checkSisterKey );
$purge = $this->parsePurgeValue( $wrapped );
if ( $purge !== null && $purge[self::PURGE_TIME] < $purgeTimestamp ) {
$isStale = true;
$this->logger->warning( "Reaping stale check key '$key'." );
$ok = $this->cache->changeTTL( $checkSisterKey, self::TTL_SECOND );
if ( !$ok ) {
$this->logger->error( "Could not complete reap of check key '$key'." );
}
return $ok;
}
$isStale = false;
return false;
}
/**
* Make a cache key for the global keyspace and given components
*

View file

@ -1,200 +0,0 @@
<?php
/**
* 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
* @ingroup Cache
*/
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
use Wikimedia\ScopedCallback;
/**
* Class for scanning through chronological, log-structured data or change logs
* and locally purging cache keys related to entities that appear in this data.
*
* This is useful for repairing cache when purges are missed by using a reliable
* stream, such as Kafka or a replicated MySQL table. Purge loss between datacenters
* is expected to be more common than within them.
*
* @since 1.28
*/
class WANObjectCacheReaper implements LoggerAwareInterface {
/** @var WANObjectCache */
protected $cache;
/** @var BagOStuff */
protected $store;
/** @var callable */
protected $logChunkCallback;
/** @var callable */
protected $keyListCallback;
/** @var LoggerInterface */
protected $logger;
/** @var string */
protected $channel;
/** @var int */
protected $initialStartWindow;
/**
* @param WANObjectCache $cache Cache to reap bad keys from
* @param BagOStuff $store Cache to store positions use for locking
* @param callable $logCallback Callback taking arguments:
* - The starting position as a UNIX timestamp
* - The starting unique ID used for breaking timestamp collisions or null
* - The ending position as a UNIX timestamp
* - The maximum number of results to return
* It returns a list of maps of (key: cache key, pos: UNIX timestamp, id: unique ID)
* for each key affected, with the corresponding event timestamp/ID information.
* The events should be in ascending order, by (timestamp,id).
* @param callable $keyCallback Callback taking arguments:
* - The WANObjectCache instance
* - An object from the event log
* It should return a list of WAN cache keys.
* The callback must fully duck-type test the object, since can be any model class.
* @param array $params Additional options:
* - channel: the name of the update event stream.
* - initialStartWindow: seconds back in time to start if the position is lost.
* Default: 1 hour.
* - logger: an SPL monolog instance [optional]
*/
public function __construct(
WANObjectCache $cache,
BagOStuff $store,
callable $logCallback,
callable $keyCallback,
array $params
) {
$this->cache = $cache;
$this->store = $store;
$this->logChunkCallback = $logCallback;
$this->keyListCallback = $keyCallback;
if ( isset( $params['channel'] ) ) {
$this->channel = $params['channel'];
} else {
throw new UnexpectedValueException( "No channel specified." );
}
$this->initialStartWindow = $params['initialStartWindow'] ?? 3600;
$this->logger = $params['logger'] ?? new NullLogger();
}
public function setLogger( LoggerInterface $logger ) {
$this->logger = $logger;
}
/**
* Check and reap stale keys based on a chunk of events
*
* @param int $n Number of events
* @return int Number of keys checked
*/
final public function invoke( $n = 100 ) {
$posKey = $this->store->makeGlobalKey( 'WANCache', 'reaper', $this->channel );
$scopeLock = $this->store->getScopedLock( "$posKey:busy", 0 );
if ( !$scopeLock ) {
return 0;
}
$now = time();
$status = $this->store->get( $posKey );
if ( !$status ) {
$status = [ 'pos' => $now - $this->initialStartWindow, 'id' => null ];
}
// Get events for entities who's keys tombstones/hold-off should have expired by now
$events = call_user_func_array(
$this->logChunkCallback,
[ $status['pos'], $status['id'], $now - WANObjectCache::HOLDOFF_TTL - 1, $n ]
);
$event = null;
$keyEvents = [];
foreach ( $events as $event ) {
$keys = call_user_func_array(
$this->keyListCallback,
[ $this->cache, $event['item'] ]
);
foreach ( $keys as $key ) {
// use only the latest per key
unset( $keyEvents[$key] );
$keyEvents[$key] = [
'pos' => $event['pos'],
'id' => $event['id']
];
}
}
$purgeCount = 0;
$lastOkEvent = null;
foreach ( $keyEvents as $key => $keyEvent ) {
if ( !$this->cache->reap( $key, $keyEvent['pos'] ) ) {
break;
}
++$purgeCount;
$lastOkEvent = $event;
}
if ( $lastOkEvent ) {
$ok = $this->store->merge(
$posKey,
static function ( $bag, $key, $curValue ) use ( $lastOkEvent ) {
if ( !$curValue ) {
// Use new position
} else {
$curCoord = [ $curValue['pos'], $curValue['id'] ];
$newCoord = [ $lastOkEvent['pos'], $lastOkEvent['id'] ];
if ( $newCoord < $curCoord ) {
// Keep prior position instead of rolling it back
return $curValue;
}
}
return [
'pos' => $lastOkEvent['pos'],
'id' => $lastOkEvent['id'],
'ctime' => $curValue ? $curValue['ctime'] : date( 'c' )
];
},
BagOStuff::TTL_INDEFINITE
);
$pos = $lastOkEvent['pos'];
$id = $lastOkEvent['id'];
if ( $ok ) {
$this->logger->info( "Updated cache reap position ($pos, $id)." );
} else {
$this->logger->error( "Could not update cache reap position ($pos, $id)." );
}
}
ScopedCallback::consume( $scopeLock );
return $purgeCount;
}
/**
* @return array|bool Returns (pos, id) map or false if not set
*/
public function getState() {
$posKey = $this->store->makeGlobalKey( 'WANCache', 'reaper', $this->channel );
return $this->store->get( $posKey );
}
}

View file

@ -3261,17 +3261,6 @@ class WikiPage implements Page, IDBAccessObject, PageRecord {
return $this->getTitle()->getCanonicalURL();
}
/**
* @param WANObjectCache $cache
* @return string[]
* @since 1.28
*/
public function getMutableCacheKeys( WANObjectCache $cache ) {
$linkCache = MediaWikiServices::getInstance()->getLinkCache();
return $linkCache->getMutableCacheKeys( $cache, $this->getTitle() );
}
/**
* Ensure consistency when unserializing.
* @note WikiPage objects should never be serialized in the first place.

View file

@ -18,7 +18,6 @@
* @file
*/
use MediaWiki\Logger\LoggerFactory;
use MediaWiki\MainConfigNames;
use MediaWiki\MediaWikiServices;
use MediaWiki\ResourceLoader as RL;
@ -689,14 +688,6 @@ abstract class ChangesListSpecialPage extends SpecialPage {
$this->outputTimeout();
}
if ( $this->getConfig()->get( MainConfigNames::EnableWANCacheReaper ) ) {
// Clean up any bad page entries for titles showing up in RC
DeferredUpdates::addUpdate( new WANCacheReapUpdate(
$this->getDB(),
LoggerFactory::getInstance( 'objectcache' )
) );
}
$this->includeRcFiltersApp();
}

View file

@ -499,17 +499,6 @@ class User implements Authority, UserIdentity, UserEmailContact {
return $cache->makeGlobalKey( 'user', 'id', $lbFactory->getLocalDomainID(), $this->mId );
}
/**
* @param WANObjectCache $cache
* @return string[]
* @since 1.28
*/
public function getMutableCacheKeys( WANObjectCache $cache ) {
$id = $this->getId();
return $id ? [ $this->getCacheKey( $cache ) ] : [];
}
/**
* Load user data from shared cache, given mId has already been set.
*

View file

@ -307,31 +307,22 @@ class LinkCacheTest extends MediaWikiIntegrationTestCase {
/**
* @covers LinkCache::addLinkObj()
* @covers LinkCache::getMutableCacheKeys()
*/
public function testAddLinkObjUsesWANCache() {
// Pages in some namespaces use the WAN cache: Template, File, Category, MediaWiki
// For some namespaces we cache data (Template, File, etc)
$existing = $this->getExistingTestPage( Title::makeTitle( NS_TEMPLATE, __METHOD__ ) );
$fakeRow = $this->getPageRow( $existing->getId() + 100 );
$cache = new HashBagOStuff();
$wanCache = new WANObjectCache( [ 'cache' => $cache ] );
$wanCache = new WANObjectCache( [ 'cache' => new HashBagOStuff() ] );
$linkCache = $this->newLinkCache( $wanCache );
// load the page row into the cache
$linkCache->addLinkObj( $existing );
$keys = $linkCache->getMutableCacheKeys( $wanCache, $existing );
$this->assertNotEmpty( $keys );
foreach ( $keys as $key ) {
$this->assertNotFalse( $wanCache->get( $key ) );
}
// replace real row data with fake, and assert that it gets used
$key = $wanCache->makeKey( 'page', $existing->getNamespace(), sha1( $existing->getDBkey() ) );
$fakeRow = $this->getPageRow( $existing->getId() + 100 );
$wanCache->set( $key, $fakeRow );
$linkCache->clearLink( $existing ); // clear local cache
// clear in-class cache
$linkCache->clearLink( $existing );
$this->assertSame( (int)$fakeRow->page_id, $linkCache->addLinkObj( $existing ) );
// set the "read latest" flag and try again
@ -488,79 +479,4 @@ class LinkCacheTest extends MediaWikiIntegrationTestCase {
)
);
}
/**
* @covers LinkCache::getGoodLinkRow()
*/
public function testGetGoodLinkRowGetsIncompleteCachedInfo() {
// Pages in some namespaces use the WAN cache: Template, File, Category, MediaWiki
$existing = new TitleValue( NS_TEMPLATE, 'Existing' );
$brokenRow = $this->getPageRow( 3 );
unset( $brokenRow->page_len ); // make incomplete row
$cache = new HashBagOStuff();
$wanCache = new WANObjectCache( [ 'cache' => $cache ] );
$linkCache = $this->newLinkCache( $wanCache );
// force the incomplete row into the cache
$keys = $linkCache->getMutableCacheKeys( $wanCache, $existing );
$wanCache->set( $keys[0], $brokenRow );
// check that we are not getting the broken row, but load a good row
$callback = [ $this, 'getRowIfExisting' ];
$row = $linkCache->getGoodLinkRow( $existing->getNamespace(), $existing->getDBkey(), $callback );
$this->assertNotEquals( $brokenRow, $row );
}
/**
* @covers LinkCache::getGoodLinkRow()
* @covers LinkCache::getMutableCacheKeys()
*/
public function testGetGoodLinkRowUsesWANCache() {
// Pages in some namespaces use the WAN cache: Template, File, Category, MediaWiki
$existing = new TitleValue( NS_TEMPLATE, 'Existing' );
$callback = [ $this, 'getRowIfExisting' ];
$existingRow = $this->getPageRow( 0 );
$fakeRow = $this->getPageRow( 3 );
$cache = new HashBagOStuff();
$wanCache = new WANObjectCache( [ 'cache' => $cache ] );
$linkCache = $this->newLinkCache( $wanCache );
// load the page row into the cache
$linkCache->getGoodLinkRow( $existing->getNamespace(), $existing->getDBkey(), $callback );
$keys = $linkCache->getMutableCacheKeys( $wanCache, $existing );
$this->assertNotEmpty( $keys );
foreach ( $keys as $key ) {
$this->assertNotFalse( $wanCache->get( $key ) );
}
// replace real row data with fake, and assert that it gets used
$wanCache->set( $key, $fakeRow );
$linkCache->clearLink( $existing ); // clear local cache
$this->assertSame(
$fakeRow,
$linkCache->getGoodLinkRow(
$existing->getNamespace(),
$existing->getDBkey(),
$callback
)
);
// set the "read latest" flag and try again
$flags = IDBAccessObject::READ_LATEST;
$this->assertEquals(
$existingRow,
$linkCache->getGoodLinkRow(
$existing->getNamespace(),
$existing->getDBkey(),
$callback,
$flags
)
);
}
}

View file

@ -1971,96 +1971,6 @@ class WANObjectCacheTest extends MediaWikiUnitTestCase {
$this->assertGreaterThan( -5.1, $curTTL, "Correct CTL" );
}
/**
* @covers WANObjectCache::reap()
* @covers WANObjectCache::reapCheckKey()
*/
public function testReap() {
$this->hideDeprecated( 'WANObjectCache::reap' );
$this->hideDeprecated( 'WANObjectCache::reapCheckKey' );
[ $cache, $bag ] = $this->newWanCache();
$vKey1 = wfRandomString();
$vKey2 = wfRandomString();
$tKey1 = wfRandomString();
$tKey2 = wfRandomString();
$value = 'moo';
$mockWallClock = 1549343530.0;
$cache->setMockTime( $mockWallClock );
$knownPurge = $mockWallClock - 60;
$goodTime = $mockWallClock - 5;
$badTime = $mockWallClock - 300;
$bag->set(
'WANCache:' . $vKey1 . '|#|v',
[
0 => 1,
1 => $value,
2 => 3600,
3 => $goodTime
]
);
$bag->set(
'WANCache:' . $vKey2 . '|#|v',
[
0 => 1,
1 => $value,
2 => 3600,
3 => $badTime
]
);
$bag->set(
'WANCache:' . $tKey1 . '|#|t',
'PURGED:' . $goodTime
);
$bag->set(
'WANCache:' . $tKey2 . '|#|t',
'PURGED:' . $badTime
);
$this->assertSame( $value, $cache->get( $vKey1 ) );
$this->assertSame( $value, $cache->get( $vKey2 ) );
$cache->reap( $vKey1, $knownPurge, $bad1 );
$cache->reap( $vKey2, $knownPurge, $bad2 );
$this->assertSame( false, $bad1 );
$this->assertTrue( $bad2 );
$cache->reapCheckKey( $tKey1, $knownPurge, $tBad1 );
$cache->reapCheckKey( $tKey2, $knownPurge, $tBad2 );
$this->assertSame( false, $tBad1 );
$this->assertTrue( $tBad2 );
}
/**
* @covers WANObjectCache::reap()
*/
public function testReap_fail() {
$this->hideDeprecated( 'WANObjectCache::reap' );
$backend = $this->getMockBuilder( EmptyBagOStuff::class )
->onlyMethods( [ 'get', 'changeTTL' ] )->getMock();
$backend->expects( $this->once() )->method( 'get' )
->willReturn( [
0 => 1,
1 => 'value',
2 => 3600,
3 => 300,
] );
$backend->expects( $this->once() )->method( 'changeTTL' )
->willReturn( false );
$wanCache = new WANObjectCache( [
'cache' => $backend
] );
$isStale = null;
$ret = $wanCache->reap( 'key', 360, $isStale );
$this->assertTrue( $isStale, 'value was stale' );
$this->assertSame( false, $ret, 'changeTTL failed' );
}
/**
* @covers WANObjectCache::set()
*/