From c3dec1193cdfc4e5ead50df39b572b67c153afc6 Mon Sep 17 00:00:00 2001 From: Aaron Schulz Date: Wed, 27 May 2015 11:52:44 -0700 Subject: [PATCH] Added BagOStuff READ_LATEST flag for replicated stores Bug: T88493 Change-Id: I7ea050a2eabba635f2aadb4e33b6f8fbfb1b01a8 --- includes/libs/objectcache/APCBagOStuff.php | 3 +- includes/libs/objectcache/BagOStuff.php | 11 ++++--- includes/libs/objectcache/EmptyBagOStuff.php | 2 +- includes/libs/objectcache/HashBagOStuff.php | 2 +- .../libs/objectcache/ReplicatedBagOStuff.php | 12 ++++--- .../libs/objectcache/WinCacheBagOStuff.php | 33 +------------------ includes/libs/objectcache/XCacheBagOStuff.php | 23 +------------ includes/objectcache/MemcachedBagOStuff.php | 7 +--- .../objectcache/MemcachedPeclBagOStuff.php | 13 ++------ .../objectcache/MemcachedPhpBagOStuff.php | 6 +--- includes/objectcache/MultiWriteBagOStuff.php | 9 ++--- includes/objectcache/ObjectCache.php | 11 +++++-- includes/objectcache/RedisBagOStuff.php | 4 +-- includes/objectcache/SqlBagOStuff.php | 13 ++------ 14 files changed, 38 insertions(+), 111 deletions(-) diff --git a/includes/libs/objectcache/APCBagOStuff.php b/includes/libs/objectcache/APCBagOStuff.php index cc54fe7dd8..0dbbaba987 100644 --- a/includes/libs/objectcache/APCBagOStuff.php +++ b/includes/libs/objectcache/APCBagOStuff.php @@ -27,7 +27,6 @@ * @ingroup Cache */ class APCBagOStuff extends BagOStuff { - /** * @var string String to append to each APC key. This may be changed * whenever the handling of values is changed, to prevent existing code @@ -35,7 +34,7 @@ class APCBagOStuff extends BagOStuff { **/ const KEY_SUFFIX = ':1'; - public function get( $key, &$casToken = null ) { + public function get( $key, &$casToken = null, $flags = 0 ) { $val = apc_fetch( $key . self::KEY_SUFFIX ); $casToken = $val; diff --git a/includes/libs/objectcache/BagOStuff.php b/includes/libs/objectcache/BagOStuff.php index 65ff0ee1fd..726c789e65 100644 --- a/includes/libs/objectcache/BagOStuff.php +++ b/includes/libs/objectcache/BagOStuff.php @@ -59,6 +59,9 @@ abstract class BagOStuff implements LoggerAwareInterface { const ERR_UNREACHABLE = 2; // can't connect const ERR_UNEXPECTED = 3; // response gave some error + /** Bitfield constants for get()/getMulti() */ + const READ_LATEST = 1; // use latest data for replicated stores + public function __construct( array $params = array() ) { if ( isset( $params['logger'] ) ) { $this->setLogger( $params['logger'] ); @@ -86,9 +89,10 @@ abstract class BagOStuff implements LoggerAwareInterface { * Get an item with the given key. Returns false if it does not exist. * @param string $key * @param mixed $casToken [optional] + * @param integer $flags Bitfield; supports READ_LATEST [optional] * @return mixed Returns false on failure */ - abstract public function get( $key, &$casToken = null ); + abstract public function get( $key, &$casToken = null, $flags = 0 ); /** * Set an item. @@ -262,14 +266,13 @@ abstract class BagOStuff implements LoggerAwareInterface { return false; } - /* *** Emulated functions *** */ - /** * Get an associative array containing the item for each of the keys that have items. * @param array $keys List of strings + * @param integer $flags Bitfield; supports READ_LATEST [optional] * @return array */ - public function getMulti( array $keys ) { + public function getMulti( array $keys, $flags = 0 ) { $res = array(); foreach ( $keys as $key ) { $val = $this->get( $key ); diff --git a/includes/libs/objectcache/EmptyBagOStuff.php b/includes/libs/objectcache/EmptyBagOStuff.php index 4ccf2707ae..55e84b05f2 100644 --- a/includes/libs/objectcache/EmptyBagOStuff.php +++ b/includes/libs/objectcache/EmptyBagOStuff.php @@ -27,7 +27,7 @@ * @ingroup Cache */ class EmptyBagOStuff extends BagOStuff { - public function get( $key, &$casToken = null ) { + public function get( $key, &$casToken = null, $flags = 0 ) { return false; } diff --git a/includes/libs/objectcache/HashBagOStuff.php b/includes/libs/objectcache/HashBagOStuff.php index 2c8b05a59d..185c74bfec 100644 --- a/includes/libs/objectcache/HashBagOStuff.php +++ b/includes/libs/objectcache/HashBagOStuff.php @@ -48,7 +48,7 @@ class HashBagOStuff extends BagOStuff { return true; } - public function get( $key, &$casToken = null ) { + public function get( $key, &$casToken = null, $flags = 0 ) { if ( !isset( $this->bag[$key] ) ) { return false; } diff --git a/includes/libs/objectcache/ReplicatedBagOStuff.php b/includes/libs/objectcache/ReplicatedBagOStuff.php index 1b246165f7..20e146d281 100644 --- a/includes/libs/objectcache/ReplicatedBagOStuff.php +++ b/includes/libs/objectcache/ReplicatedBagOStuff.php @@ -72,12 +72,16 @@ class ReplicatedBagOStuff extends BagOStuff { $this->readStore->setDebug( $debug ); } - public function get( $key, &$casToken = null ) { - return $this->readStore->get( $key, $casToken ); + public function get( $key, &$casToken = null, $flags = 0 ) { + return ( $flags & self::READ_LATEST ) + ? $this->writeStore->get( $key, $casToken, $flags ) + : $this->readStore->get( $key, $casToken, $flags ); } - public function getMulti( array $keys ) { - return $this->readStore->getMulti( $keys ); + public function getMulti( array $keys, $flags = 0 ) { + return ( $flags & self::READ_LATEST ) + ? $this->writeStore->getMulti( $keys, $flags ) + : $this->readStore->getMulti( $keys, $flags ); } public function set( $key, $value, $exptime = 0 ) { diff --git a/includes/libs/objectcache/WinCacheBagOStuff.php b/includes/libs/objectcache/WinCacheBagOStuff.php index 536257464e..c480aa08d9 100644 --- a/includes/libs/objectcache/WinCacheBagOStuff.php +++ b/includes/libs/objectcache/WinCacheBagOStuff.php @@ -28,15 +28,7 @@ * @ingroup Cache */ class WinCacheBagOStuff extends BagOStuff { - - /** - * Get a value from the WinCache object cache - * - * @param string $key Cache key - * @param int $casToken [optional] Cas token - * @return mixed - */ - public function get( $key, &$casToken = null ) { + public function get( $key, &$casToken = null, $flags = 0 ) { $val = wincache_ucache_get( $key ); $casToken = $val; @@ -48,14 +40,6 @@ class WinCacheBagOStuff extends BagOStuff { return $val; } - /** - * Store a value in the WinCache object cache - * - * @param string $key Cache key - * @param mixed $value Value to store - * @param int $expire Expiration time - * @return bool - */ public function set( $key, $value, $expire = 0 ) { $result = wincache_ucache_set( $key, serialize( $value ), $expire ); @@ -64,25 +48,10 @@ class WinCacheBagOStuff extends BagOStuff { return ( is_array( $result ) && $result === array() ) || $result; } - /** - * Store a value in the WinCache object cache, race condition-safe - * - * @param int $casToken Cas token - * @param string $key Cache key - * @param int $value Object to store - * @param int $exptime Expiration time - * @return bool - */ protected function cas( $casToken, $key, $value, $exptime = 0 ) { return wincache_ucache_cas( $key, $casToken, serialize( $value ) ); } - /** - * Remove a value from the WinCache object cache - * - * @param string $key Cache key - * @return bool - */ public function delete( $key ) { wincache_ucache_delete( $key ); diff --git a/includes/libs/objectcache/XCacheBagOStuff.php b/includes/libs/objectcache/XCacheBagOStuff.php index cfee92362a..9dbff6f174 100644 --- a/includes/libs/objectcache/XCacheBagOStuff.php +++ b/includes/libs/objectcache/XCacheBagOStuff.php @@ -28,14 +28,7 @@ * @ingroup Cache */ class XCacheBagOStuff extends BagOStuff { - /** - * Get a value from the XCache object cache - * - * @param string $key Cache key - * @param mixed $casToken Cas token - * @return mixed - */ - public function get( $key, &$casToken = null ) { + public function get( $key, &$casToken = null, $flags = 0 ) { $val = xcache_get( $key ); if ( is_string( $val ) ) { @@ -51,14 +44,6 @@ class XCacheBagOStuff extends BagOStuff { return $val; } - /** - * Store a value in the XCache object cache - * - * @param string $key Cache key - * @param mixed $value Object to store - * @param int $expire Expiration time - * @return bool - */ public function set( $key, $value, $expire = 0 ) { if ( !$this->isInteger( $value ) ) { $value = serialize( $value ); @@ -68,12 +53,6 @@ class XCacheBagOStuff extends BagOStuff { return true; } - /** - * Remove a value from the XCache object cache - * - * @param string $key Cache key - * @return bool - */ public function delete( $key ) { xcache_unset( $key ); return true; diff --git a/includes/objectcache/MemcachedBagOStuff.php b/includes/objectcache/MemcachedBagOStuff.php index eeca9b158a..e545aa55a6 100644 --- a/includes/objectcache/MemcachedBagOStuff.php +++ b/includes/objectcache/MemcachedBagOStuff.php @@ -57,12 +57,7 @@ class MemcachedBagOStuff extends BagOStuff { return $params; } - /** - * @param string $key - * @param mixed $casToken [optional] - * @return mixed - */ - public function get( $key, &$casToken = null ) { + public function get( $key, &$casToken = null, $flags = 0 ) { return $this->client->get( $this->encodeKey( $key ), $casToken ); } diff --git a/includes/objectcache/MemcachedPeclBagOStuff.php b/includes/objectcache/MemcachedPeclBagOStuff.php index f2c49281ba..7e6a4d7074 100644 --- a/includes/objectcache/MemcachedPeclBagOStuff.php +++ b/includes/objectcache/MemcachedPeclBagOStuff.php @@ -115,12 +115,7 @@ class MemcachedPeclBagOStuff extends MemcachedBagOStuff { $this->client->addServers( $servers ); } - /** - * @param string $key - * @param float $casToken [optional] - * @return mixed - */ - public function get( $key, &$casToken = null ) { + public function get( $key, &$casToken = null, $flags = 0 ) { $this->debugLog( "get($key)" ); $result = $this->client->get( $this->encodeKey( $key ), null, $casToken ); $result = $this->checkResult( $key, $result ); @@ -238,11 +233,7 @@ class MemcachedPeclBagOStuff extends MemcachedBagOStuff { return $result; } - /** - * @param array $keys - * @return array - */ - public function getMulti( array $keys ) { + public function getMulti( array $keys, $flags = 0 ) { $this->debugLog( 'getMulti(' . implode( ', ', $keys ) . ')' ); $callback = array( $this, 'encodeKey' ); $result = $this->client->getMulti( array_map( $callback, $keys ) ); diff --git a/includes/objectcache/MemcachedPhpBagOStuff.php b/includes/objectcache/MemcachedPhpBagOStuff.php index 6fba61ba0f..69792ada56 100644 --- a/includes/objectcache/MemcachedPhpBagOStuff.php +++ b/includes/objectcache/MemcachedPhpBagOStuff.php @@ -57,11 +57,7 @@ class MemcachedPhpBagOStuff extends MemcachedBagOStuff { $this->client->set_debug( $debug ); } - /** - * @param array $keys - * @return array - */ - public function getMulti( array $keys ) { + public function getMulti( array $keys, $flags = 0 ) { $callback = array( $this, 'encodeKey' ); return $this->client->get_multi( array_map( $callback, $keys ) ); } diff --git a/includes/objectcache/MultiWriteBagOStuff.php b/includes/objectcache/MultiWriteBagOStuff.php index be54e4d3cd..3a30f83bba 100644 --- a/includes/objectcache/MultiWriteBagOStuff.php +++ b/includes/objectcache/MultiWriteBagOStuff.php @@ -61,14 +61,9 @@ class MultiWriteBagOStuff extends BagOStuff { $this->doWrite( 'setDebug', $debug ); } - /** - * @param string $key - * @param mixed $casToken [optional] - * @return bool|mixed - */ - public function get( $key, &$casToken = null ) { + public function get( $key, &$casToken = null, $flags = 0 ) { foreach ( $this->caches as $cache ) { - $value = $cache->get( $key ); + $value = $cache->get( $key, null, $flags = 0 ); if ( $value !== false ) { return $value; } diff --git a/includes/objectcache/ObjectCache.php b/includes/objectcache/ObjectCache.php index c5850b6a7f..8a99f53f41 100644 --- a/includes/objectcache/ObjectCache.php +++ b/includes/objectcache/ObjectCache.php @@ -29,9 +29,13 @@ use MediaWiki\Logger\LoggerFactory; * The word "cache" has two main dictionary meanings, and both * are used in this factory class. They are: * - a) A place to store copies or computations on existing data - * for higher access speeds (the computer science definition) + * for higher access speeds (the computer science definition) * - b) A place to store lightweight data that is not canonically - * stored anywhere else (e.g. a "hoard" of objects) + * stored anywhere else (e.g. a "hoard" of objects) + * + * The former should always use strongly consistent stores, so callers don't + * have to deal with stale reads. The later may be eventually consistent, but + * callers can use BagOStuff:READ_LATEST to see the latest available data. * * @ingroup Cache */ @@ -238,9 +242,10 @@ class ObjectCache { * In general, this means avoiding updates on idempotent HTTP requests and * avoiding an assumption of perfect serializability (or accepting anomalies). * Reads may be eventually consistent or data might rollback as nodes flap. + * Callers can use BagOStuff:READ_LATEST to see the latest available data. * - * @since 1.26 * @return BagOStuff + * @since 1.26 */ static function getMainStashInstance() { global $wgMainStash; diff --git a/includes/objectcache/RedisBagOStuff.php b/includes/objectcache/RedisBagOStuff.php index 11dd660e0d..a9af9b126b 100644 --- a/includes/objectcache/RedisBagOStuff.php +++ b/includes/objectcache/RedisBagOStuff.php @@ -80,7 +80,7 @@ class RedisBagOStuff extends BagOStuff { } } - public function get( $key, &$casToken = null ) { + public function get( $key, &$casToken = null, $flags = 0 ) { list( $server, $conn ) = $this->getConnection( $key ); if ( !$conn ) { @@ -174,7 +174,7 @@ class RedisBagOStuff extends BagOStuff { return $result; } - public function getMulti( array $keys ) { + public function getMulti( array $keys, $flags = 0 ) { $batches = array(); $conns = array(); diff --git a/includes/objectcache/SqlBagOStuff.php b/includes/objectcache/SqlBagOStuff.php index 3b46249cf2..e08fec9926 100644 --- a/includes/objectcache/SqlBagOStuff.php +++ b/includes/objectcache/SqlBagOStuff.php @@ -220,12 +220,7 @@ class SqlBagOStuff extends BagOStuff { } } - /** - * @param string $key - * @param mixed $casToken [optional] - * @return mixed - */ - public function get( $key, &$casToken = null ) { + public function get( $key, &$casToken = null, $flags = 0 ) { $values = $this->getMulti( array( $key ) ); if ( array_key_exists( $key, $values ) ) { $casToken = $values[$key]; @@ -234,11 +229,7 @@ class SqlBagOStuff extends BagOStuff { return false; } - /** - * @param array $keys - * @return array - */ - public function getMulti( array $keys ) { + public function getMulti( array $keys, $flags = 0 ) { $values = array(); // array of (key => value) $keysByTable = array(); -- 2.20.1