X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2Ffilebackend%2FFileBackendStore.php;h=ce4deddf9af5435f2ce146b23e74db65d23155e8;hb=9a4968a2bab4104a0bff7da5771a271b95df00bf;hp=9a2ebb7188f308e12b089a7417b395a15a29b7c4;hpb=806df0771ec33e1e6abd4b83105a8c6ffa1d9bad;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/filebackend/FileBackendStore.php b/includes/filebackend/FileBackendStore.php index 9a2ebb7188..ce4deddf9a 100644 --- a/includes/filebackend/FileBackendStore.php +++ b/includes/filebackend/FileBackendStore.php @@ -46,7 +46,7 @@ abstract class FileBackendStore extends FileBackend { /** @var array Map of container names to sharding config */ protected $shardViaHashLevels = array(); - /** @var callback Method to get the MIME type of files */ + /** @var callable Method to get the MIME type of files */ protected $mimeCallback; protected $maxFileSize = 4294967296; // integer bytes (4GiB) @@ -464,7 +464,7 @@ abstract class FileBackendStore extends FileBackend { /** * @see FileBackendStore::doPrepare() - * @param $container + * @param string $container * @param string $dir * @param array $params * @return Status @@ -499,7 +499,7 @@ abstract class FileBackendStore extends FileBackend { /** * @see FileBackendStore::doSecure() - * @param $container + * @param string $container * @param string $dir * @param array $params * @return Status @@ -534,7 +534,7 @@ abstract class FileBackendStore extends FileBackend { /** * @see FileBackendStore::doPublish() - * @param $container + * @param string $container * @param string $dir * @param array $params * @return Status @@ -590,7 +590,7 @@ abstract class FileBackendStore extends FileBackend { /** * @see FileBackendStore::doClean() - * @param $container + * @param string $container * @param string $dir * @param array $params * @return Status @@ -648,7 +648,8 @@ abstract class FileBackendStore extends FileBackend { $stat = $this->doGetFileStat( $params ); wfProfileOut( __METHOD__ . '-miss-' . $this->name ); if ( is_array( $stat ) ) { // file exists - $stat['latest'] = $latest; + // Strongly consistent backends can automatically set "latest" + $stat['latest'] = isset( $stat['latest'] ) ? $stat['latest'] : $latest; $this->cheapCache->set( $path, 'stat', $stat ); $this->setFileCache( $path, $stat ); // update persistent cache if ( isset( $stat['sha1'] ) ) { // some backends store SHA-1 as metadata @@ -961,7 +962,7 @@ abstract class FileBackendStore extends FileBackend { * @param string $container Resolved container name * @param string $dir Resolved path relative to container * @param array $params - * @return Traversable|Array|null Returns null on failure + * @return Traversable|array|null Returns null on failure */ abstract public function getDirectoryListInternal( $container, $dir, array $params ); @@ -991,7 +992,7 @@ abstract class FileBackendStore extends FileBackend { * @param string $container Resolved container name * @param string $dir Resolved path relative to container * @param array $params - * @return Traversable|Array|null Returns null on failure + * @return Traversable|array|null Returns null on failure */ abstract public function getFileListInternal( $container, $dir, array $params ); @@ -1101,19 +1102,35 @@ abstract class FileBackendStore extends FileBackend { $paths = array_merge( $paths, $op->storagePathsRead() ); $paths = array_merge( $paths, $op->storagePathsChanged() ); } + + // Enlarge the cache to fit the stat entries of these files + $this->cheapCache->resize( max( 2 * count( $paths ), self::CACHE_CHEAP_SIZE ) ); + // Load from the persistent container caches $this->primeContainerCache( $paths ); // Get the latest stat info for all the files (having locked them) - $this->preloadFileStat( array( 'srcs' => $paths, 'latest' => true ) ); + $ok = $this->preloadFileStat( array( 'srcs' => $paths, 'latest' => true ) ); - // Actually attempt the operation batch... - $opts = $this->setConcurrencyFlags( $opts ); - $subStatus = FileOpBatch::attempt( $performOps, $opts, $this->fileJournal ); + if ( $ok ) { + // Actually attempt the operation batch... + $opts = $this->setConcurrencyFlags( $opts ); + $subStatus = FileOpBatch::attempt( $performOps, $opts, $this->fileJournal ); + } else { + // If we could not even stat some files, then bail out... + $subStatus = Status::newFatal( 'backend-fail-internal', $this->name ); + foreach ( $ops as $i => $op ) { // mark each op as failed + $subStatus->success[$i] = false; + ++$subStatus->failCount; + } + } // Merge errors into status fields $status->merge( $subStatus ); $status->success = $subStatus->success; // not done in merge() + // Shrink the stat cache back to normal size + $this->cheapCache->resize( self::CACHE_CHEAP_SIZE ); + return $status; } @@ -1281,11 +1298,12 @@ abstract class FileBackendStore extends FileBackend { final public function preloadFileStat( array $params ) { $section = new ProfileSection( __METHOD__ . "-{$this->name}" ); + $success = true; // no network errors $params['concurrency'] = ( $this->parallelize !== 'off' ) ? $this->concurrency : 1; $stats = $this->doGetFileStatMulti( $params ); if ( $stats === null ) { - return; // not supported + return true; // not supported } $latest = !empty( $params['latest'] ); // use latest data? @@ -1295,7 +1313,8 @@ abstract class FileBackendStore extends FileBackend { continue; // this shouldn't happen } if ( is_array( $stat ) ) { // file exists - $stat['latest'] = $latest; + // Strongly consistent backends can automatically set "latest" + $stat['latest'] = isset( $stat['latest'] ) ? $stat['latest'] : $latest; $this->cheapCache->set( $path, 'stat', $stat ); $this->setFileCache( $path, $stat ); // update persistent cache if ( isset( $stat['sha1'] ) ) { // some backends store SHA-1 as metadata @@ -1316,9 +1335,12 @@ abstract class FileBackendStore extends FileBackend { array( 'hash' => false, 'latest' => $latest ) ); wfDebug( __METHOD__ . ": File $path does not exist.\n" ); } else { // an error occurred + $success = false; wfDebug( __METHOD__ . ": Could not stat file $path.\n" ); } } + + return $success; } /** @@ -1565,7 +1587,7 @@ abstract class FileBackendStore extends FileBackend { * @return string */ private function containerCacheKey( $container ) { - return wfMemcKey( 'backend', $this->getName(), 'container', $container ); + return "filebackend:{$this->name}:{$this->wikiId}:container:{$container}"; } /** @@ -1646,7 +1668,7 @@ abstract class FileBackendStore extends FileBackend { * @return string */ private function fileCacheKey( $path ) { - return wfMemcKey( 'backend', $this->getName(), 'file', sha1( $path ) ); + return "filebackend:{$this->name}:{$this->wikiId}:file:" . sha1( $path ); } /** @@ -1664,7 +1686,22 @@ abstract class FileBackendStore extends FileBackend { } $age = time() - wfTimestamp( TS_UNIX, $val['mtime'] ); $ttl = min( 7 * 86400, max( 300, floor( .1 * $age ) ) ); - $this->memCache->add( $this->fileCacheKey( $path ), $val, $ttl ); + $key = $this->fileCacheKey( $path ); + // Set the cache unless it is currently salted with the value "PURGED". + // Using add() handles this except it also is a no-op in that case where + // the current value is not "latest" but $val is, so use CAS in that case. + if ( !$this->memCache->add( $key, $val, $ttl ) && !empty( $val['latest'] ) ) { + $this->memCache->merge( + $key, + function( BagOStuff $cache, $key, $cValue ) use ( $val ) { + return ( is_array( $cValue ) && empty( $cValue['latest'] ) ) + ? $val // update the stat cache with the lastest info + : false; // do nothing (cache is salted or some error happened) + }, + $ttl, + 1 + ); + } } /**