From 12200a2332c99a90cb47aa7cf15aee479921897a Mon Sep 17 00:00:00 2001 From: Aaron Schulz Date: Wed, 11 Jul 2018 00:26:43 +0100 Subject: [PATCH] Make MultiWriteBagOStuff use the native merge() of each backend This lets backends that support CAS take advantage of it. Also fix race condition with merge() in asyncWrites mode where two threads might add to a list/set but the first request finishes after the second, which would erase an item during the set(). Bug: T198239 Change-Id: Ibd2539429746f12b4de74d0f031089cb80aa8b4b --- .../libs/objectcache/MultiWriteBagOStuff.php | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/includes/libs/objectcache/MultiWriteBagOStuff.php b/includes/libs/objectcache/MultiWriteBagOStuff.php index 91f4167e32..043f8cbbe2 100644 --- a/includes/libs/objectcache/MultiWriteBagOStuff.php +++ b/includes/libs/objectcache/MultiWriteBagOStuff.php @@ -122,7 +122,7 @@ class MultiWriteBagOStuff extends BagOStuff { && $missIndexes && ( $flags & self::READ_VERIFIED ) == self::READ_VERIFIED ) { - // Backfill the value to the lower (and often larger) cache tiers + // Backfill the value to the higher (and often faster/smaller) cache tiers $this->doWrite( $missIndexes, $this->asyncWrites, 'set', $key, $value, self::UPGRADE_TTL ); @@ -171,6 +171,23 @@ class MultiWriteBagOStuff extends BagOStuff { return $this->doWrite( $this->cacheIndexes, $this->asyncWrites, 'decr', $key, $value ); } + public function merge( $key, callable $callback, $exptime = 0, $attempts = 10, $flags = 0 ) { + $asyncWrites = ( ( $flags & self::WRITE_SYNC ) == self::WRITE_SYNC ) + ? false + : $this->asyncWrites; + + return $this->doWrite( + $this->cacheIndexes, + $asyncWrites, + 'merge', + $key, + $callback, + $exptime, + $attempts, + $flags + ); + } + public function lock( $key, $timeout = 6, $expiry = 6, $rclass = '' ) { // Only need to lock the first cache; also avoids deadlocks return $this->caches[0]->lock( $key, $timeout, $expiry, $rclass ); @@ -202,7 +219,7 @@ class MultiWriteBagOStuff extends BagOStuff { $ret = true; $args = array_slice( func_get_args(), 3 ); - if ( array_diff( $indexes, [ 0 ] ) && $asyncWrites ) { + if ( array_diff( $indexes, [ 0 ] ) && $asyncWrites && $method !== 'merge' ) { // Deep-clone $args to prevent misbehavior when something writes an // object to the BagOStuff then modifies it afterwards, e.g. T168040. $args = unserialize( serialize( $args ) ); -- 2.20.1