X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2Ffilebackend%2Flockmanager%2FRedisLockManager.php;h=ff4cba56ce90ec83cbc765638b3fc8b161737f8b;hb=bd2a78a159ce6d9f7b27fd75d05570228b44c3cb;hp=9d5612a313ecef890c773199904b5226056236f7;hpb=8f90b1cfa8bf0622ed06d796b4f8db684ed59aaf;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/filebackend/lockmanager/RedisLockManager.php b/includes/filebackend/lockmanager/RedisLockManager.php index 9d5612a313..ff4cba56ce 100644 --- a/includes/filebackend/lockmanager/RedisLockManager.php +++ b/includes/filebackend/lockmanager/RedisLockManager.php @@ -78,116 +78,89 @@ class RedisLockManager extends QuorumLockManager { $this->session = wfRandomString( 32 ); } - // @TODO: change this code to work in one batch protected function getLocksOnServer( $lockSrv, array $pathsByType ) { $status = Status::newGood(); - $lockedPaths = array(); - foreach ( $pathsByType as $type => $paths ) { - $status->merge( $this->doGetLocksOnServer( $lockSrv, $paths, $type ) ); - if ( $status->isOK() ) { - $lockedPaths[$type] = isset( $lockedPaths[$type] ) - ? array_merge( $lockedPaths[$type], $paths ) - : $paths; - } else { - foreach ( $lockedPaths as $lType => $lPaths ) { - $status->merge( $this->doFreeLocksOnServer( $lockSrv, $lPaths, $lType ) ); - } - break; - } - } - - return $status; - } - - // @todo Change this code to work in one batch - protected function freeLocksOnServer( $lockSrv, array $pathsByType ) { - $status = Status::newGood(); - - foreach ( $pathsByType as $type => $paths ) { - $status->merge( $this->doFreeLocksOnServer( $lockSrv, $paths, $type ) ); - } - - return $status; - } - - protected function doGetLocksOnServer( $lockSrv, array $paths, $type ) { - $status = Status::newGood(); - $server = $this->lockServers[$lockSrv]; $conn = $this->redisPool->getConnection( $server ); if ( !$conn ) { - foreach ( $paths as $path ) { + foreach ( array_merge( array_values( $pathsByType ) ) as $path ) { $status->fatal( 'lockmanager-fail-acquirelock', $path ); } return $status; } - $keys = array_map( array( $this, 'recordKeyForPath' ), $paths ); // lock records + $pathsByKey = array(); // (type:hash => path) map + foreach ( $pathsByType as $type => $paths ) { + $typeString = ( $type == LockManager::LOCK_SH ) ? 'SH' : 'EX'; + foreach ( $paths as $path ) { + $pathsByKey[$this->recordKeyForPath( $path, $typeString )] = $path; + } + } try { static $script = <<luaEval( $script, array_merge( - $keys, // KEYS[0], KEYS[1],...KEYS[N] + array_keys( $pathsByKey ), // KEYS[0], KEYS[1],...,KEYS[N] array( - $type === self::LOCK_SH ? 'SH' : 'EX', // ARGV[1] - $this->session, // ARGV[2] - $this->lockTTL, // ARGV[3] - time() // ARGV[4] + $this->session, // ARGV[1] + $this->lockTTL, // ARGV[2] + time() // ARGV[3] ) ), - count( $keys ) # number of first argument(s) that are keys + count( $pathsByKey ) # number of first argument(s) that are keys ); } catch ( RedisException $e ) { $res = false; - $this->redisPool->handleException( $server, $conn, $e ); + $this->redisPool->handleError( $conn, $e ); } if ( $res === false ) { - foreach ( $paths as $path ) { + foreach ( array_merge( array_values( $pathsByType ) ) as $path ) { $status->fatal( 'lockmanager-fail-acquirelock', $path ); } } else { - $pathsByKey = array_combine( $keys, $paths ); foreach ( $res as $key ) { $status->fatal( 'lockmanager-fail-acquirelock', $pathsByKey[$key] ); } @@ -196,62 +169,66 @@ LUA; return $status; } - protected function doFreeLocksOnServer( $lockSrv, array $paths, $type ) { + protected function freeLocksOnServer( $lockSrv, array $pathsByType ) { $status = Status::newGood(); $server = $this->lockServers[$lockSrv]; $conn = $this->redisPool->getConnection( $server ); if ( !$conn ) { - foreach ( $paths as $path ) { + foreach ( array_merge( array_values( $pathsByType ) ) as $path ) { $status->fatal( 'lockmanager-fail-releaselock', $path ); } return $status; } - $keys = array_map( array( $this, 'recordKeyForPath' ), $paths ); // lock records + $pathsByKey = array(); // (type:hash => path) map + foreach ( $pathsByType as $type => $paths ) { + $typeString = ( $type == LockManager::LOCK_SH ) ? 'SH' : 'EX'; + foreach ( $paths as $path ) { + $pathsByKey[$this->recordKeyForPath( $path, $typeString )] = $path; + } + } try { static $script = << 0 then -- Remove the whole structure if it is now empty if redis.call('hLen',resourceKey) == 0 then redis.call('del',resourceKey) end else - failed[#failed+1] = resourceKey + failed[#failed+1] = requestKey end end return failed LUA; $res = $conn->luaEval( $script, array_merge( - $keys, // KEYS[0], KEYS[1],...KEYS[N] + array_keys( $pathsByKey ), // KEYS[0], KEYS[1],...,KEYS[N] array( - $type === self::LOCK_SH ? 'SH' : 'EX', // ARGV[1] - $this->session // ARGV[2] + $this->session, // ARGV[1] ) ), - count( $keys ) # number of first argument(s) that are keys + count( $pathsByKey ) # number of first argument(s) that are keys ); } catch ( RedisException $e ) { $res = false; - $this->redisPool->handleException( $server, $conn, $e ); + $this->redisPool->handleError( $conn, $e ); } if ( $res === false ) { - foreach ( $paths as $path ) { + foreach ( array_merge( array_values( $pathsByType ) ) as $path ) { $status->fatal( 'lockmanager-fail-releaselock', $path ); } } else { - $pathsByKey = array_combine( $keys, $paths ); foreach ( $res as $key ) { $status->fatal( 'lockmanager-fail-releaselock', $pathsByKey[$key] ); } @@ -270,10 +247,12 @@ LUA; /** * @param string $path + * @param string $type One of (EX,SH) * @return string */ - protected function recordKeyForPath( $path ) { - return implode( ':', array( __CLASS__, 'locks', $this->sha1Base36Absolute( $path ) ) ); + protected function recordKeyForPath( $path, $type ) { + return implode( ':', + array( __CLASS__, 'locks', "$type:" . $this->sha1Base36Absolute( $path ) ) ); } /** @@ -281,10 +260,13 @@ LUA; */ function __destruct() { while ( count( $this->locksHeld ) ) { + $pathsByType = array(); foreach ( $this->locksHeld as $path => $locks ) { - $this->doUnlock( array( $path ), self::LOCK_EX ); - $this->doUnlock( array( $path ), self::LOCK_SH ); + foreach ( $locks as $type => $count ) { + $pathsByType[$type][] = $path; + } } + $this->unlockByType( $pathsByType ); } } }