protected function freeLocksOnServer($lockSrv, array $paths, $type) { $status = Status::newGood(); $server = $this->lockServers[$lockSrv]; $conn = $this->redisPool->getConnection($server); if (!$conn) { foreach ($paths as $path) { $status->fatal('lockmanager-fail-releaselock', $path); } return $status; } $keys = array_map(array($this, 'recordKeyForPath'), $paths); // lock records try { static $script = <<<LUA \t\t\tif ARGV[1] ~= 'EX' and ARGV[1] ~= 'SH' then \t\t\t\treturn redis.error_reply('Unrecognized lock type given (must be EX or SH)') \t\t\tend \t\t\tlocal failed = {} \t\t\tfor i,resourceKey in ipairs(KEYS) do \t\t\t\tlocal released = redis.call('hDel',resourceKey,ARGV[1] .. ':' .. ARGV[2]) \t\t\t\tif released > 0 then \t\t\t\t\t-- Remove the whole structure if it is now empty \t\t\t\t\tif redis.call('hLen',resourceKey) == 0 then \t\t\t\t\t\tredis.call('del',resourceKey) \t\t\t\t\tend \t\t\t\telse \t\t\t\t\tfailed[#failed+1] = resourceKey \t\t\t\tend \t\t\tend \t\t\treturn failed LUA; $res = $conn->luaEval($script, array_merge($keys, array($type === self::LOCK_SH ? 'SH' : 'EX', $this->session)), count($keys)); } catch (RedisException $e) { $res = false; $this->redisPool->handleException($server, $conn, $e); } if ($res === false) { foreach ($paths 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]); } } return $status; }
/** * The redis extension throws an exception in response to various read, write * and protocol errors. Sometimes it also closes the connection, sometimes * not. The safest response for us is to explicitly destroy the connection * object and let it be reopened during the next request. */ protected function handleException( $server, RedisConnRef $conn, $e ) { $this->redisPool->handleException( $server, $conn, $e ); }
/** * @param $server string * @param $conn RedisConnRef * @param $e RedisException * @throws MWException */ protected function throwRedisException($server, RedisConnRef $conn, $e) { $this->redisPool->handleException($server, $conn, $e); throw new MWException("Redis server error: {$e->getMessage()}\n"); }