Made LocalFile::loadExtraFromDB() handle re-upload race conditions
authorAaron Schulz <aschulz@wikimedia.org>
Tue, 22 Apr 2014 16:38:51 +0000 (09:38 -0700)
committerAaron Schulz <aschulz@wikimedia.org>
Thu, 24 Apr 2014 22:05:12 +0000 (15:05 -0700)
Change-Id: I99a39c3d2b5d7a227be9b11a2f23c534ea4739d9

includes/filerepo/file/LocalFile.php

index f89dc3d..3d6f24e 100644 (file)
@@ -417,19 +417,13 @@ class LocalFile extends File {
                # Unconditionally set loaded=true, we don't want the accessors constantly rechecking
                $this->extraDataLoaded = true;
 
-               $dbr = $this->repo->getSlaveDB();
-               // In theory the file could have just been renamed/deleted...oh well
-               $row = $dbr->selectRow( 'image', $this->getLazyCacheFields( 'img_' ),
-                       array( 'img_name' => $this->getName() ), $fname );
-
-               if ( !$row ) { // fallback to master
-                       $dbr = $this->repo->getMasterDB();
-                       $row = $dbr->selectRow( 'image', $this->getLazyCacheFields( 'img_' ),
-                               array( 'img_name' => $this->getName() ), $fname );
+               $fieldMap = $this->loadFieldsWithTimestamp( $this->repo->getSlaveDB(), $fname );
+               if ( !$fieldMap ) {
+                       $fieldMap = $this->loadFieldsWithTimestamp( $this->repo->getMasterDB(), $fname );
                }
 
-               if ( $row ) {
-                       foreach ( $this->unprefixRow( $row, 'img_' ) as $name => $value ) {
+               if ( $fieldMap ) {
+                       foreach ( $fieldMap as $name => $value ) {
                                $this->$name = $value;
                        }
                } else {
@@ -440,6 +434,32 @@ class LocalFile extends File {
                wfProfileOut( $fname );
        }
 
+       /**
+        * @param DatabaseBase $dbr
+        * @param string $fname
+        * @return array|false
+        */
+       private function loadFieldsWithTimestamp( $dbr, $fname ) {
+               $fieldMap = false;
+
+               $row = $dbr->selectRow( 'image', $this->getLazyCacheFields( 'img_' ),
+                       array( 'img_name' => $this->getName(), 'img_timestamp' => $this->getTimestamp() ),
+                       $fname );
+               if ( $row ) {
+                       $fieldMap = $this->unprefixRow( $row, 'img_' );
+               } else {
+                       # File may have been uploaded over in the meantime; check the old versions
+                       $row = $dbr->selectRow( 'oldimage', $this->getLazyCacheFields( 'oi_' ),
+                               array( 'oi_name' => $this->getName(), 'oi_timestamp' => $this->getTimestamp() ),
+                               $fname );
+                       if ( $row ) {
+                               $fieldMap = $this->unprefixRow( $row, 'oi_' );
+                       }
+               }
+
+               return $fieldMap;
+       }
+
        /**
         * @param array $row Row
         * @param string $prefix
@@ -1911,10 +1931,14 @@ class LocalFile extends File {
 
                $key = $this->repo->getSharedCacheKey( 'file-volatile', md5( $this->getName() ) );
                if ( $key ) {
-                       if ( $this->lastMarkedVolatile && ( time() - $this->lastMarkedVolatile ) <= self::VOLATILE_TTL ) {
+                       if ( $this->lastMarkedVolatile
+                               && ( time() - $this->lastMarkedVolatile ) <= self::VOLATILE_TTL
+                       ) {
                                return true; // sanity
                        }
-                       return ( $wgMemc->get( $key ) !== false );
+                       $volatileTimestamp = (int)$wgMemc->get( $key );
+                       $this->lastMarkedVolatile = max( $this->lastMarkedVolatile, $volatileTimestamp );
+                       return ( $volatileTimestamp != 0 );
                }
 
                return false;