Merge "Made LocalFile move/delete/restore handle network partitions better"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Thu, 21 Aug 2014 15:38:10 +0000 (15:38 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Thu, 21 Aug 2014 15:38:10 +0000 (15:38 +0000)
1  2 
includes/filerepo/FileRepo.php
includes/filerepo/file/LocalFile.php

@@@ -1346,13 -1346,16 +1346,16 @@@ class FileRepo 
         * Checks existence of an array of files.
         *
         * @param array $files Virtual URLs (or storage paths) of files to check
-        * @return array|bool Either array of files and existence flags, or false
+        * @return array Map of files and existence flags, or false
         */
        public function fileExistsBatch( array $files ) {
+               $paths = array_map( array( $this, 'resolveToStoragePath' ), $files );
+               $this->backend->preloadFileStat( array( 'srcs' => $paths ) );
                $result = array();
                foreach ( $files as $key => $file ) {
-                       $file = $this->resolveToStoragePath( $file );
-                       $result[$key] = $this->backend->fileExists( array( 'src' => $file ) );
+                       $path = $this->resolveToStoragePath( $file );
+                       $result[$key] = $this->backend->fileExists( array( 'src' => $path ) );
                }
  
                return $result;
         * Delete files in the deleted directory if they are not referenced in the filearchive table
         *
         * STUB
 +       * @param array $storageKeys
         */
        public function cleanupDeletedBatch( array $storageKeys ) {
                $this->assertWritableRepo();
@@@ -379,7 -379,6 +379,7 @@@ class LocalFile extends File 
  
        /**
         * Load file metadata from the DB
 +       * @param int $flags
         */
        function loadFromDB( $flags = 0 ) {
                # Polymorphic function name to distinguish foreign and local fetches
  
        /**
         * Delete cached transformed files for the current version only.
 +       * @param array $options
         */
        function purgeThumbnails( $options = array() ) {
                global $wgUseSquid;
@@@ -2284,7 -2282,12 +2284,12 @@@ class LocalFileDeleteBatch 
                $this->doDBInserts();
  
                // Removes non-existent file from the batch, so we don't get errors.
-               $this->deletionBatch = $this->removeNonexistentFiles( $this->deletionBatch );
+               $checkStatus = $this->removeNonexistentFiles( $this->deletionBatch );
+               if ( !$checkStatus->isGood() ) {
+                       $this->status->merge( $checkStatus );
+                       return $this->status;
+               }
+               $this->deletionBatch = $checkStatus->value;
  
                // Execute the file deletion batch
                $status = $this->file->repo->deleteBatch( $this->deletionBatch );
        /**
         * Removes non-existent files from a deletion batch.
         * @param array $batch
-        * @return array
+        * @return Status
         */
        function removeNonexistentFiles( $batch ) {
                $files = $newBatch = array();
                }
  
                $result = $this->file->repo->fileExistsBatch( $files );
+               if ( in_array( null, $result, true ) ) {
+                       return Status::newFatal( 'backend-fail-internal',
+                               $this->file->repo->getBackend()->getName() );
+               }
  
                foreach ( $batch as $batchItem ) {
                        if ( $result[$batchItem[0]] ) {
                        }
                }
  
-               return $newBatch;
+               return Status::newGood( $newBatch );
        }
  }
  
@@@ -2373,7 -2380,6 +2382,7 @@@ class LocalFileRestoreBatch 
  
        /**
         * Add a file by ID
 +       * @param int $fa_id
         */
        function addId( $fa_id ) {
                $this->ids[] = $fa_id;
  
        /**
         * Add a whole lot of files by ID
 +       * @param int[] $ids
         */
        function addIds( $ids ) {
                $this->ids = array_merge( $this->ids, $ids );
                }
  
                // Remove missing files from batch, so we don't get errors when undeleting them
-               $storeBatch = $this->removeNonexistentFiles( $storeBatch );
+               $checkStatus = $this->removeNonexistentFiles( $storeBatch );
+               if ( !$checkStatus->isGood() ) {
+                       $status->merge( $checkStatus );
+                       return $status;
+               }
+               $storeBatch = $checkStatus->value;
  
                // Run the store batch
                // Use the OVERWRITE_SAME flag to smooth over a common error
        /**
         * Removes non-existent files from a store batch.
         * @param array $triplets
-        * @return array
+        * @return Status
         */
        function removeNonexistentFiles( $triplets ) {
                $files = $filteredTriplets = array();
                }
  
                $result = $this->file->repo->fileExistsBatch( $files );
+               if ( in_array( null, $result, true ) ) {
+                       return Status::newFatal( 'backend-fail-internal',
+                               $this->file->repo->getBackend()->getName() );
+               }
  
                foreach ( $triplets as $file ) {
                        if ( $result[$file[0]] ) {
                        }
                }
  
-               return $filteredTriplets;
+               return Status::newGood( $filteredTriplets );
        }
  
        /**
@@@ -2824,7 -2838,12 +2842,12 @@@ class LocalFileMoveBatch 
                $status = $repo->newGood();
  
                $triplets = $this->getMoveTriplets();
-               $triplets = $this->removeNonexistentFiles( $triplets );
+               $checkStatus = $this->removeNonexistentFiles( $triplets );
+               if ( !$checkStatus->isGood() ) {
+                       $status->merge( $checkStatus );
+                       return $status;
+               }
+               $triplets = $checkStatus->value;
                $destFile = wfLocalFile( $this->target );
  
                $this->file->lock(); // begin
        /**
         * Removes non-existent files from move batch.
         * @param array $triplets
-        * @return array
+        * @return Status
         */
        function removeNonexistentFiles( $triplets ) {
                $files = array();
                }
  
                $result = $this->file->repo->fileExistsBatch( $files );
-               $filteredTriplets = array();
+               if ( in_array( null, $result, true ) ) {
+                       return Status::newFatal( 'backend-fail-internal',
+                               $this->file->repo->getBackend()->getName() );
+               }
  
+               $filteredTriplets = array();
                foreach ( $triplets as $file ) {
                        if ( $result[$file[0]] ) {
                                $filteredTriplets[] = $file;
                        }
                }
  
-               return $filteredTriplets;
+               return Status::newGood( $filteredTriplets );
        }
  
        /**
         * Cleanup a partially moved array of triplets by deleting the target
         * files. Called if something went wrong half way.
 +       * @param array $triplets
         */
        function cleanupTarget( $triplets ) {
                // Create dest pairs from the triplets
        /**
         * Cleanup a fully moved array of triplets by deleting the source files.
         * Called at the end of the move process if everything else went ok.
 +       * @param array $triplets
         */
        function cleanupSource( $triplets ) {
                // Create source file names from the triplets