/** * @param $info array|null */ function __construct($info) { parent::__construct($info); $this->wiki = $info['wiki']; list($this->dbName, $this->tablePrefix) = wfSplitWikiID($this->wiki); $this->hasSharedCache = $info['hasSharedCache']; }
/** * Get a memcached key * @return string */ public static function memcKey() { global $wgRegexBlockDatabase; $args = func_get_args(); if ($wgRegexBlockDatabase === false) { return call_user_func_array('wfMemcKey', $args); } else { $newArgs = array_merge(wfSplitWikiID($wgRegexBlockDatabase), $args); return call_user_func_array('wfForeignMemcKey', $newArgs); } }
/** * Get all databases that have a pending job * @param $type String Job type * @return array */ private function getPendingDbs($type) { global $wgLocalDatabases; $pendingDBs = array(); # Cross-reference DBs by master DB server $dbsByMaster = array(); foreach ($wgLocalDatabases as $db) { $lb = wfGetLB($db); $dbsByMaster[$lb->getServerName(0)][] = $db; } foreach ($dbsByMaster as $dbs) { $dbConn = wfGetDB(DB_MASTER, array(), $dbs[0]); $stype = $dbConn->addQuotes($type); # Padding row for MySQL bug $sql = "(SELECT '-------------------------------------------' as db)"; foreach ($dbs as $wikiId) { if ($sql != '') { $sql .= ' UNION '; } list($dbName, $tablePrefix) = wfSplitWikiID($wikiId); $dbConn->tablePrefix($tablePrefix); $jobTable = $dbConn->tableName('job'); if ($type === false) { $sql .= "(SELECT '{$wikiId}' as db FROM {$dbName}.{$jobTable} LIMIT 1)"; } else { $sql .= "(SELECT '{$wikiId}' as db FROM {$dbName}.{$jobTable} WHERE job_cmd={$stype} LIMIT 1)"; } } $res = $dbConn->query($sql, __METHOD__); $first = true; foreach ($res as $row) { if ($first) { // discard padding row $first = false; continue; } $pendingDBs[] = $row->db; } } return $pendingDBs; }
/** * @param $group * @return String */ public static function getGlobalRulesKey($group) { global $wgAbuseFilterIsCentral, $wgAbuseFilterCentralDB; if (!$wgAbuseFilterIsCentral) { list($globalSite, $globalPrefix) = wfSplitWikiID($wgAbuseFilterCentralDB); return wfForeignMemcKey($globalSite, $globalPrefix, 'abusefilter', 'rules', $group); } return wfMemcKey('abusefilter', 'rules', $group); }
/** * Get all databases that have a pending job * @param $type String Job type * @return array */ private function getPendingDbs() { global $wgLocalDatabases; $pendingDBs = array(); # Cross-reference DBs by master DB server $dbsByMaster = array(); foreach ($wgLocalDatabases as $db) { $lb = wfGetLB($db); $dbsByMaster[$lb->getServerName(0)][] = $db; } foreach ($dbsByMaster as $dbs) { $dbConn = wfGetDB(DB_MASTER, array(), $dbs[0]); # Padding row for MySQL bug $pad = str_repeat('-', 40); $sql = "(SELECT '{$pad}' as db, '{$pad}' as job_cmd)"; foreach ($dbs as $wikiId) { if ($sql != '') { $sql .= ' UNION '; } list($dbName, $tablePrefix) = wfSplitWikiID($wikiId); $dbConn->tablePrefix($tablePrefix); $jobTable = $dbConn->tableName('job'); $sql .= "(SELECT DISTINCT '{$wikiId}' as db, job_cmd FROM {$dbName}.{$jobTable} GROUP BY job_cmd)"; } $res = $dbConn->query($sql, __METHOD__); $first = true; foreach ($res as $row) { if ($first) { // discard padding row $first = false; continue; } $pendingDBs[$row->job_cmd][] = $row->db; } } return $pendingDBs; }
/** * @param string $name * @return mixed */ private function getCachedConfigVar($name) { global $wgConf, $wgMemc; if ($this->wiki === wfWikiID()) { return $GLOBALS[$name]; // common case } else { list($db, $prefix) = wfSplitWikiID($this->wiki); $key = wfForeignMemcKey($db, $prefix, 'configvalue', $name); $value = $wgMemc->get($key); // ('v' => ...) or false if (is_array($value)) { return $value['v']; } else { $value = $wgConf->getConfig($this->wiki, $name); $wgMemc->set($key, array('v' => $value), 86400 + mt_rand(0, 86400)); return $value; } } }
/** * @param string $property * @return string */ private function getCacheKey($property) { list($db, $prefix) = wfSplitWikiID($this->wiki); $cluster = is_string($this->cluster) ? $this->cluster : 'main'; return wfForeignMemcKey($db, $prefix, 'jobqueue', $cluster, $this->type, $property); }
/** * Get cache key */ protected function cacheKey() { $args = func_get_args(); $args = array_merge(wfSplitWikiID($this->mDb), $args); return call_user_func_array('wfForeignMemcKey', $args); }
/** * @return string */ private function getCacheKey( $property ) { list( $db, $prefix ) = wfSplitWikiID( $this->wiki ); return wfForeignMemcKey( $db, $prefix, 'jobqueue', $this->type, $property ); }
/** * @param $path string * @return string */ protected function recordKeyForPath($path) { $hash = LockManager::sha1Base36($path); list($db, $prefix) = wfSplitWikiID($this->wikiId); return wfForeignMemcKey($db, $prefix, __CLASS__, 'locks', $hash); }
/** * @param string $prop * @param string|null $type Override this for sibling queues * @return string */ private function getQueueKey($prop, $type = null) { $type = is_string($type) ? $type : $this->type; list($db, $prefix) = wfSplitWikiID($this->wiki); $keyspace = $prefix ? "{$db}-{$prefix}" : $db; $parts = array($keyspace, 'jobqueue', $type, $prop); // Parts are typically ASCII, but encode for sanity to escape ":" return implode(':', array_map('rawurlencode', $parts)); }
/** * Open a connection to a foreign DB, or return one if it is already open. * * Increments a reference count on the returned connection which locks the * connection to the requested wiki. This reference count can be * decremented by calling reuseConnection(). * * If a connection is open to the appropriate server already, but with the wrong * database, it will be switched to the right database and returned, as long as * it has been freed first with reuseConnection(). * * On error, returns false, and the connection which caused the * error will be available via $this->mErrorConnection. * * @param $i Integer: server index * @param string $wiki wiki ID to open * @return DatabaseBase */ function openForeignConnection( $i, $wiki ) { wfProfileIn( __METHOD__ ); list( $dbName, $prefix ) = wfSplitWikiID( $wiki ); if ( isset( $this->mConns['foreignUsed'][$i][$wiki] ) ) { // Reuse an already-used connection $conn = $this->mConns['foreignUsed'][$i][$wiki]; wfDebug( __METHOD__ . ": reusing connection $i/$wiki\n" ); } elseif ( isset( $this->mConns['foreignFree'][$i][$wiki] ) ) { // Reuse a free connection for the same wiki $conn = $this->mConns['foreignFree'][$i][$wiki]; unset( $this->mConns['foreignFree'][$i][$wiki] ); $this->mConns['foreignUsed'][$i][$wiki] = $conn; wfDebug( __METHOD__ . ": reusing free connection $i/$wiki\n" ); } elseif ( !empty( $this->mConns['foreignFree'][$i] ) ) { // Reuse a connection from another wiki $conn = reset( $this->mConns['foreignFree'][$i] ); $oldWiki = key( $this->mConns['foreignFree'][$i] ); if ( !$conn->selectDB( $dbName ) ) { $this->mLastError = "Error selecting database $dbName on server " . $conn->getServer() . " from client host " . wfHostname() . "\n"; $this->mErrorConnection = $conn; $conn = false; } else { $conn->tablePrefix( $prefix ); unset( $this->mConns['foreignFree'][$i][$oldWiki] ); $this->mConns['foreignUsed'][$i][$wiki] = $conn; wfDebug( __METHOD__ . ": reusing free connection from $oldWiki for $wiki\n" ); } } else { // Open a new connection $server = $this->mServers[$i]; $server['serverIndex'] = $i; $server['foreignPoolRefCount'] = 0; $server['foreign'] = true; $conn = $this->reallyOpenConnection( $server, $dbName ); if ( !$conn->isOpen() ) { wfDebug( __METHOD__ . ": error opening connection for $i/$wiki\n" ); $this->mErrorConnection = $conn; $conn = false; } else { $conn->tablePrefix( $prefix ); $this->mConns['foreignUsed'][$i][$wiki] = $conn; wfDebug( __METHOD__ . ": opened new connection for $i/$wiki\n" ); } } // Increment reference count if ( $conn ) { $refCount = $conn->getLBInfo( 'foreignPoolRefCount' ); $conn->setLBInfo( 'foreignPoolRefCount', $refCount + 1 ); } wfProfileOut( __METHOD__ ); return $conn; }
/** * @param $prop string * @param $type string|null * @return string */ private function getQueueKey($prop, $type = null) { $type = is_string($type) ? $type : $this->type; list($db, $prefix) = wfSplitWikiID($this->wiki); if (strlen($this->key)) { // namespaced queue (for testing) return wfForeignMemcKey($db, $prefix, 'jobqueue', $type, $this->key, $prop); } else { return wfForeignMemcKey($db, $prefix, 'jobqueue', $type, $prop); } }
/** * @param string $name * @return mixed */ private function getCachedConfigVar($name) { global $wgConf; if ($this->wiki === wfWikiID()) { return $GLOBALS[$name]; // common case } else { $cache = ObjectCache::getLocalClusterInstance(); list($db, $prefix) = wfSplitWikiID($this->wiki); $key = wfForeignMemcKey($db, $prefix, 'configvalue', $name); $value = $cache->get($key); // ('v' => ...) or false if (is_array($value)) { return $value['v']; } else { $value = $wgConf->getConfig($this->wiki, $name); $cache->set($key, array('v' => $value), $cache::TTL_DAY + mt_rand(0, $cache::TTL_DAY)); return $value; } } }
/** * Open a connection to a foreign DB, or return one if it is already open. * * Increments a reference count on the returned connection which locks the * connection to the requested wiki. This reference count can be * decremented by calling reuseConnection(). * * If a connection is open to the appropriate server already, but with the wrong * database, it will be switched to the right database and returned, as long as * it has been freed first with reuseConnection(). * * On error, returns false, and the connection which caused the * error will be available via $this->mErrorConnection. * * @param int $i Server index * @param string $wiki Wiki ID to open * @return DatabaseBase */ private function openForeignConnection($i, $wiki) { list($dbName, $prefix) = wfSplitWikiID($wiki); if (isset($this->mConns['foreignUsed'][$i][$wiki])) { // Reuse an already-used connection $conn = $this->mConns['foreignUsed'][$i][$wiki]; wfDebug(__METHOD__ . ": reusing connection {$i}/{$wiki}\n"); } elseif (isset($this->mConns['foreignFree'][$i][$wiki])) { // Reuse a free connection for the same wiki $conn = $this->mConns['foreignFree'][$i][$wiki]; unset($this->mConns['foreignFree'][$i][$wiki]); $this->mConns['foreignUsed'][$i][$wiki] = $conn; wfDebug(__METHOD__ . ": reusing free connection {$i}/{$wiki}\n"); } elseif (!empty($this->mConns['foreignFree'][$i])) { // Reuse a connection from another wiki $conn = reset($this->mConns['foreignFree'][$i]); $oldWiki = key($this->mConns['foreignFree'][$i]); // The empty string as a DB name means "don't care". // DatabaseMysqlBase::open() already handle this on connection. if ($dbName !== '' && !$conn->selectDB($dbName)) { $this->mLastError = "Error selecting database {$dbName} on server " . $conn->getServer() . " from client host " . wfHostname() . "\n"; $this->mErrorConnection = $conn; $conn = false; } else { $conn->tablePrefix($prefix); unset($this->mConns['foreignFree'][$i][$oldWiki]); $this->mConns['foreignUsed'][$i][$wiki] = $conn; wfDebug(__METHOD__ . ": reusing free connection from {$oldWiki} for {$wiki}\n"); } } else { // Open a new connection $server = $this->mServers[$i]; $server['serverIndex'] = $i; $server['foreignPoolRefCount'] = 0; $server['foreign'] = true; $conn = $this->reallyOpenConnection($server, $dbName); if (!$conn->isOpen()) { wfDebug(__METHOD__ . ": error opening connection for {$i}/{$wiki}\n"); $this->mErrorConnection = $conn; $conn = false; } else { $conn->tablePrefix($prefix); $this->mConns['foreignUsed'][$i][$wiki] = $conn; wfDebug(__METHOD__ . ": opened new connection for {$i}/{$wiki}\n"); } } // Increment reference count if ($conn) { $refCount = $conn->getLBInfo('foreignPoolRefCount'); $conn->setLBInfo('foreignPoolRefCount', $refCount + 1); } return $conn; }
/** * @param string $signature Hash identifier of the root job * @return string */ protected function getRootJobCacheKey($signature) { list($db, $prefix) = wfSplitWikiID($this->wiki); return wfForeignMemcKey($db, $prefix, 'jobqueue', $this->type, 'rootjob', $signature); }
/** * Get the database name and prefix based on the wiki ID * @param bool|string $wiki * @return array */ private function getDBNameAndPrefix($wiki = false) { if ($wiki === false) { global $wgDBname, $wgDBprefix; return array($wgDBname, $wgDBprefix); } else { return wfSplitWikiID($wiki); } }
/** * @return string */ private function getEmptinessCacheKey() { list($db, $prefix) = wfSplitWikiID($this->wiki); return wfForeignMemcKey($db, $prefix, 'jobqueue', $this->type, 'isempty'); }