Merge "[FileBackend] Added a "ttl" option to getFileHttpUrl()."
[lhc/web/wiklou.git] / includes / filebackend / FileBackendStore.php
index 4172819..35384c7 100644 (file)
@@ -57,8 +57,8 @@ abstract class FileBackendStore extends FileBackend {
         */
        public function __construct( array $config ) {
                parent::__construct( $config );
-               $this->memCache       = new EmptyBagOStuff(); // disabled by default
-               $this->cheapCache     = new ProcessCacheLRU( 300 );
+               $this->memCache = new EmptyBagOStuff(); // disabled by default
+               $this->cheapCache = new ProcessCacheLRU( 300 );
                $this->expensiveCache = new ProcessCacheLRU( 5 );
        }
 
@@ -97,6 +97,8 @@ abstract class FileBackendStore extends FileBackend {
         *   - async       : Status will be returned immediately if supported.
         *                   If the status is OK, then its value field will be
         *                   set to a FileBackendStoreOpHandle object.
+        *   - dstExists   : Whether a file exists at the destination (optimization).
+        *                   Callers can use "false" if no existing file is being changed.
         *
         * @param $params Array
         * @return Status
@@ -110,7 +112,9 @@ abstract class FileBackendStore extends FileBackend {
                } else {
                        $status = $this->doCreateInternal( $params );
                        $this->clearCache( array( $params['dst'] ) );
-                       $this->deleteFileCache( $params['dst'] ); // persistent cache
+                       if ( !isset( $params['dstExists'] ) || $params['dstExists'] ) {
+                               $this->deleteFileCache( $params['dst'] ); // persistent cache
+                       }
                }
                wfProfileOut( __METHOD__ . '-' . $this->name );
                wfProfileOut( __METHOD__ );
@@ -136,6 +140,8 @@ abstract class FileBackendStore extends FileBackend {
         *   - async       : Status will be returned immediately if supported.
         *                   If the status is OK, then its value field will be
         *                   set to a FileBackendStoreOpHandle object.
+        *   - dstExists   : Whether a file exists at the destination (optimization).
+        *                   Callers can use "false" if no existing file is being changed.
         *
         * @param $params Array
         * @return Status
@@ -149,7 +155,9 @@ abstract class FileBackendStore extends FileBackend {
                } else {
                        $status = $this->doStoreInternal( $params );
                        $this->clearCache( array( $params['dst'] ) );
-                       $this->deleteFileCache( $params['dst'] ); // persistent cache
+                       if ( !isset( $params['dstExists'] ) || $params['dstExists'] ) {
+                               $this->deleteFileCache( $params['dst'] ); // persistent cache
+                       }
                }
                wfProfileOut( __METHOD__ . '-' . $this->name );
                wfProfileOut( __METHOD__ );
@@ -175,6 +183,8 @@ abstract class FileBackendStore extends FileBackend {
         *   - async               : Status will be returned immediately if supported.
         *                           If the status is OK, then its value field will be
         *                           set to a FileBackendStoreOpHandle object.
+        *   - dstExists           : Whether a file exists at the destination (optimization).
+        *                           Callers can use "false" if no existing file is being changed.
         *
         * @param $params Array
         * @return Status
@@ -184,7 +194,9 @@ abstract class FileBackendStore extends FileBackend {
                wfProfileIn( __METHOD__ . '-' . $this->name );
                $status = $this->doCopyInternal( $params );
                $this->clearCache( array( $params['dst'] ) );
-               $this->deleteFileCache( $params['dst'] ); // persistent cache
+               if ( !isset( $params['dstExists'] ) || $params['dstExists'] ) {
+                       $this->deleteFileCache( $params['dst'] ); // persistent cache
+               }
                wfProfileOut( __METHOD__ . '-' . $this->name );
                wfProfileOut( __METHOD__ );
                return $status;
@@ -240,6 +252,8 @@ abstract class FileBackendStore extends FileBackend {
         *   - async               : Status will be returned immediately if supported.
         *                           If the status is OK, then its value field will be
         *                           set to a FileBackendStoreOpHandle object.
+        *   - dstExists           : Whether a file exists at the destination (optimization).
+        *                           Callers can use "false" if no existing file is being changed.
         *
         * @param $params Array
         * @return Status
@@ -250,7 +264,9 @@ abstract class FileBackendStore extends FileBackend {
                $status = $this->doMoveInternal( $params );
                $this->clearCache( array( $params['src'], $params['dst'] ) );
                $this->deleteFileCache( $params['src'] ); // persistent cache
-               $this->deleteFileCache( $params['dst'] ); // persistent cache
+               if ( !isset( $params['dstExists'] ) || $params['dstExists'] ) {
+                       $this->deleteFileCache( $params['dst'] ); // persistent cache
+               }
                wfProfileOut( __METHOD__ . '-' . $this->name );
                wfProfileOut( __METHOD__ );
                return $status;
@@ -350,12 +366,8 @@ abstract class FileBackendStore extends FileBackend {
         */
        protected function doConcatenate( array $params ) {
                $status = Status::newGood();
-
                $tmpPath = $params['dst']; // convenience
                unset( $params['latest'] ); // sanity
-               $callback = isset( $params['callback'] )
-                       ? $params['callback']
-                       : function( Status $status, $segment ) {};
 
                // Check that the specified temp file is valid...
                wfSuppressWarnings();
@@ -363,7 +375,6 @@ abstract class FileBackendStore extends FileBackend {
                wfRestoreWarnings();
                if ( !$ok ) { // not present or not empty
                        $status->fatal( 'backend-fail-opentemp', $tmpPath );
-                       $callback( $status, null ); // update progress
                        return $status;
                }
 
@@ -374,7 +385,6 @@ abstract class FileBackendStore extends FileBackend {
                                $fsFile = $this->getLocalReference( array( 'src' => $path ) );
                                if ( !$fsFile ) { // retry failed?
                                        $status->fatal( 'backend-fail-read', $path );
-                                       $callback( $status, null ); // update progress
                                        return $status;
                                }
                        }
@@ -385,20 +395,16 @@ abstract class FileBackendStore extends FileBackend {
                $tmpHandle = fopen( $tmpPath, 'ab' );
                if ( $tmpHandle === false ) {
                        $status->fatal( 'backend-fail-opentemp', $tmpPath );
-                       $callback( $status, null ); // update progress
                        return $status;
                }
 
-               $segment = 0; // segment number
                // Build up the temp file using the source chunks (in order)...
                foreach ( $fsFiles as $virtualSource => $fsFile ) {
-                       ++$segment; // first segment is "1"
                        // Get a handle to the local FS version
                        $sourceHandle = fopen( $fsFile->getPath(), 'rb' );
                        if ( $sourceHandle === false ) {
                                fclose( $tmpHandle );
                                $status->fatal( 'backend-fail-read', $virtualSource );
-                               $callback( $status, null ); // update progress
                                return $status;
                        }
                        // Append chunk to file (pass chunk size to avoid magic quotes)
@@ -406,20 +412,16 @@ abstract class FileBackendStore extends FileBackend {
                                fclose( $sourceHandle );
                                fclose( $tmpHandle );
                                $status->fatal( 'backend-fail-writetemp', $tmpPath );
-                               $callback( $status , null );
                                return $status;
                        }
                        fclose( $sourceHandle );
-                       $callback( $status, $segment ); // update progress (chunk success)
                }
                if ( !fclose( $tmpHandle ) ) {
                        $status->fatal( 'backend-fail-closetemp', $tmpPath );
-                       $callback( $status, null ); // update progress
                        return $status;
                }
 
                clearstatcache(); // temp file changed
-               $callback( $status, null ); // update progress (full success)
 
                return $status;
        }
@@ -664,12 +666,19 @@ abstract class FileBackendStore extends FileBackend {
                if ( $this->cheapCache->has( $path, 'stat', self::CACHE_TTL ) ) {
                        $stat = $this->cheapCache->get( $path, 'stat' );
                        // If we want the latest data, check that this cached
-                       // value was in fact fetched with the latest available data
-                       // (the process cache is ignored if it contains a negative).
-                       if ( !$latest || ( is_array( $stat ) && $stat['latest'] ) ) {
-                               wfProfileOut( __METHOD__ . '-' . $this->name );
-                               wfProfileOut( __METHOD__ );
-                               return $stat;
+                       // value was in fact fetched with the latest available data.
+                       if ( is_array( $stat ) ) {
+                               if ( !$latest || $stat['latest'] ) {
+                                       wfProfileOut( __METHOD__ . '-' . $this->name );
+                                       wfProfileOut( __METHOD__ );
+                                       return $stat;
+                               }
+                       } elseif ( in_array( $stat, array( 'NOT_EXIST', 'NOT_EXIST_LATEST' ) ) ) {
+                               if ( !$latest || $stat === 'NOT_EXIST_LATEST' ) {
+                                       wfProfileOut( __METHOD__ . '-' . $this->name );
+                                       wfProfileOut( __METHOD__ );
+                                       return false;
+                               }
                        }
                }
                wfProfileIn( __METHOD__ . '-miss' );
@@ -686,7 +695,7 @@ abstract class FileBackendStore extends FileBackend {
                                        array( 'hash' => $stat['sha1'], 'latest' => $latest ) );
                        }
                } elseif ( $stat === false ) { // file does not exist
-                       $this->cheapCache->set( $path, 'stat', false );
+                       $this->cheapCache->set( $path, 'stat', $latest ? 'NOT_EXIST_LATEST' : 'NOT_EXIST' );
                        wfDebug( __METHOD__ . ": File $path does not exist.\n" );
                } else { // an error occurred
                        wfDebug( __METHOD__ . ": Could not stat file $path.\n" );
@@ -758,10 +767,7 @@ abstract class FileBackendStore extends FileBackend {
                $hash = $this->doGetFileSha1Base36( $params );
                wfProfileOut( __METHOD__ . '-miss-' . $this->name );
                wfProfileOut( __METHOD__ . '-miss' );
-               if ( $hash ) { // don't cache negatives
-                       $this->cheapCache->set( $path, 'sha1',
-                               array( 'hash' => $hash, 'latest' => $latest ) );
-               }
+               $this->cheapCache->set( $path, 'sha1', array( 'hash' => $hash, 'latest' => $latest ) );
                wfProfileOut( __METHOD__ . '-' . $this->name );
                wfProfileOut( __METHOD__ );
                return $hash;
@@ -1661,6 +1667,8 @@ abstract class FileBackendStore extends FileBackend {
        /**
         * Delete the cached stat info for a file path.
         * The cache key is salted for a while to prevent race conditions.
+        * Since negatives (404s) are not cached, this does not need to be called when
+        * a file is created at a path were there was none before.
         *
         * @param $path string Storage path
         */