/** * Get a Redis object with a connection suitable for fetching the specified key * @return Array (server, RedisConnRef) or (false, false) */ protected function getConnection( $key ) { if ( count( $this->servers ) === 1 ) { $candidates = $this->servers; } else { $candidates = $this->servers; ArrayUtils::consistentHashSort( $candidates, $key, '/' ); if ( !$this->automaticFailover ) { $candidates = array_slice( $candidates, 0, 1 ); } } foreach ( $candidates as $server ) { $conn = $this->redisPool->getConnection( $server ); if ( $conn ) { return array( $server, $conn ); } } return array( false, false ); }
/** * Get a Redis object with a connection suitable for fetching the specified key * @param string $key * @return array (server, RedisConnRef) or (false, false) */ protected function getConnection($key) { $candidates = array_keys($this->serverTagMap); if (count($this->servers) > 1) { ArrayUtils::consistentHashSort($candidates, $key, '/'); if (!$this->automaticFailover) { $candidates = array_slice($candidates, 0, 1); } } while (($tag = array_shift($candidates)) !== null) { $server = $this->serverTagMap[$tag]; $conn = $this->redisPool->getConnection($server); if (!$conn) { continue; } // If automatic failover is enabled, check that the server's link // to its master (if any) is up -- but only if there are other // viable candidates left to consider. Also, getMasterLinkStatus() // does not work with twemproxy, though $candidates will be empty // by now in such cases. if ($this->automaticFailover && $candidates) { try { if ($this->getMasterLinkStatus($conn) === 'down') { // If the master cannot be reached, fail-over to the next server. // If masters are in data-center A, and slaves in data-center B, // this helps avoid the case were fail-over happens in A but not // to the corresponding server in B (e.g. read/write mismatch). continue; } } catch (RedisException $e) { // Server is not accepting commands $this->handleException($conn, $e); continue; } } return array($server, $conn); } $this->setLastError(BagOStuff::ERR_UNREACHABLE); return array(false, false); }
/** * @return Status Uses RediConnRef as value on success */ protected function getConnection() { if (!isset($this->conn)) { $conn = false; $servers = $this->ring->getLocations($this->key, 3); ArrayUtils::consistentHashSort($servers, $this->key); foreach ($servers as $server) { $conn = $this->pool->getConnection($this->serversByLabel[$server], $this->logger); if ($conn) { break; } } if (!$conn) { return Status::newFatal('pool-servererror', implode(', ', $servers)); } $this->conn = $conn; } return Status::newGood($this->conn); }
/** * Get the server index and table name for a given key * @param string $key * @return array Server index and table name */ protected function getTableByKey($key) { if ($this->shards > 1) { $hash = hexdec(substr(md5($key), 0, 8)) & 0x7fffffff; $tableIndex = $hash % $this->shards; } else { $tableIndex = 0; } if ($this->numServers > 1) { $sortedServers = $this->serverNames; ArrayUtils::consistentHashSort($sortedServers, $key); reset($sortedServers); $serverIndex = key($sortedServers); } else { $serverIndex = 0; } return array($serverIndex, $this->getTableNameByShard($tableIndex)); }
/** * Get a Redis object with a connection suitable for fetching the specified key * @param string $key * @return array (server, RedisConnRef) or (false, false) */ protected function getConnection($key) { $candidates = array_keys($this->serverTagMap); if (count($this->servers) > 1) { ArrayUtils::consistentHashSort($candidates, $key, '/'); if (!$this->automaticFailover) { $candidates = array_slice($candidates, 0, 1); } } foreach ($candidates as $tag) { $server = $this->serverTagMap[$tag]; $conn = $this->redisPool->getConnection($server); if ($conn) { return array($server, $conn); } } $this->setLastError(BagOStuff::ERR_UNREACHABLE); return array(false, false); }
/** * Get a Redis object with a connection suitable for fetching the specified key * @param string $key * @return array (server, RedisConnRef) or (false, false) */ protected function getConnection($key) { $candidates = array_keys($this->serverTagMap); if (count($this->servers) > 1) { ArrayUtils::consistentHashSort($candidates, $key, '/'); if (!$this->automaticFailover) { $candidates = array_slice($candidates, 0, 1); } } foreach ($candidates as $tag) { $server = $this->serverTagMap[$tag]; $conn = $this->redisPool->getConnection($server); if (!$conn) { continue; } try { $info = $conn->info(); // Check if this server has an unreachable redis master if ($info['role'] === 'slave' && $info['master_link_status'] === 'down' && $this->automaticFailover) { // If the master cannot be reached, fail-over to the next server. // If masters are in data-center A, and slaves in data-center B, // this helps avoid the case were fail-over happens in A but not // to the corresponding server in B (e.g. read/write mismatch). continue; } } catch (RedisException $e) { // Server is not accepting commands $this->handleException($conn, $e); continue; } return array($server, $conn); } $this->setLastError(BagOStuff::ERR_UNREACHABLE); return array(false, false); }