/** * @see FileBackend::getLocalReference() * @return TempFSFile|null */ public function getLocalReference(array $params) { $path = self::normalizeStoragePath($params['src']); if ($path === null) { return null; // invalid storage path } wfProfileIn(__METHOD__); wfProfileIn(__METHOD__ . '-' . $this->name); $latest = !empty($params['latest']); // use latest data? if ($this->expensiveCache->has($path, 'localRef')) { $val = $this->expensiveCache->get($path, 'localRef'); // If we want the latest data, check that this cached // value was in fact fetched with the latest available data. if (!$latest || $val['latest']) { wfProfileOut(__METHOD__ . '-' . $this->name); wfProfileOut(__METHOD__); return $val['object']; } } $tmpFile = $this->getLocalCopy($params); if ($tmpFile) { // don't cache negatives $this->expensiveCache->set($path, 'localRef', array('object' => $tmpFile, 'latest' => $latest)); } wfProfileOut(__METHOD__ . '-' . $this->name); wfProfileOut(__METHOD__); return $tmpFile; }
/** * Create a new BacklinkCache or reuse any existing one. * Currently, only one cache instance can exist; callers that * need multiple backlink cache objects should keep them in scope. * * @param Title $title : Title object to get a backlink cache for * @return BacklinkCache */ public static function get(Title $title) { if (!self::$cache) { // init cache self::$cache = new ProcessCacheLRU(1); } $dbKey = $title->getPrefixedDBkey(); if (!self::$cache->has($dbKey, 'obj')) { self::$cache->set($dbKey, 'obj', new self($title)); } return self::$cache->get($dbKey, 'obj'); }
/** * Check if jobs should not be popped of a queue right now. * This is only used for performance, such as to avoid spamming * the queue with many sub-jobs before they actually get run. * * @param $type string * @return bool */ public function isQueueDeprioritized( $type ) { if ( $this->cache->has( 'isDeprioritized', $type, 5 ) ) { return $this->cache->get( 'isDeprioritized', $type ); } if ( $type === 'refreshLinks2' ) { // Don't keep converting refreshLinks2 => refreshLinks jobs if the // later jobs have not been done yet. This helps throttle queue spam. $deprioritized = !$this->get( 'refreshLinks' )->isEmpty(); $this->cache->set( 'isDeprioritized', $type, $deprioritized ); return $deprioritized; } return false; }
/** * Get lag time for each server * * Results are cached for a short time in memcached/process cache * * @param string|bool $wiki * @return int[] Map of (server index => seconds) */ public function getLagTimes($wiki = false) { if ($this->getServerCount() <= 1) { return array(0 => 0); // no replication = no lag } if ($this->mProcCache->has('slave_lag', 'times', 1)) { return $this->mProcCache->get('slave_lag', 'times'); } # Send the request to the load monitor $times = $this->getLoadMonitor()->getLagTimes(array_keys($this->mServers), $wiki); $this->mProcCache->set('slave_lag', 'times', $times); return $times; }
/** * Search repositories for an image. * You can also use wfFindFile() to do this. * * @param Title|string $title Title object or string * @param array $options Associative array of options: * time: requested time for an archived image, or false for the * current version. An image object will be returned which was * created at the specified time. * ignoreRedirect: If true, do not follow file redirects * private: If true, return restricted (deleted) files if the current * user is allowed to view them. Otherwise, such files will not * be found. * latest: If true, load from the latest available data into File objects * @return File|bool False if title is not found */ function findFile($title, $options = []) { if (!is_array($options)) { // MW 1.15 compat $options = ['time' => $options]; } if (isset($options['bypassCache'])) { $options['latest'] = $options['bypassCache']; // b/c } if (!$this->reposInitialised) { $this->initialiseRepos(); } $title = File::normalizeTitle($title); if (!$title) { return false; } # Check the cache $dbkey = $title->getDBkey(); if (empty($options['ignoreRedirect']) && empty($options['private']) && empty($options['bypassCache'])) { $time = isset($options['time']) ? $options['time'] : ''; if ($this->cache->has($dbkey, $time, 60)) { return $this->cache->get($dbkey, $time); } $useCache = true; } else { $time = false; $useCache = false; } # Check the local repo $image = $this->localRepo->findFile($title, $options); # Check the foreign repos if (!$image) { foreach ($this->foreignRepos as $repo) { $image = $repo->findFile($title, $options); if ($image) { break; } } } $image = $image ? $image : false; // type sanity # Cache file existence or non-existence if ($useCache && (!$image || $image->isCacheable())) { $this->cache->set($dbkey, $time, $image); } return $image; }
/** * Translate legacy "title" paths to their "sha1" counterparts * * E.g. mwstore://local-backend/local-public/a/ab/<name>.jpg * => mwstore://local-backend/local-original/x/y/z/<sha1>.jpg * * @param array $paths * @param bool $latest * @return array Translated paths in same order */ public function getBackendPaths(array $paths, $latest = true) { $db = $this->getDB($latest ? DB_MASTER : DB_SLAVE); $origBasePath = $this->backend->getContainerStoragePath("{$this->repoName}-original"); // @TODO: batching $resolved = array(); foreach ($paths as $i => $path) { if (!$latest && $this->resolvedPathCache->has($path, 'target', 10)) { $resolved[$i] = $this->resolvedPathCache->get($path, 'target'); continue; } list(, $container, $rel) = FileBackend::splitStoragePath($path); if ($container === "{$this->repoName}-public") { $name = basename($path); if (strpos($path, '!') !== false) { $sha1 = $db->selectField('oldimage', 'oi_sha1', array('oi_archive_name' => $name), __METHOD__); } else { $sha1 = $db->selectField('image', 'img_sha1', array('img_name' => $name), __METHOD__); } if (!strlen($sha1)) { $resolved[$i] = $path; // give up continue; } $resolved[$i] = $this->getPathForSHA1($sha1); $this->resolvedPathCache->set($path, 'target', $resolved[$i]); } elseif ($container === "{$this->repoName}-deleted") { $name = basename($path); // <hash>.<ext> $sha1 = substr($name, 0, strpos($name, '.')); // ignore extension $resolved[$i] = $this->getPathForSHA1($sha1); $this->resolvedPathCache->set($path, 'target', $resolved[$i]); } else { $resolved[$i] = $path; } } $res = array(); foreach ($paths as $i => $path) { $res[$i] = $resolved[$i]; } return $res; }
/** * Pop a job off one of the job queues * * This pops a job off a queue as specified by $wgJobTypeConf and * updates the aggregate job queue information cache as needed. * * @param int|string $qtype JobQueueGroup::TYPE_* constant or job type string * @param int $flags Bitfield of JobQueueGroup::USE_* constants * @param array $blacklist List of job types to ignore * @return Job|bool Returns false on failure */ public function pop($qtype = self::TYPE_DEFAULT, $flags = 0, array $blacklist = array()) { $job = false; if (is_string($qtype)) { // specific job type if (!in_array($qtype, $blacklist)) { $job = $this->get($qtype)->pop(); if (!$job) { JobQueueAggregator::singleton()->notifyQueueEmpty($this->wiki, $qtype); } } } else { // any job in the "default" jobs types if ($flags & self::USE_CACHE) { if (!$this->cache->has('queues-ready', 'list', self::PROC_CACHE_TTL)) { $this->cache->set('queues-ready', 'list', $this->getQueuesWithJobs()); } $types = $this->cache->get('queues-ready', 'list'); } else { $types = $this->getQueuesWithJobs(); } if ($qtype == self::TYPE_DEFAULT) { $types = array_intersect($types, $this->getDefaultQueueTypes()); } $types = array_diff($types, $blacklist); // avoid selected types shuffle($types); // avoid starvation foreach ($types as $type) { // for each queue... $job = $this->get($type)->pop(); if ($job) { // found break; } else { // not found JobQueueAggregator::singleton()->notifyQueueEmpty($this->wiki, $type); $this->cache->clear('queues-ready'); } } } return $job; }
/** * Get a Swift container object, possibly from process cache. * Use $reCache if the file count or byte count is needed. * * @param string $container Container name * @param bool $bypassCache Bypass all caches and load from Swift * @return CF_Container * @throws CloudFilesException */ protected function getContainer( $container, $bypassCache = false ) { $conn = $this->getConnection(); // Swift proxy connection if ( $bypassCache ) { // purge cache $this->connContainerCache->clear( $container ); } elseif ( !$this->connContainerCache->has( $container, 'obj' ) ) { $this->primeContainerCache( array( $container ) ); // check persistent cache } if ( !$this->connContainerCache->has( $container, 'obj' ) ) { $contObj = $conn->get_container( $container ); // NoSuchContainerException not thrown: container must exist $this->connContainerCache->set( $container, 'obj', $contObj ); // cache it if ( !$bypassCache ) { $this->setContainerCache( $container, // update persistent cache array( 'bytes' => $contObj->bytes_used, 'count' => $contObj->object_count ) ); } } return $this->connContainerCache->get( $container, 'obj' ); }
/** * @see FileBackend::getLocalReferenceMulti() * @return Array */ public final function getLocalReferenceMulti(array $params) { wfProfileIn(__METHOD__); wfProfileIn(__METHOD__ . '-' . $this->name); $params = $this->setConcurrencyFlags($params); $fsFiles = array(); // (path => FSFile) $latest = !empty($params['latest']); // use latest data? // Reuse any files already in process cache... foreach ($params['srcs'] as $src) { $path = self::normalizeStoragePath($src); if ($path === null) { $fsFiles[$src] = null; // invalid storage path } elseif ($this->expensiveCache->has($path, 'localRef')) { $val = $this->expensiveCache->get($path, 'localRef'); // If we want the latest data, check that this cached // value was in fact fetched with the latest available data. if (!$latest || $val['latest']) { $fsFiles[$src] = $val['object']; } } } // Fetch local references of any remaning files... $params['srcs'] = array_diff($params['srcs'], array_keys($fsFiles)); foreach ($this->doGetLocalReferenceMulti($params) as $path => $fsFile) { $fsFiles[$path] = $fsFile; if ($fsFile) { // update the process cache... $this->expensiveCache->set($path, 'localRef', array('object' => $fsFile, 'latest' => $latest)); } } wfProfileOut(__METHOD__ . '-' . $this->name); wfProfileOut(__METHOD__); return $fsFiles; }