MediaWiki  REL1_19
LocalRepo.php
Go to the documentation of this file.
00001 <?php
00016 class LocalRepo extends FileRepo {
00017         var $fileFactory           = array( 'LocalFile'   , 'newFromTitle' );
00018         var $fileFactoryKey        = array( 'LocalFile'   , 'newFromKey'   );
00019         var $fileFromRowFactory    = array( 'LocalFile'   , 'newFromRow'   );
00020         var $oldFileFactory        = array( 'OldLocalFile', 'newFromTitle' );
00021         var $oldFileFactoryKey     = array( 'OldLocalFile', 'newFromKey'   );
00022         var $oldFileFromRowFactory = array( 'OldLocalFile', 'newFromRow'   );
00023 
00029         function newFileFromRow( $row ) {
00030                 if ( isset( $row->img_name ) ) {
00031                         return call_user_func( $this->fileFromRowFactory, $row, $this );
00032                 } elseif ( isset( $row->oi_name ) ) {
00033                         return call_user_func( $this->oldFileFromRowFactory, $row, $this );
00034                 } else {
00035                         throw new MWException( __METHOD__.': invalid row' );
00036                 }
00037         }
00038 
00044         function newFromArchiveName( $title, $archiveName ) {
00045                 return OldLocalFile::newFromArchiveName( $title, $this, $archiveName );
00046         }
00047 
00058         function cleanupDeletedBatch( $storageKeys ) {
00059                 $backend = $this->backend; // convenience
00060                 $root = $this->getZonePath( 'deleted' );
00061                 $dbw = $this->getMasterDB();
00062                 $status = $this->newGood();
00063                 $storageKeys = array_unique( $storageKeys );
00064                 foreach ( $storageKeys as $key ) {
00065                         $hashPath = $this->getDeletedHashPath( $key );
00066                         $path = "$root/$hashPath$key";
00067                         $dbw->begin();
00068                         // Check for usage in deleted/hidden files and pre-emptively
00069                         // lock the key to avoid any future use until we are finished.
00070                         $deleted = $this->deletedFileHasKey( $key, 'lock' );
00071                         $hidden = $this->hiddenFileHasKey( $key, 'lock' );
00072                         if ( !$deleted && !$hidden ) { // not in use now
00073                                 wfDebug( __METHOD__ . ": deleting $key\n" );
00074                                 $op = array( 'op' => 'delete', 'src' => $path );
00075                                 if ( !$backend->doOperation( $op )->isOK() ) {
00076                                         $status->error( 'undelete-cleanup-error', $path );
00077                                         $status->failCount++;
00078                                 }
00079                         } else {
00080                                 wfDebug( __METHOD__ . ": $key still in use\n" );
00081                                 $status->successCount++;
00082                         }
00083                         $dbw->commit();
00084                 }
00085                 return $status;
00086         }
00087 
00095         protected function deletedFileHasKey( $key, $lock = null ) {
00096                 $options = ( $lock === 'lock' ) ? array( 'FOR UPDATE' ) : array();
00097 
00098                 $dbw = $this->getMasterDB();
00099                 return (bool)$dbw->selectField( 'filearchive', '1',
00100                         array( 'fa_storage_group' => 'deleted', 'fa_storage_key' => $key ),
00101                         __METHOD__, $options
00102                 );
00103         }
00104 
00112         protected function hiddenFileHasKey( $key, $lock = null ) {
00113                 $options = ( $lock === 'lock' ) ? array( 'FOR UPDATE' ) : array();
00114 
00115                 $sha1 = self::getHashFromKey( $key );
00116                 $ext = File::normalizeExtension( substr( $key, strcspn( $key, '.' ) + 1 ) );
00117 
00118                 $dbw = $this->getMasterDB();
00119                 return (bool)$dbw->selectField( 'oldimage', '1',
00120                         array( 'oi_sha1' => $sha1,
00121                                 'oi_archive_name ' . $dbw->buildLike( $dbw->anyString(), ".$ext" ),
00122                                 $dbw->bitAnd( 'oi_deleted', File::DELETED_FILE ) => File::DELETED_FILE ),
00123                         __METHOD__, $options
00124                 );
00125         }
00126 
00133         public static function getHashFromKey( $key ) {
00134                 return strtok( $key, '.' );
00135         }
00136         
00143         function checkRedirect( Title $title ) {
00144                 global $wgMemc;
00145 
00146                 $title = File::normalizeTitle( $title, 'exception' );
00147 
00148                 $memcKey = $this->getSharedCacheKey( 'image_redirect', md5( $title->getDBkey() ) );
00149                 if ( $memcKey === false ) {
00150                         $memcKey = $this->getLocalCacheKey( 'image_redirect', md5( $title->getDBkey() ) );
00151                         $expiry = 300; // no invalidation, 5 minutes
00152                 } else {
00153                         $expiry = 86400; // has invalidation, 1 day
00154                 }
00155                 $cachedValue = $wgMemc->get( $memcKey );
00156                 if ( $cachedValue === ' '  || $cachedValue === '' ) {
00157                         // Does not exist
00158                         return false;
00159                 } elseif ( strval( $cachedValue ) !== '' ) {
00160                         return Title::newFromText( $cachedValue, NS_FILE );
00161                 } // else $cachedValue is false or null: cache miss
00162 
00163                 $id = $this->getArticleID( $title );
00164                 if( !$id ) {
00165                         $wgMemc->set( $memcKey, " ", $expiry );
00166                         return false;
00167                 }
00168                 $dbr = $this->getSlaveDB();
00169                 $row = $dbr->selectRow(
00170                         'redirect',
00171                         array( 'rd_title', 'rd_namespace' ),
00172                         array( 'rd_from' => $id ),
00173                         __METHOD__
00174                 );
00175 
00176                 if( $row && $row->rd_namespace == NS_FILE ) {
00177                         $targetTitle = Title::makeTitle( $row->rd_namespace, $row->rd_title );
00178                         $wgMemc->set( $memcKey, $targetTitle->getDBkey(), $expiry );
00179                         return $targetTitle;
00180                 } else {
00181                         $wgMemc->set( $memcKey, '', $expiry );
00182                         return false;
00183                 }
00184         }
00185 
00186 
00193         protected function getArticleID( $title ) {
00194                 if( !$title instanceof Title ) {
00195                         return 0;
00196                 }
00197                 $dbr = $this->getSlaveDB();
00198                 $id = $dbr->selectField(
00199                         'page', // Table
00200                         'page_id',  //Field
00201                         array(  //Conditions
00202                                 'page_namespace' => $title->getNamespace(),
00203                                 'page_title' => $title->getDBkey(),
00204                         ),
00205                         __METHOD__  //Function name
00206                 );
00207                 return $id;
00208         }
00209 
00217         function findBySha1( $hash ) {
00218                 $dbr = $this->getSlaveDB();
00219                 $res = $dbr->select(
00220                         'image',
00221                         LocalFile::selectFields(),
00222                         array( 'img_sha1' => $hash )
00223                 );
00224                 
00225                 $result = array();
00226                 foreach ( $res as $row ) {
00227                         $result[] = $this->newFileFromRow( $row );
00228                 }
00229                 $res->free();
00230 
00231                 return $result;
00232         }
00233 
00237         function getSlaveDB() {
00238                 return wfGetDB( DB_SLAVE );
00239         }
00240 
00244         function getMasterDB() {
00245                 return wfGetDB( DB_MASTER );
00246         }
00247 
00255         function getSharedCacheKey( /*...*/ ) {
00256                 $args = func_get_args();
00257                 return call_user_func_array( 'wfMemcKey', $args );
00258         }
00259 
00266         function invalidateImageRedirect( Title $title ) {
00267                 global $wgMemc;
00268                 $memcKey = $this->getSharedCacheKey( 'image_redirect', md5( $title->getDBkey() ) );
00269                 if ( $memcKey ) {
00270                         $wgMemc->delete( $memcKey );
00271                 }
00272         }
00273 }
00274