MediaWiki  REL1_20
LocalRepo.php
Go to the documentation of this file.
00001 <?php
00031 class LocalRepo extends FileRepo {
00032         var $fileFactory           = array( 'LocalFile'   , 'newFromTitle' );
00033         var $fileFactoryKey        = array( 'LocalFile'   , 'newFromKey'   );
00034         var $fileFromRowFactory    = array( 'LocalFile'   , 'newFromRow'   );
00035         var $oldFileFactory        = array( 'OldLocalFile', 'newFromTitle' );
00036         var $oldFileFactoryKey     = array( 'OldLocalFile', 'newFromKey'   );
00037         var $oldFileFromRowFactory = array( 'OldLocalFile', 'newFromRow'   );
00038 
00044         function newFileFromRow( $row ) {
00045                 if ( isset( $row->img_name ) ) {
00046                         return call_user_func( $this->fileFromRowFactory, $row, $this );
00047                 } elseif ( isset( $row->oi_name ) ) {
00048                         return call_user_func( $this->oldFileFromRowFactory, $row, $this );
00049                 } else {
00050                         throw new MWException( __METHOD__.': invalid row' );
00051                 }
00052         }
00053 
00059         function newFromArchiveName( $title, $archiveName ) {
00060                 return OldLocalFile::newFromArchiveName( $title, $this, $archiveName );
00061         }
00062 
00073         function cleanupDeletedBatch( array $storageKeys ) {
00074                 $backend = $this->backend; // convenience
00075                 $root = $this->getZonePath( 'deleted' );
00076                 $dbw = $this->getMasterDB();
00077                 $status = $this->newGood();
00078                 $storageKeys = array_unique( $storageKeys );
00079                 foreach ( $storageKeys as $key ) {
00080                         $hashPath = $this->getDeletedHashPath( $key );
00081                         $path = "$root/$hashPath$key";
00082                         $dbw->begin( __METHOD__ );
00083                         // Check for usage in deleted/hidden files and pre-emptively
00084                         // lock the key to avoid any future use until we are finished.
00085                         $deleted = $this->deletedFileHasKey( $key, 'lock' );
00086                         $hidden = $this->hiddenFileHasKey( $key, 'lock' );
00087                         if ( !$deleted && !$hidden ) { // not in use now
00088                                 wfDebug( __METHOD__ . ": deleting $key\n" );
00089                                 $op = array( 'op' => 'delete', 'src' => $path );
00090                                 if ( !$backend->doOperation( $op )->isOK() ) {
00091                                         $status->error( 'undelete-cleanup-error', $path );
00092                                         $status->failCount++;
00093                                 }
00094                         } else {
00095                                 wfDebug( __METHOD__ . ": $key still in use\n" );
00096                                 $status->successCount++;
00097                         }
00098                         $dbw->commit( __METHOD__ );
00099                 }
00100                 return $status;
00101         }
00102 
00110         protected function deletedFileHasKey( $key, $lock = null ) {
00111                 $options = ( $lock === 'lock' ) ? array( 'FOR UPDATE' ) : array();
00112 
00113                 $dbw = $this->getMasterDB();
00114                 return (bool)$dbw->selectField( 'filearchive', '1',
00115                         array( 'fa_storage_group' => 'deleted', 'fa_storage_key' => $key ),
00116                         __METHOD__, $options
00117                 );
00118         }
00119 
00127         protected function hiddenFileHasKey( $key, $lock = null ) {
00128                 $options = ( $lock === 'lock' ) ? array( 'FOR UPDATE' ) : array();
00129 
00130                 $sha1 = self::getHashFromKey( $key );
00131                 $ext = File::normalizeExtension( substr( $key, strcspn( $key, '.' ) + 1 ) );
00132 
00133                 $dbw = $this->getMasterDB();
00134                 return (bool)$dbw->selectField( 'oldimage', '1',
00135                         array( 'oi_sha1' => $sha1,
00136                                 'oi_archive_name ' . $dbw->buildLike( $dbw->anyString(), ".$ext" ),
00137                                 $dbw->bitAnd( 'oi_deleted', File::DELETED_FILE ) => File::DELETED_FILE ),
00138                         __METHOD__, $options
00139                 );
00140         }
00141 
00148         public static function getHashFromKey( $key ) {
00149                 return strtok( $key, '.' );
00150         }
00151 
00158         function checkRedirect( Title $title ) {
00159                 global $wgMemc;
00160 
00161                 $title = File::normalizeTitle( $title, 'exception' );
00162 
00163                 $memcKey = $this->getSharedCacheKey( 'image_redirect', md5( $title->getDBkey() ) );
00164                 if ( $memcKey === false ) {
00165                         $memcKey = $this->getLocalCacheKey( 'image_redirect', md5( $title->getDBkey() ) );
00166                         $expiry = 300; // no invalidation, 5 minutes
00167                 } else {
00168                         $expiry = 86400; // has invalidation, 1 day
00169                 }
00170                 $cachedValue = $wgMemc->get( $memcKey );
00171                 if ( $cachedValue === ' '  || $cachedValue === '' ) {
00172                         // Does not exist
00173                         return false;
00174                 } elseif ( strval( $cachedValue ) !== '' ) {
00175                         return Title::newFromText( $cachedValue, NS_FILE );
00176                 } // else $cachedValue is false or null: cache miss
00177 
00178                 $id = $this->getArticleID( $title );
00179                 if( !$id ) {
00180                         $wgMemc->set( $memcKey, " ", $expiry );
00181                         return false;
00182                 }
00183                 $dbr = $this->getSlaveDB();
00184                 $row = $dbr->selectRow(
00185                         'redirect',
00186                         array( 'rd_title', 'rd_namespace' ),
00187                         array( 'rd_from' => $id ),
00188                         __METHOD__
00189                 );
00190 
00191                 if( $row && $row->rd_namespace == NS_FILE ) {
00192                         $targetTitle = Title::makeTitle( $row->rd_namespace, $row->rd_title );
00193                         $wgMemc->set( $memcKey, $targetTitle->getDBkey(), $expiry );
00194                         return $targetTitle;
00195                 } else {
00196                         $wgMemc->set( $memcKey, '', $expiry );
00197                         return false;
00198                 }
00199         }
00200 
00208         protected function getArticleID( $title ) {
00209                 if( !$title instanceof Title ) {
00210                         return 0;
00211                 }
00212                 $dbr = $this->getSlaveDB();
00213                 $id = $dbr->selectField(
00214                         'page', // Table
00215                         'page_id',  //Field
00216                         array(  //Conditions
00217                                 'page_namespace' => $title->getNamespace(),
00218                                 'page_title' => $title->getDBkey(),
00219                         ),
00220                         __METHOD__  //Function name
00221                 );
00222                 return $id;
00223         }
00224 
00232         function findBySha1( $hash ) {
00233                 $dbr = $this->getSlaveDB();
00234                 $res = $dbr->select(
00235                         'image',
00236                         LocalFile::selectFields(),
00237                         array( 'img_sha1' => $hash ),
00238                         __METHOD__,
00239                         array( 'ORDER BY' => 'img_name' )
00240                 );
00241                 
00242                 $result = array();
00243                 foreach ( $res as $row ) {
00244                         $result[] = $this->newFileFromRow( $row );
00245                 }
00246                 $res->free();
00247 
00248                 return $result;
00249         }
00250 
00260         function findBySha1s( array $hashes ) {
00261                 if( !count( $hashes ) ) {
00262                         return array(); //empty parameter
00263                 }
00264 
00265                 $dbr = $this->getSlaveDB();
00266                 $res = $dbr->select(
00267                         'image',
00268                         LocalFile::selectFields(),
00269                         array( 'img_sha1' => $hashes ),
00270                         __METHOD__,
00271                         array( 'ORDER BY' => 'img_name' )
00272                 );
00273 
00274                 $result = array();
00275                 foreach ( $res as $row ) {
00276                         $file = $this->newFileFromRow( $row );
00277                         $result[$file->getSha1()][] = $file;
00278                 }
00279                 $res->free();
00280 
00281                 return $result;
00282         }
00283 
00288         function getSlaveDB() {
00289                 return wfGetDB( DB_SLAVE );
00290         }
00291 
00296         function getMasterDB() {
00297                 return wfGetDB( DB_MASTER );
00298         }
00299 
00307         function getSharedCacheKey( /*...*/ ) {
00308                 $args = func_get_args();
00309                 return call_user_func_array( 'wfMemcKey', $args );
00310         }
00311 
00318         function invalidateImageRedirect( Title $title ) {
00319                 global $wgMemc;
00320                 $memcKey = $this->getSharedCacheKey( 'image_redirect', md5( $title->getDBkey() ) );
00321                 if ( $memcKey ) {
00322                         $wgMemc->delete( $memcKey );
00323                 }
00324         }
00325 }
00326