X-Git-Url: http://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2Ffilerepo%2FRepoGroup.php;h=809633632fe2e3bcdb80aa3e9ee27f92e3499d83;hb=6fcb33538fb85b5735761bd430ee8162030bcf8b;hp=d96e5024b5b51d792d60aab99995e5e6400ad71c;hpb=79d5225c0e864482269e2315f47b899697681e52;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/filerepo/RepoGroup.php b/includes/filerepo/RepoGroup.php index d96e5024b5..809633632f 100644 --- a/includes/filerepo/RepoGroup.php +++ b/includes/filerepo/RepoGroup.php @@ -1,18 +1,37 @@ localInfo = $localInfo; $this->foreignInfo = $foreignInfo; + $this->cache = array(); } /** * Search repositories for an image. - * You can also use wfGetFile() to do this. - * @param mixed $title Title object or string - * @param mixed $time The 14-char timestamp the file should have - * been uploaded, or false for the current version + * You can also use wfFindFile() to do this. + * + * @param $title Title|string Title object or string + * @param $options array 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. + * + * bypassCache: If true, do not use the process-local cache of File objects * @return File object or false if it is not found */ - function findFile( $title, $time = false ) { + function findFile( $title, $options = array() ) { + if ( !is_array( $options ) ) { + // MW 1.15 compat + $options = array( 'time' => $options ); + } if ( !$this->reposInitialised ) { $this->initialiseRepos(); } + $title = File::normalizeTitle( $title ); + if ( !$title ) { + return false; + } + + # Check the cache + if ( empty( $options['ignoreRedirect'] ) + && empty( $options['private'] ) + && empty( $options['bypassCache'] ) ) + { + $useCache = true; + $time = isset( $options['time'] ) ? $options['time'] : ''; + $dbkey = $title->getDBkey(); + if ( isset( $this->cache[$dbkey][$time] ) ) { + wfDebug( __METHOD__.": got File:$dbkey from process cache\n" ); + # Move it to the end of the list so that we can delete the LRU entry later + $tmp = $this->cache[$dbkey]; + unset( $this->cache[$dbkey] ); + $this->cache[$dbkey] = $tmp; + # Return the entry + return $this->cache[$dbkey][$time]; + } else { + # Add a negative cache entry, may be overridden + $this->trimCache(); + $this->cache[$dbkey][$time] = false; + $cacheEntry =& $this->cache[$dbkey][$time]; + } + } else { + $useCache = false; + } - $image = $this->localRepo->findFile( $title, $time ); + # Check the local repo + $image = $this->localRepo->findFile( $title, $options ); if ( $image ) { + if ( $useCache ) { + $cacheEntry = $image; + } return $image; } + + # Check the foreign repos foreach ( $this->foreignRepos as $repo ) { - $image = $repo->findFile( $title, $time ); + $image = $repo->findFile( $title, $options ); if ( $image ) { + if ( $useCache ) { + $cacheEntry = $image; + } return $image; } } + # Not found, do not override negative cache return false; } + function findFiles( $inputItems ) { + if ( !$this->reposInitialised ) { + $this->initialiseRepos(); + } + + $items = array(); + foreach ( $inputItems as $item ) { + if ( !is_array( $item ) ) { + $item = array( 'title' => $item ); + } + $item['title'] = File::normalizeTitle( $item['title'] ); + if ( $item['title'] ) { + $items[$item['title']->getDBkey()] = $item; + } + } + + $images = $this->localRepo->findFiles( $items ); + + foreach ( $this->foreignRepos as $repo ) { + // Remove found files from $items + foreach ( $images as $name => $image ) { + unset( $items[$name] ); + } + + $images = array_merge( $images, $repo->findFiles( $items ) ); + } + return $images; + } + /** * Interface for FileRepo::checkRedirect() + * @return bool */ - function checkRedirect( $title ) { + function checkRedirect( Title $title ) { if ( !$this->reposInitialised ) { $this->initialiseRepos(); } @@ -97,8 +209,50 @@ class RepoGroup { return false; } + /** + * Find an instance of the file with this key, created at the specified time + * Returns false if the file does not exist. + * + * @param $hash String base 36 SHA-1 hash + * @param $options array Option array, same as findFile() + * @return File object or false if it is not found + */ + function findFileFromKey( $hash, $options = array() ) { + if ( !$this->reposInitialised ) { + $this->initialiseRepos(); + } + + $file = $this->localRepo->findFileFromKey( $hash, $options ); + if ( !$file ) { + foreach ( $this->foreignRepos as $repo ) { + $file = $repo->findFileFromKey( $hash, $options ); + if ( $file ) break; + } + } + return $file; + } + + /** + * Find all instances of files with this key + * + * @param $hash String base 36 SHA-1 hash + * @return Array of File objects + */ + function findBySha1( $hash ) { + if ( !$this->reposInitialised ) { + $this->initialiseRepos(); + } + + $result = $this->localRepo->findBySha1( $hash ); + foreach ( $this->foreignRepos as $repo ) { + $result = array_merge( $result, $repo->findBySha1( $hash ) ); + } + return $result; + } + /** * Get the repo instance with a given key. + * @return bool|LocalRepo */ function getRepo( $index ) { if ( !$this->reposInitialised ) { @@ -114,12 +268,13 @@ class RepoGroup { } /** * Get the repo instance by its name + * @return bool */ function getRepoByName( $name ) { if ( !$this->reposInitialised ) { $this->initialiseRepos(); } - foreach ( $this->foreignRepos as $key => $repo ) { + foreach ( $this->foreignRepos as $repo ) { if ( $repo->name == $name) return $repo; } @@ -129,11 +284,39 @@ class RepoGroup { /** * Get the local repository, i.e. the one corresponding to the local image * table. Files are typically uploaded to the local repository. + * + * @return LocalRepo */ function getLocalRepo() { return $this->getRepo( 'local' ); } + /** + * Call a function for each foreign repo, with the repo object as the + * first parameter. + * + * @param $callback Callback: the function to call + * @param $params Array: optional additional parameters to pass to the function + * @return bool + */ + function forEachForeignRepo( $callback, $params = array() ) { + foreach( $this->foreignRepos as $repo ) { + $args = array_merge( array( $repo ), $params ); + if( call_user_func_array( $callback, $args ) ) { + return true; + } + } + return false; + } + + /** + * Does the installation have any foreign repos set up? + * @return Boolean + */ + function hasForeignRepos() { + return (bool)$this->foreignRepos; + } + /** * Initialise the $repos array */ @@ -160,11 +343,12 @@ class RepoGroup { /** * Split a virtual URL into repo, zone and rel parts - * @return an array containing repo, zone and rel + * @param $url string + * @return array containing repo, zone and rel */ function splitVirtualUrl( $url ) { if ( substr( $url, 0, 9 ) != 'mwrepo://' ) { - throw new MWException( __METHOD__.': unknown protoocl' ); + throw new MWException( __METHOD__.': unknown protocol' ); } $bits = explode( '/', substr( $url, 9 ), 3 ); @@ -183,7 +367,34 @@ class RepoGroup { $repo = $this->getRepo( $repoName ); return $repo->getFileProps( $fileName ); } else { - return File::getPropsFromPath( $fileName ); + return FSFile::getPropsFromPath( $fileName ); + } + } + + /** + * Limit cache memory + */ + protected function trimCache() { + while ( count( $this->cache ) >= self::MAX_CACHE_SIZE ) { + reset( $this->cache ); + $key = key( $this->cache ); + wfDebug( __METHOD__.": evicting $key\n" ); + unset( $this->cache[$key] ); + } + } + + /** + * Clear RepoGroup process cache used for finding a file + * @param $title Title|null Title of the file or null to clear all files + */ + public function clearCache( Title $title = null ) { + if ( $title == null ) { + $this->cache = array(); + } else { + $dbKey = $title->getDBkey(); + if ( isset( $this->cache[$dbKey] ) ) { + unset( $this->cache[$dbKey] ); + } } } }