public function getLagTimes($serverIndexes, $wiki) { if (count($serverIndexes) == 1 && reset($serverIndexes) == 0) { // Single server only, just return zero without caching return array(0 => 0); } $expiry = 5; $requestRate = 10; $cache = $this->cache; $masterName = $this->parent->getServerName(0); $memcKey = wfMemcKey('lag_times', $masterName); $times = $cache->get($memcKey); if (is_array($times)) { # Randomly recache with probability rising over $expiry $elapsed = time() - $times['timestamp']; $chance = max(0, ($expiry - $elapsed) * $requestRate); if (mt_rand(0, $chance) != 0) { unset($times['timestamp']); // hide from caller return $times; } wfIncrStats('lag_cache.miss.expired'); } else { wfIncrStats('lag_cache.miss.absent'); } # Cache key missing or expired if ($cache->lock($memcKey, 0, 10)) { # Let this process alone update the cache value $unlocker = new ScopedCallback(function () use($cache, $memcKey) { $cache->unlock($memcKey); }); } elseif (is_array($times)) { # Could not acquire lock but an old cache exists, so use it unset($times['timestamp']); // hide from caller return $times; } $times = array(); foreach ($serverIndexes as $i) { if ($i == 0) { # Master $times[$i] = 0; } elseif (false !== ($conn = $this->parent->getAnyOpenConnection($i))) { $times[$i] = $conn->getLag(); } elseif (false !== ($conn = $this->parent->openConnection($i, $wiki))) { $times[$i] = $conn->getLag(); // Close the connection to avoid sleeper connections piling up. // Note that the caller will pick one of these DBs and reconnect, // which is slightly inefficient, but this only matters for the lag // time cache miss cache, which is far less common that cache hits. $this->parent->closeConnection($conn); } } # Add a timestamp key so we know when it was cached $times['timestamp'] = time(); $cache->set($memcKey, $times, $expiry + 10); unset($times['timestamp']); // hide from caller return $times; }
public function getLagTimes($serverIndexes, $wiki) { if (count($serverIndexes) == 1 && reset($serverIndexes) == 0) { // Single server only, just return zero without caching return array(0 => 0); } $section = new ProfileSection(__METHOD__); $expiry = 5; $requestRate = 10; global $wgMemc; if (empty($wgMemc)) { $wgMemc = wfGetMainCache(); } $masterName = $this->parent->getServerName(0); $memcKey = wfMemcKey('lag_times', $masterName); $times = $wgMemc->get($memcKey); if (is_array($times)) { # Randomly recache with probability rising over $expiry $elapsed = time() - $times['timestamp']; $chance = max(0, ($expiry - $elapsed) * $requestRate); if (mt_rand(0, $chance) != 0) { unset($times['timestamp']); // hide from caller return $times; } wfIncrStats('lag_cache_miss_expired'); } else { wfIncrStats('lag_cache_miss_absent'); } # Cache key missing or expired if ($wgMemc->add("{$memcKey}:lock", 1, 10)) { # Let this process alone update the cache value $unlocker = new ScopedCallback(function () use($wgMemc, $memcKey) { $wgMemc->delete($memcKey); }); } elseif (is_array($times)) { # Could not acquire lock but an old cache exists, so use it unset($times['timestamp']); // hide from caller return $times; } $times = array(); foreach ($serverIndexes as $i) { if ($i == 0) { # Master $times[$i] = 0; } elseif (false !== ($conn = $this->parent->getAnyOpenConnection($i))) { $times[$i] = $conn->getLag(); } elseif (false !== ($conn = $this->parent->openConnection($i, $wiki))) { $times[$i] = $conn->getLag(); } } # Add a timestamp key so we know when it was cached $times['timestamp'] = time(); $wgMemc->set($memcKey, $times, $expiry + 10); unset($times['timestamp']); // hide from caller return $times; }
/** * @param $serverIndexes * @param $wiki * @return array */ function getLagTimes($serverIndexes, $wiki) { if (count($serverIndexes) == 1 && reset($serverIndexes) == 0) { // Single server only, just return zero without caching return array(0 => 0); } wfProfileIn(__METHOD__); $expiry = 5; $requestRate = 10; global $wgMemc; if (empty($wgMemc)) { $wgMemc = wfGetMainCache(); } $masterName = $this->parent->getServerName(0); $memcKey = wfMemcKey('lag_times', $masterName); $times = $wgMemc->get($memcKey); if ($times) { # Randomly recache with probability rising over $expiry $elapsed = time() - $times['timestamp']; $chance = max(0, ($expiry - $elapsed) * $requestRate); if (mt_rand(0, $chance) != 0) { unset($times['timestamp']); wfProfileOut(__METHOD__); return $times; } wfIncrStats('lag_cache_miss_expired'); } else { wfIncrStats('lag_cache_miss_absent'); } # Cache key missing or expired $times = array(); foreach ($serverIndexes as $i) { if ($i == 0) { # Master $times[$i] = 0; } elseif (false !== ($conn = $this->parent->getAnyOpenConnection($i))) { $times[$i] = $conn->getLag(); } elseif (false !== ($conn = $this->parent->openConnection($i, $wiki))) { $times[$i] = $conn->getLag(); } } # Add a timestamp key so we know when it was cached $times['timestamp'] = time(); $wgMemc->set($memcKey, $times, $expiry); # But don't give the timestamp to the caller unset($times['timestamp']); $lagTimes = $times; wfProfileOut(__METHOD__); return $lagTimes; }
/** * Notify the ChronologyProtector that the LoadBalancer is about to shut * down. Saves replication positions. * * @param LoadBalancer $lb * @return void */ public function shutdownLB(LoadBalancer $lb) { if (session_id() == '' || $lb->getServerCount() <= 1) { return; // don't start a session; don't bother with non-replicated setups } $masterName = $lb->getServerName(0); if (isset($this->shutdownPositions[$masterName])) { return; // already done } // Only save the position if writes have been done on the connection $db = $lb->getAnyOpenConnection(0); $info = $lb->parentInfo(); if (!$db || !$db->doneWrites()) { wfDebug(__METHOD__ . ": LB {$info['id']}, no writes done\n"); return; } $pos = $db->getMasterPos(); wfDebug(__METHOD__ . ": LB {$info['id']} has master pos {$pos}\n"); $this->shutdownPositions[$masterName] = $pos; }
/** * Notify the ChronologyProtector that the LoadBalancer is about to shut * down. Saves replication positions. * * @param LoadBalancer $lb * @return void */ public function shutdownLB(LoadBalancer $lb) { if (!$this->enabled || $lb->getServerCount() <= 1) { return; // non-replicated setup or disabled } $info = $lb->parentInfo(); $masterName = $lb->getServerName($lb->getWriterIndex()); // Only save the position if writes have been done on the connection $db = $lb->getAnyOpenConnection($lb->getWriterIndex()); if (!$db || !$db->doneWrites()) { wfDebugLog('replication', __METHOD__ . ": LB {$info['id']}, no writes done\n"); return; // nothing to do } $pos = $db->getMasterPos(); wfDebugLog('replication', __METHOD__ . ": LB {$info['id']} has master pos {$pos}\n"); $this->shutdownPositions[$masterName] = $pos; }
private function getLagTimeCacheKey() { # Lag is per-server, not per-DB, so key on the master DB name return wfGlobalCacheKey('lag-times', $this->parent->getServerName(0)); }
private function getLagTimeCacheKey() { $writerIndex = $this->parent->getWriterIndex(); // Lag is per-server, not per-DB, so key on the master DB name return $this->srvCache->makeGlobalKey('lag-times', $this->parent->getServerName($writerIndex)); }
private function getLagTimeCacheKey() { # Lag is per-server, not per-DB, so key on the master DB name return wfForeignMemcKey($this->parent->getServerName(0), '', 'lag_times'); }
/** * Notify the ChronologyProtector that the LoadBalancer is about to shut * down. Saves replication positions. * * @param LoadBalancer $lb */ function shutdownLB($lb) { if (session_id() != '' && $lb->getServerCount() > 1) { $masterName = $lb->getServerName(0); if (!isset($this->shutdownPos[$masterName])) { $pos = $lb->getMasterPos(); $info = $lb->parentInfo(); wfDebug(__METHOD__ . ": LB " . $info['id'] . " has master pos {$pos}\n"); $this->shutdownPos[$masterName] = $pos; } } }