Cache user data in memory
Stores user data looked up in WAN cache in memory so that lookups in the
same request do not result in new memcached lookups.
Quick and dirty solution, but nicer ones are more difficult:
* no idea what replacing WANObjectCache::get/set with getWithSetCallback
(which has its own in-process cache) would do, the code is complex
and completely different
* would be nice to wrap the logic into a proxy object (like CachedBagOStuff)
but WANObjectCache calls set() internally (and marks it final), so
inheriting is not safe; the interface and implementation should be
separated, and that means updating all external callers which do a type
check.
* ObjectCache::getInstance('hash') cannot be used because it has no
item limit and this could eat up the memory with a script that iterates
through lots of users
The patch does not attempt to replicate tombstoning for
User::clearSharedCache('refresh').
Based on Iec1504700a and Idef9a9d3.
Change-Id: I419f356b0c306d16711b433da95dccdb44645154
Co-Authored-By: Ori Livneh <ori@wikimedia.org>
Bug: T128157
This commit is contained in:
parent
3071f1fad7
commit
9c73331810
1 changed files with 41 additions and 9 deletions
|
|
@ -187,6 +187,12 @@ class User implements IDBAccessObject {
|
|||
*/
|
||||
protected static $mAllRights = false;
|
||||
|
||||
/**
|
||||
* An in-process cache for user data lookup
|
||||
* @var HashBagOStuff
|
||||
*/
|
||||
protected static $inProcessCache;
|
||||
|
||||
/** Cache variables */
|
||||
// @{
|
||||
public $mId;
|
||||
|
|
@ -443,7 +449,10 @@ class User implements IDBAccessObject {
|
|||
*/
|
||||
public static function purge( $wikiId, $userId ) {
|
||||
$cache = ObjectCache::getMainWANInstance();
|
||||
$cache->delete( $cache->makeGlobalKey( 'user', 'id', $wikiId, $userId ) );
|
||||
$processCache = self::getInProcessCache();
|
||||
$key = $cache->makeGlobalKey( 'user', 'id', $wikiId, $userId );
|
||||
$cache->delete( $key );
|
||||
$processCache->delete( $key );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -455,6 +464,17 @@ class User implements IDBAccessObject {
|
|||
return $cache->makeGlobalKey( 'user', 'id', wfWikiID(), $this->mId );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.27
|
||||
* @return HashBagOStuff
|
||||
*/
|
||||
protected static function getInProcessCache() {
|
||||
if ( !self::$inProcessCache ) {
|
||||
self::$inProcessCache = new HashBagOStuff( ['maxKeys' => 10] );
|
||||
}
|
||||
return self::$inProcessCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load user data from shared cache, given mId has already been set.
|
||||
*
|
||||
|
|
@ -468,12 +488,17 @@ class User implements IDBAccessObject {
|
|||
}
|
||||
|
||||
$cache = ObjectCache::getMainWANInstance();
|
||||
$data = $cache->get( $this->getCacheKey( $cache ) );
|
||||
if ( !is_array( $data ) || $data['mVersion'] < self::VERSION ) {
|
||||
// Object is expired
|
||||
return false;
|
||||
$processCache = self::getInProcessCache();
|
||||
$key = $this->getCacheKey( $cache );
|
||||
$data = $processCache->get( $key );
|
||||
if ( !is_array( $data ) ) {
|
||||
$data = $cache->get( $key );
|
||||
if ( !is_array( $data ) || $data['mVersion'] < self::VERSION ) {
|
||||
// Object is expired
|
||||
return false;
|
||||
}
|
||||
$processCache->set( $key, $data );
|
||||
}
|
||||
|
||||
wfDebug( "User: got user {$this->mId} from cache\n" );
|
||||
|
||||
// Restore from cache
|
||||
|
|
@ -507,8 +532,10 @@ class User implements IDBAccessObject {
|
|||
$opts = Database::getCacheSetOptions( wfGetDB( DB_SLAVE ) );
|
||||
|
||||
$cache = ObjectCache::getMainWANInstance();
|
||||
$processCache = self::getInProcessCache();
|
||||
$key = $this->getCacheKey( $cache );
|
||||
$cache->set( $key, $data, $cache::TTL_HOUR, $opts );
|
||||
$processCache->set( $key, $data );
|
||||
}
|
||||
|
||||
/** @name newFrom*() static factory methods */
|
||||
|
|
@ -2296,13 +2323,18 @@ class User implements IDBAccessObject {
|
|||
}
|
||||
|
||||
$cache = ObjectCache::getMainWANInstance();
|
||||
$processCache = self::getInProcessCache();
|
||||
$key = $this->getCacheKey( $cache );
|
||||
if ( $mode === 'refresh' ) {
|
||||
$cache->delete( $key, 1 );
|
||||
$processCache->delete( $key );
|
||||
} else {
|
||||
wfGetDB( DB_MASTER )->onTransactionPreCommitOrIdle( function() use ( $cache, $key ) {
|
||||
$cache->delete( $key );
|
||||
} );
|
||||
wfGetDB( DB_MASTER )->onTransactionPreCommitOrIdle(
|
||||
function() use ( $cache, $processCache, $key ) {
|
||||
$cache->delete( $key );
|
||||
$processCache->delete( $key );
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue