Make MessageCache use getWithSetCallback() for big messages
Change-Id: I8f93e1dffbcbbabf4d7cb361b001d8ca6e7ad954
This commit is contained in:
parent
56d45558b1
commit
04bc03a29a
1 changed files with 63 additions and 62 deletions
87
includes/cache/MessageCache.php
vendored
87
includes/cache/MessageCache.php
vendored
|
|
@ -55,7 +55,7 @@ class MessageCache {
|
||||||
/**
|
/**
|
||||||
* @var bool[] Map of (language code => boolean)
|
* @var bool[] Map of (language code => boolean)
|
||||||
*/
|
*/
|
||||||
protected $mCacheVolatile = [];
|
protected $cacheVolatile = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should mean that database cannot be used, but check
|
* Should mean that database cannot be used, but check
|
||||||
|
|
@ -272,7 +272,7 @@ class MessageCache {
|
||||||
# Hash of the contents is stored in memcache, to detect if data-center cache
|
# Hash of the contents is stored in memcache, to detect if data-center cache
|
||||||
# or local cache goes out of date (e.g. due to replace() on some other server)
|
# or local cache goes out of date (e.g. due to replace() on some other server)
|
||||||
list( $hash, $hashVolatile ) = $this->getValidationHash( $code );
|
list( $hash, $hashVolatile ) = $this->getValidationHash( $code );
|
||||||
$this->mCacheVolatile[$code] = $hashVolatile;
|
$this->cacheVolatile[$code] = $hashVolatile;
|
||||||
|
|
||||||
# Try the local cache and check against the cluster hash key...
|
# Try the local cache and check against the cluster hash key...
|
||||||
$cache = $this->getLocalCache( $code );
|
$cache = $this->getLocalCache( $code );
|
||||||
|
|
@ -966,10 +966,13 @@ class MessageCache {
|
||||||
* @return string|bool The message, or false if it does not exist or on error
|
* @return string|bool The message, or false if it does not exist or on error
|
||||||
*/
|
*/
|
||||||
public function getMsgFromNamespace( $title, $code ) {
|
public function getMsgFromNamespace( $title, $code ) {
|
||||||
|
// Load all MediaWiki page definitions into cache. Note that individual keys
|
||||||
|
// already loaded into cache during this request remain in the cache, which
|
||||||
|
// includes the value of hook-defined messages.
|
||||||
$this->load( $code );
|
$this->load( $code );
|
||||||
|
|
||||||
if ( $this->cache->hasField( $code, $title ) ) {
|
|
||||||
$entry = $this->cache->getField( $code, $title );
|
$entry = $this->cache->getField( $code, $title );
|
||||||
|
if ( $entry !== null ) {
|
||||||
if ( substr( $entry, 0, 1 ) === ' ' ) {
|
if ( substr( $entry, 0, 1 ) === ' ' ) {
|
||||||
// The message exists and is not '!TOO BIG'
|
// The message exists and is not '!TOO BIG'
|
||||||
return (string)substr( $entry, 1 );
|
return (string)substr( $entry, 1 );
|
||||||
|
|
@ -978,6 +981,7 @@ class MessageCache {
|
||||||
}
|
}
|
||||||
// Fall through and try invididual message cache below
|
// Fall through and try invididual message cache below
|
||||||
} else {
|
} else {
|
||||||
|
// Message does not have a MediaWiki page definition
|
||||||
$message = false;
|
$message = false;
|
||||||
Hooks::run( 'MessagesPreLoad', [ $title, &$message, $code ] );
|
Hooks::run( 'MessagesPreLoad', [ $title, &$message, $code ] );
|
||||||
if ( $message !== false ) {
|
if ( $message !== false ) {
|
||||||
|
|
@ -989,75 +993,72 @@ class MessageCache {
|
||||||
return $message;
|
return $message;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Individual message cache key
|
if ( $this->cacheVolatile[$code] ) {
|
||||||
$bigKey = $this->bigMessageCacheKey( $this->cache->getField( $code, 'HASH' ), $title );
|
|
||||||
|
|
||||||
if ( $this->mCacheVolatile[$code] ) {
|
|
||||||
$entry = false;
|
$entry = false;
|
||||||
// Make sure that individual keys respect the WAN cache holdoff period too
|
// Make sure that individual keys respect the WAN cache holdoff period too
|
||||||
LoggerFactory::getInstance( 'MessageCache' )->debug(
|
LoggerFactory::getInstance( 'MessageCache' )->debug(
|
||||||
__METHOD__ . ': loading volatile key \'{titleKey}\'',
|
__METHOD__ . ': loading volatile key \'{titleKey}\'',
|
||||||
[ 'titleKey' => $bigKey, 'code' => $code ] );
|
[ 'titleKey' => $title, 'code' => $code ] );
|
||||||
} else {
|
} else {
|
||||||
// Try the individual message cache
|
// Try the individual message cache
|
||||||
$entry = $this->wanCache->get( $bigKey );
|
$entry = $this->loadCachedMessagePageEntry(
|
||||||
|
$title,
|
||||||
|
$code,
|
||||||
|
$this->cache->getField( $code, 'HASH' )
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $entry !== false ) {
|
if ( $entry !== false && substr( $entry, 0, 1 ) === ' ' ) {
|
||||||
if ( substr( $entry, 0, 1 ) === ' ' ) {
|
|
||||||
$this->cache->setField( $code, $title, $entry );
|
$this->cache->setField( $code, $title, $entry );
|
||||||
// The message exists, so make sure a string is returned
|
// The message exists, so make sure a string is returned
|
||||||
return (string)substr( $entry, 1 );
|
return (string)substr( $entry, 1 );
|
||||||
} elseif ( $entry === '!NONEXISTENT' ) {
|
}
|
||||||
|
|
||||||
$this->cache->setField( $code, $title, '!NONEXISTENT' );
|
$this->cache->setField( $code, $title, '!NONEXISTENT' );
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
} else {
|
|
||||||
// Corrupt/obsolete entry, delete it
|
|
||||||
$this->wanCache->delete( $bigKey );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $dbKey
|
||||||
|
* @param string $code
|
||||||
|
* @param string $hash
|
||||||
|
* @return string Either " <MESSAGE>" or "!NONEXISTANT"
|
||||||
|
*/
|
||||||
|
private function loadCachedMessagePageEntry( $dbKey, $code, $hash ) {
|
||||||
|
return $this->wanCache->getWithSetCallback(
|
||||||
|
$this->bigMessageCacheKey( $hash, $dbKey ),
|
||||||
|
$this->mExpiry,
|
||||||
|
function ( $oldValue, &$ttl, &$setOpts ) use ( $dbKey, $code ) {
|
||||||
// Try loading the message from the database
|
// Try loading the message from the database
|
||||||
$dbr = wfGetDB( DB_REPLICA );
|
$dbr = wfGetDB( DB_REPLICA );
|
||||||
$cacheOpts = Database::getCacheSetOptions( $dbr );
|
$setOpts += Database::getCacheSetOptions( $dbr );
|
||||||
// Use newKnownCurrent() to avoid querying revision/user tables
|
// Use newKnownCurrent() to avoid querying revision/user tables
|
||||||
$titleObj = Title::makeTitle( NS_MEDIAWIKI, $title );
|
$title = Title::makeTitle( NS_MEDIAWIKI, $dbKey );
|
||||||
if ( $titleObj->getLatestRevID() ) {
|
$revision = Revision::newKnownCurrent( $dbr, $title );
|
||||||
$revision = Revision::newKnownCurrent(
|
if ( !$revision ) {
|
||||||
$dbr,
|
return '!NONEXISTENT';
|
||||||
$titleObj
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
$revision = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $revision ) {
|
|
||||||
$content = $revision->getContent();
|
$content = $revision->getContent();
|
||||||
if ( $content ) {
|
if ( $content ) {
|
||||||
$message = $this->getMessageTextFromContent( $content );
|
$message = $this->getMessageTextFromContent( $content );
|
||||||
if ( is_string( $message ) ) {
|
|
||||||
$this->cache->setField( $code, $title, ' ' . $message );
|
|
||||||
$this->wanCache->set( $bigKey, ' ' . $message, $this->mExpiry, $cacheOpts );
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// A possibly temporary loading failure
|
|
||||||
LoggerFactory::getInstance( 'MessageCache' )->warning(
|
LoggerFactory::getInstance( 'MessageCache' )->warning(
|
||||||
__METHOD__ . ': failed to load message page text for \'{titleKey}\'',
|
__METHOD__ . ': failed to load page text for \'{titleKey}\'',
|
||||||
[ 'titleKey' => $bigKey, 'code' => $code ] );
|
[ 'titleKey' => $dbKey, 'code' => $code ]
|
||||||
$message = null; // no negative caching
|
);
|
||||||
}
|
$message = null;
|
||||||
} else {
|
|
||||||
$message = false; // negative caching
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $message === false ) {
|
if ( is_string( $message ) ) {
|
||||||
// Negative caching in case a "too big" message is no longer available (deleted)
|
return ' ' . $message;
|
||||||
$this->cache->setField( $code, $title, '!NONEXISTENT' );
|
|
||||||
$this->wanCache->set( $bigKey, '!NONEXISTENT', $this->mExpiry, $cacheOpts );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $message;
|
$ttl = 5; // possibly a temporary loading failure
|
||||||
|
|
||||||
|
return '!NONEXISTENT';
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue