Use quickImport() for upload chunk storage calls.
authorAaron Schulz <aschulz@wikimedia.org>
Sun, 9 Sep 2012 04:40:17 +0000 (21:40 -0700)
committerAaron Schulz <aschulz@wikimedia.org>
Sun, 9 Sep 2012 04:48:31 +0000 (21:48 -0700)
* Using store() is slower and causes problems with multiwrite backends,
  since the other temp storage calls already wrap doQuickOperations().
* Modified quickImport() to accept stored files as the source parameter.

Change-Id: I3b32b46ce6b5562bb661ec49255630236aeaa44c

includes/filerepo/FileRepo.php
includes/upload/UploadFromChunks.php

index 6a3ae12..a31b148 100644 (file)
@@ -696,7 +696,7 @@ class FileRepo {
        /**
         * Store a file to a given destination.
         *
-        * @param $srcPath String: source FS path, storage path, or virtual URL
+        * @param $srcPath String: source file system path, storage path, or virtual URL
         * @param $dstZone String: destination zone
         * @param $dstRel String: destination relative path
         * @param $flags Integer: bitwise combination of the following flags:
@@ -841,7 +841,7 @@ class FileRepo {
         * This function can be used to write to otherwise read-only foreign repos.
         * This is intended for copying generated thumbnails into the repo.
         *
-        * @param $src string File system path
+        * @param $src string Source file system path, storage path, or virtual URL
         * @param $dst string Virtual URL or storage path
         * @param $disposition string|null Content-Disposition if given and supported
         * @return FileRepoStatus
@@ -883,9 +883,10 @@ class FileRepo {
         * This function can be used to write to otherwise read-only foreign repos.
         * This is intended for copying generated thumbnails into the repo.
         *
+        * All path parameters may be a file system path, storage path, or virtual URL.
         * When "dispositions" are given they are used as Content-Disposition if supported.
         *
-        * @param $triples Array List of (file system path, virtual URL/storage path, disposition)
+        * @param $triples Array List of (source path, destination path, disposition)
         * @return FileRepoStatus
         */
        public function quickImportBatch( array $triples ) {
@@ -893,9 +894,10 @@ class FileRepo {
                $operations = array();
                foreach ( $triples as $triple ) {
                        list( $src, $dst ) = $triple;
+                       $src = $this->resolveToStoragePath( $src );
                        $dst = $this->resolveToStoragePath( $dst );
                        $operations[] = array(
-                               'op'          => 'store',
+                               'op'          => FileBackend::isStoragePath( $src ) ? 'copy' : 'store',
                                'src'         => $src,
                                'dst'         => $dst,
                                'disposition' => isset( $triple[2] ) ? $triple[2] : null
@@ -1014,12 +1016,12 @@ class FileRepo {
 
        /**
         * Copy or move a file either from a storage path, virtual URL,
-        * or FS path, into this repository at the specified destination location.
+        * or file system path, into this repository at the specified destination location.
         *
         * Returns a FileRepoStatus object. On success, the value contains "new" or
         * "archived", to indicate whether the file was new with that name.
         *
-        * @param $srcPath String: the source FS path, storage path, or URL
+        * @param $srcPath String: the source file system path, storage path, or URL
         * @param $dstRel String: the destination relative path
         * @param $archiveRel String: the relative path where the existing file is to
         *        be archived, if there is one. Relative to the public zone root.
index 54a68af..0542bba 100644 (file)
@@ -61,35 +61,35 @@ class UploadFromChunks extends UploadFromFile {
                return true;
        }
        /**
-        * Calls the parent stashFile and updates the uploadsession table to handle "chunks" 
+        * Calls the parent stashFile and updates the uploadsession table to handle "chunks"
         *
         * @return UploadStashFile stashed file
         */
        public function stashFile() {
-               // Stash file is the called on creating a new chunk session: 
+               // Stash file is the called on creating a new chunk session:
                $this->mChunkIndex = 0;
                $this->mOffset = 0;
                // Create a local stash target
                $this->mLocalFile = parent::stashFile();
-               // Update the initial file offset ( based on file size ) 
+               // Update the initial file offset ( based on file size )
                $this->mOffset = $this->mLocalFile->getSize();
                $this->mFileKey = $this->mLocalFile->getFileKey();
 
                // Output a copy of this first to chunk 0 location:
                $status = $this->outputChunk( $this->mLocalFile->getPath() );
 
-               // Update db table to reflect initial "chunk" state 
+               // Update db table to reflect initial "chunk" state
                $this->updateChunkStatus();
                return $this->mLocalFile;
        }
 
        /**
         * Continue chunk uploading
-        */     
+        */
        public function continueChunks( $name, $key, $webRequestUpload ) {
                $this->mFileKey = $key;
                $this->mUpload = $webRequestUpload;
-               // Get the chunk status form the db: 
+               // Get the chunk status form the db:
                $this->getChunkStatus();
 
                $metadata = $this->stash->getMetadata( $key );
@@ -105,7 +105,7 @@ class UploadFromChunks extends UploadFromFile {
         * @return FileRepoStatus
         */
        public function concatenateChunks() {
-               wfDebug( __METHOD__ . " concatenate {$this->mChunkIndex} chunks:" . 
+               wfDebug( __METHOD__ . " concatenate {$this->mChunkIndex} chunks:" .
                        $this->getOffset() . ' inx:' . $this->getChunkIndex() . "\n" );
 
                // Concatenate all the chunks to mVirtualTempPath
@@ -125,10 +125,10 @@ class UploadFromChunks extends UploadFromFile {
                // Concatenate the chunks at the temp file
                $status = $this->repo->concatenate( $fileList, $tmpPath, FileRepo::DELETE_SOURCE );
                if( !$status->isOk() ){
-                       return $status; 
+                       return $status;
                }
                // Update the mTempPath and mLocalFile
-               // ( for FileUpload or normal Stash to take over )  
+               // ( for FileUpload or normal Stash to take over )
                $this->mTempPath = $tmpPath; // file system path
                $this->mLocalFile = parent::stashFile();
 
@@ -149,16 +149,16 @@ class UploadFromChunks extends UploadFromFile {
        }
 
        /**
-        * Returns the virtual chunk location:  
+        * Returns the virtual chunk location:
         * @param $index
         * @return string
         */
        function getVirtualChunkLocation( $index ){
-               return $this->repo->getVirtualUrl( 'temp' ) . 
+               return $this->repo->getVirtualUrl( 'temp' ) .
                                '/' .
-                               $this->repo->getHashPath( 
+                               $this->repo->getHashPath(
                                        $this->getChunkFileKey( $index )
-                               ) . 
+                               ) .
                                $this->getChunkFileKey( $index );
        }
 
@@ -173,20 +173,20 @@ class UploadFromChunks extends UploadFromFile {
        public function addChunk( $chunkPath, $chunkSize, $offset ) {
                // Get the offset before we add the chunk to the file system
                $preAppendOffset = $this->getOffset();
-               
+
                if ( $preAppendOffset + $chunkSize > $this->getMaxUploadSize()) {
                        $status = Status::newFatal( 'file-too-large' );
                } else {
                        // Make sure the client is uploading the correct chunk with a matching offset.
                        if ( $preAppendOffset == $offset ) {
-                               // Update local chunk index for the current chunk   
+                               // Update local chunk index for the current chunk
                                $this->mChunkIndex++;
                                $status = $this->outputChunk( $chunkPath );
                                if( $status->isGood() ){
-                                       // Update local offset: 
+                                       // Update local offset:
                                        $this->mOffset = $preAppendOffset + $chunkSize;
-                                       // Update chunk table status db         
-                                       $this->updateChunkStatus();             
+                                       // Update chunk table status db
+                                       $this->updateChunkStatus();
                                }
                        } else {
                                $status = Status::newFatal( 'invalid-chunk-offset' );
@@ -196,16 +196,16 @@ class UploadFromChunks extends UploadFromFile {
        }
 
        /**
-        * Update the chunk db table with the current status: 
+        * Update the chunk db table with the current status:
         */
        private function updateChunkStatus(){
-               wfDebug( __METHOD__ . " update chunk status for {$this->mFileKey} offset:" . 
+               wfDebug( __METHOD__ . " update chunk status for {$this->mFileKey} offset:" .
                                        $this->getOffset() . ' inx:' . $this->getChunkIndex() . "\n" );
 
                $dbw = $this->repo->getMasterDb();
                $dbw->update(
                        'uploadstash',
-                       array( 
+                       array(
                                'us_status' => 'chunks',
                                'us_chunk_inx' => $this->getChunkIndex(),
                                'us_size' => $this->getOffset()
@@ -219,12 +219,12 @@ class UploadFromChunks extends UploadFromFile {
         * Get the chunk db state and populate update relevant local values
         */
        private function getChunkStatus(){
-               // get Master db to avoid race conditions. 
+               // get Master db to avoid race conditions.
                // Otherwise, if chunk upload time < replag there will be spurious errors
                $dbw = $this->repo->getMasterDb();
                $row = $dbw->selectRow(
-                       'uploadstash', 
-                       array( 
+                       'uploadstash',
+                       array(
                                'us_chunk_inx',
                                'us_size',
                                'us_path',
@@ -241,7 +241,7 @@ class UploadFromChunks extends UploadFromFile {
        }
 
        /**
-        * Get the current Chunk index 
+        * Get the current Chunk index
         * @return Integer index of the current chunk
         */
        private function getChunkIndex(){
@@ -252,8 +252,8 @@ class UploadFromChunks extends UploadFromFile {
        }
 
        /**
-        * Gets the current offset in fromt the stashedupload table 
-        * @return Integer current byte offset of the chunk file set 
+        * Gets the current offset in fromt the stashedupload table
+        * @return Integer current byte offset of the chunk file set
         */
        private function getOffset(){
                if ( $this->mOffset !== null ){
@@ -272,11 +272,12 @@ class UploadFromChunks extends UploadFromFile {
        private function outputChunk( $chunkPath ){
                // Key is fileKey + chunk index
                $fileKey = $this->getChunkFileKey();
-               
-               // Store the chunk per its indexed fileKey: 
+
+               // Store the chunk per its indexed fileKey:
                $hashPath = $this->repo->getHashPath( $fileKey );
-               $storeStatus = $this->repo->store( $chunkPath, 'temp', "$hashPath$fileKey" );
-               
+               $storeStatus = $this->repo->quickImport( $chunkPath,
+                       $this->repo->getZonePath( 'temp' ) . "/{$hashPath}{$fileKey}" );
+
                // Check for error in stashing the chunk:
                if ( ! $storeStatus->isOK() ) {
                        $error = $storeStatus->getErrorsArray();