X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;ds=sidebyside;f=includes%2Ffilerepo%2Ffile%2FLocalFile.php;h=f1f8af43732f2a0d191106762389601c59876543;hb=2721bc43dfc1ea6a3af678c63bdd3a06b2795cc2;hp=07f1f09e389009e8c9e70f8813df4673c77de66b;hpb=ec9002258c8a0264cb2d92df6a216e9fa11d3462;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/filerepo/file/LocalFile.php b/includes/filerepo/file/LocalFile.php index 07f1f09e38..f1f8af4373 100644 --- a/includes/filerepo/file/LocalFile.php +++ b/includes/filerepo/file/LocalFile.php @@ -913,7 +913,7 @@ class LocalFile extends File { $files = $this->getThumbnails( $archiveName ); // Purge any custom thumbnail caches - wfRunHooks( 'LocalFilePurgeThumbnails', array( $this, $archiveName ) ); + Hooks::run( 'LocalFilePurgeThumbnails', array( $this, $archiveName ) ); $dir = array_shift( $files ); $this->purgeThumbList( $dir, $files ); @@ -958,7 +958,7 @@ class LocalFile extends File { } // Purge any custom thumbnail caches - wfRunHooks( 'LocalFilePurgeThumbnails', array( $this, false ) ); + Hooks::run( 'LocalFilePurgeThumbnails', array( $this, false ) ); $dir = array_shift( $files ); $this->purgeThumbList( $dir, $files ); @@ -1035,7 +1035,7 @@ class LocalFile extends File { $opts['ORDER BY'] = "oi_timestamp $order"; $opts['USE INDEX'] = array( 'oldimage' => 'oi_name_timestamp' ); - wfRunHooks( 'LocalFile::getHistory', array( &$this, &$tables, &$fields, + Hooks::run( 'LocalFile::getHistory', array( &$this, &$tables, &$fields, &$conds, &$opts, &$join_conds ) ); $res = $dbr->select( $tables, $fields, $conds, __METHOD__, $opts, $join_conds ); @@ -1303,9 +1303,11 @@ class LocalFile extends File { ); if ( $dbw->affectedRows() == 0 ) { if ( $allowTimeKludge ) { - # Use FOR UPDATE to ignore any transaction snapshotting + # Use LOCK IN SHARE MODE to ignore any transaction snapshotting $ltimestamp = $dbw->selectField( 'image', 'img_timestamp', - array( 'img_name' => $this->getName() ), __METHOD__, array( 'FOR UPDATE' ) ); + array( 'img_name' => $this->getName() ), + __METHOD__, + array( 'LOCK IN SHARE MODE' ) ); $lUnixtime = $ltimestamp ? wfTimestamp( TS_UNIX, $ltimestamp ) : false; # Avoid a timestamp that is not newer than the last version # TODO: the image/oldimage tables should be like page/revision with an ID field @@ -1421,7 +1423,7 @@ class LocalFile extends File { if ( !is_null( $nullRevision ) ) { $nullRevision->insertOn( $dbw ); - wfRunHooks( 'NewRevisionFromEditComplete', array( $wikiPage, $nullRevision, $latest, $user ) ); + Hooks::run( 'NewRevisionFromEditComplete', array( $wikiPage, $nullRevision, $latest, $user ) ); $wikiPage->updateRevisionOn( $dbw, $nullRevision ); } } @@ -1482,7 +1484,7 @@ class LocalFile extends File { # Hooks, hooks, the magic of hooks... wfProfileIn( __METHOD__ . '-hooks' ); - wfRunHooks( 'FileUpload', array( $this, $reupload, $descTitle->exists() ) ); + Hooks::run( 'FileUpload', array( $this, $reupload, $descTitle->exists() ) ); wfProfileOut( __METHOD__ . '-hooks' ); # Invalidate cache for all pages using this file @@ -1850,7 +1852,7 @@ class LocalFile extends File { * Start a transaction and lock the image for update * Increments a reference counter if the lock is already held * @throws MWException Throws an error if the lock was not acquired - * @return bool Success + * @return bool Whether the file lock owns/spawned the DB transaction */ function lock() { $dbw = $this->repo->getMasterDB(); @@ -1877,7 +1879,7 @@ class LocalFile extends File { $this->markVolatile(); // file may change soon - return true; + return $this->lockedOwnTrx; } /** @@ -2284,7 +2286,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 ); @@ -2316,7 +2323,7 @@ class LocalFileDeleteBatch { /** * Removes non-existent files from a deletion batch. * @param array $batch - * @return array + * @return Status */ function removeNonexistentFiles( $batch ) { $files = $newBatch = array(); @@ -2327,6 +2334,10 @@ class LocalFileDeleteBatch { } $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]] ) { @@ -2334,7 +2345,7 @@ class LocalFileDeleteBatch { } } - return $newBatch; + return Status::newGood( $newBatch ); } } @@ -2410,13 +2421,19 @@ class LocalFileRestoreBatch { return $this->file->repo->newGood(); } - $this->file->lock(); + $lockOwnsTrx = $this->file->lock(); $dbw = $this->file->repo->getMasterDB(); $status = $this->file->repo->newGood(); $exists = (bool)$dbw->selectField( 'image', '1', - array( 'img_name' => $this->file->getName() ), __METHOD__, array( 'FOR UPDATE' ) ); + array( 'img_name' => $this->file->getName() ), + __METHOD__, + // The lock() should already prevents changes, but this still may need + // to bypass any transaction snapshot. However, if lock() started the + // trx (which it probably did) then snapshot is post-lock and up-to-date. + $lockOwnsTrx ? array() : array( 'LOCK IN SHARE MODE' ) + ); // Fetch all or selected archived revisions for the file, // sorted from the most recent to the oldest. @@ -2575,7 +2592,12 @@ class LocalFileRestoreBatch { } // 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 @@ -2635,7 +2657,7 @@ class LocalFileRestoreBatch { /** * Removes non-existent files from a store batch. * @param array $triplets - * @return array + * @return Status */ function removeNonexistentFiles( $triplets ) { $files = $filteredTriplets = array(); @@ -2644,6 +2666,10 @@ class LocalFileRestoreBatch { } $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]] ) { @@ -2651,7 +2677,7 @@ class LocalFileRestoreBatch { } } - return $filteredTriplets; + return Status::newGood( $filteredTriplets ); } /** @@ -2779,7 +2805,7 @@ class LocalFileMoveBatch { array( 'oi_archive_name', 'oi_deleted' ), array( 'oi_name' => $this->oldName ), __METHOD__, - array( 'FOR UPDATE' ) // ignore snapshot + array( 'LOCK IN SHARE MODE' ) // ignore snapshot ); foreach ( $result as $row ) { @@ -2824,7 +2850,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 @@ -2951,7 +2982,7 @@ class LocalFileMoveBatch { /** * Removes non-existent files from move batch. * @param array $triplets - * @return array + * @return Status */ function removeNonexistentFiles( $triplets ) { $files = array(); @@ -2961,8 +2992,12 @@ class LocalFileMoveBatch { } $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; @@ -2971,7 +3006,7 @@ class LocalFileMoveBatch { } } - return $filteredTriplets; + return Status::newGood( $filteredTriplets ); } /**