From: Aaron Schulz Date: Thu, 5 Jan 2012 06:18:36 +0000 (+0000) Subject: * Made use of FileBackend function 'latest' param in FileOp. X-Git-Tag: 1.31.0-rc.0~25516 X-Git-Url: http://git.cyclocoop.org/%40spipnet%40?a=commitdiff_plain;h=ae4a810b1ea7e5e3ae2aff4afdbd053becc1bc1f;p=lhc%2Fweb%2Fwiklou.git * Made use of FileBackend function 'latest' param in FileOp. * Added FileBackend process cache for fileExists(), getFileTimestamp(), and getLocalReference(). * Refactored getFileSha1Base36() into parent class and subclass functions. * Removed some FileBackendMultiWrite comment duplication. --- diff --git a/includes/filerepo/backend/FSFileBackend.php b/includes/filerepo/backend/FSFileBackend.php index 6eb73b3bca..5f2d04a330 100644 --- a/includes/filerepo/backend/FSFileBackend.php +++ b/includes/filerepo/backend/FSFileBackend.php @@ -337,9 +337,9 @@ class FSFileBackend extends FileBackend { } /** - * @see FileBackend::fileExists() + * @see FileBackend::doFileExists() */ - public function fileExists( array $params ) { + protected function doFileExists( array $params ) { list( $c, $source ) = $this->resolveStoragePathReal( $params['src'] ); if ( $source === null ) { return false; // invalid storage path @@ -351,9 +351,9 @@ class FSFileBackend extends FileBackend { } /** - * @see FileBackend::getFileTimestamp() + * @see FileBackend::doGetFileTimestamp() */ - public function getFileTimestamp( array $params ) { + public function doGetFileTimestamp( array $params ) { list( $c, $source ) = $this->resolveStoragePathReal( $params['src'] ); if ( $source === null ) { return false; // invalid storage path diff --git a/includes/filerepo/backend/FileBackend.php b/includes/filerepo/backend/FileBackend.php index 5f4cacc0d2..902f4cc811 100644 --- a/includes/filerepo/backend/FileBackend.php +++ b/includes/filerepo/backend/FileBackend.php @@ -37,9 +37,9 @@ abstract class FileBackendBase { * This should only be called from within FileBackendGroup. * * $config includes: - * 'name' : The unique name of this backend - * 'wikiId' : Prefix to container names that is unique to this wiki - * 'lockManager' : Registered name of a file lock manager to use + * 'name' : The unique name of this backend. + * 'wikiId' : Prefix to container names that is unique to this wiki. + * 'lockManager' : Registered name of a file lock manager to use. * 'readOnly' : Write operations are disallowed if this is a non-empty string. * It should be an explanation for the backend being read-only. * @@ -782,6 +782,48 @@ abstract class FileBackend extends FileBackendBase { return Status::newGood(); } + /** + * @see FileBackendBase::fileExists() + */ + final public function fileExists( array $params ) { + $path = $params['src']; + if ( isset( $this->cache[$path]['exists'] ) ) { + return $this->cache[$path]['exists']; + } + $exists = $this->doFileExists( $params ); + if ( $exists ) { // don't cache negatives + $this->trimCache(); // limit memory + $this->cache[$path]['exists'] = $exists; + } + return $exists; + } + + /** + * @see FileBackend::fileExists() + */ + abstract protected function doFileExists( array $params ); + + /** + * @see FileBackendBase::getFileTimestamp() + */ + final public function getFileTimestamp( array $params ) { + $path = $params['src']; + if ( isset( $this->cache[$path]['timestamp'] ) ) { + return $this->cache[$path]['timestamp']; + } + $timestamp = $this->doGetFileTimestamp( $params ); + if ( $timestamp ) { // don't cache negatives + $this->trimCache(); // limit memory + $this->cache[$path]['timestamp'] = $timestamp; + } + return $timestamp; + } + + /** + * @see FileBackend::getFileTimestamp() + */ + abstract protected function doGetFileTimestamp( array $params ); + /** * @see FileBackendBase::getFileContents() */ @@ -804,16 +846,23 @@ abstract class FileBackend extends FileBackendBase { if ( isset( $this->cache[$path]['sha1'] ) ) { return $this->cache[$path]['sha1']; } + $hash = $this->doGetFileSha1Base36( $params ); + if ( $hash ) { // don't cache negatives + $this->trimCache(); // limit memory + $this->cache[$path]['sha1'] = $hash; + } + return $hash; + } + + /** + * @see FileBackend::getFileSha1Base36() + */ + protected function doGetFileSha1Base36( array $params ) { $fsFile = $this->getLocalReference( $params ); if ( !$fsFile ) { return false; } else { - $sha1 = $fsFile->getSha1Base36(); - if ( $sha1 !== false ) { // don't cache negatives - $this->trimCache(); // limit memory - $this->cache[$path]['sha1'] = $sha1; - } - return $sha1; + return $fsFile->getSha1Base36(); } } @@ -833,7 +882,16 @@ abstract class FileBackend extends FileBackendBase { * @see FileBackendBase::getLocalReference() */ public function getLocalReference( array $params ) { - return $this->getLocalCopy( $params ); + $path = $params['src']; + if ( isset( $this->cache[$path]['localRef'] ) ) { + return $this->cache[$path]['localRef']; + } + $tmpFile = $this->getLocalCopy( $params ); + if ( $tmpFile ) { // don't cache negatives + $this->trimCache(); // limit memory + $this->cache[$path]['localRef'] = $tmpFile; + } + return $tmpFile; } /** diff --git a/includes/filerepo/backend/FileBackendMultiWrite.php b/includes/filerepo/backend/FileBackendMultiWrite.php index 241858ee20..c9fafa53b9 100644 --- a/includes/filerepo/backend/FileBackendMultiWrite.php +++ b/includes/filerepo/backend/FileBackendMultiWrite.php @@ -32,9 +32,7 @@ class FileBackendMultiWrite extends FileBackendBase { /** * Construct a proxy backend that consists of several internal backends. - * $config contains: - * 'name' : The name of the proxy backend - * 'lockManager' : Registered name of the file lock manager to use + * Additional $config params include: * 'backends' : Array of backend config and multi-backend settings. * Each value is the config used in the constructor of a * FileBackend class, but with these additional settings: diff --git a/includes/filerepo/backend/FileOp.php b/includes/filerepo/backend/FileOp.php index 38e61ac9a7..c4bd7c9623 100644 --- a/includes/filerepo/backend/FileOp.php +++ b/includes/filerepo/backend/FileOp.php @@ -26,6 +26,7 @@ abstract class FileOp { protected $state = self::STATE_NEW; // integer protected $failed = false; // boolean protected $useBackups = true; // boolean + protected $useLatest = true; // boolean protected $destSameAsSource = false; // boolean protected $destAlreadyExists = false; // boolean @@ -60,6 +61,17 @@ abstract class FileOp { $this->useBackups = false; } + /** + * Allow stale data for file reads and existence checks. + * If this is called, then disableBackups() should also be called + * unless the affected files are known to have not changed recently. + * + * @return void + */ + final protected function allowStaleReads() { + $this->useLatest = false; + } + /** * Attempt a series of file operations. * Callers are responsible for handling file locking. @@ -71,10 +83,14 @@ abstract class FileOp { final public static function attemptBatch( array $performOps, array $opts ) { $status = Status::newGood(); + $allowStale = isset( $opts['allowStale'] ) && $opts['allowStale']; $ignoreErrors = isset( $opts['ignoreErrors'] ) && $opts['ignoreErrors']; $predicates = FileOp::newPredicates(); // account for previous op in prechecks // Do pre-checks for each operation; abort on failure... foreach ( $performOps as $index => $fileOp ) { + if ( $allowStale ) { + $fileOp->allowStaleReads(); // allow potentially stale reads + } $status->merge( $fileOp->precheck( $predicates ) ); if ( !$status->isOK() ) { // operation failed? if ( $ignoreErrors ) { @@ -320,7 +336,7 @@ abstract class FileOp { $status = Status::newGood(); if ( $this->useBackups ) { // Check if a file already exists at the source... - $params = array( 'src' => $this->params['src'] ); + $params = array( 'src' => $this->params['src'], 'latest' => $this->useLatest ); if ( $this->backend->fileExists( $params ) ) { // Create a temporary backup copy... $this->tmpSourcePath = $this->backend->getLocalCopy( $params ); @@ -350,7 +366,7 @@ abstract class FileOp { if ( $this->getParam( 'overwriteDest' ) ) { if ( $this->useBackups ) { // Create a temporary backup copy... - $params = array( 'src' => $this->params['dst'] ); + $params = array( 'src' => $this->params['dst'], 'latest' => $this->useLatest ); $this->tmpDestFile = $this->backend->getLocalCopy( $params ); if ( !$this->tmpDestFile ) { $status->fatal( 'backend-fail-backup', $this->params['dst'] ); @@ -402,7 +418,8 @@ abstract class FileOp { if ( FileBackend::isStoragePath( $path ) ) { // For some backends (e.g. Swift, Azure) we can get // standard hashes to use for this types of comparisons. - $hash = $this->backend->getFileSha1Base36( array( 'src' => $path ) ); + $params = array( 'src' => $path, 'latest' => $this->useLatest ); + $hash = $this->backend->getFileSha1Base36( $params ); // Source file is on file system } else { wfSuppressWarnings(); @@ -470,7 +487,8 @@ abstract class FileOp { if ( isset( $predicates['exists'][$source] ) ) { return $predicates['exists'][$source]; // previous op assures this } else { - return $this->backend->fileExists( array( 'src' => $source ) ); + $params = array( 'src' => $source, 'latest' => $this->useLatest ); + return $this->backend->fileExists( $params ); } }