MediaWiki
REL1_19
|
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