MediaWiki
REL1_22
|
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 ) !== '' && $cachedValue !== ' PURGED' ) { 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->add( $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->add( $memcKey, $targetTitle->getDBkey(), $expiry ); 00194 return $targetTitle; 00195 } else { 00196 $wgMemc->add( $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 00291 public function findFilesByPrefix( $prefix, $limit ) { 00292 $selectOptions = array( 'ORDER BY' => 'img_name', 'LIMIT' => intval( $limit ) ); 00293 00294 // Query database 00295 $dbr = $this->getSlaveDB(); 00296 $res = $dbr->select( 00297 'image', 00298 LocalFile::selectFields(), 00299 'img_name ' . $dbr->buildLike( $prefix, $dbr->anyString() ), 00300 __METHOD__, 00301 $selectOptions 00302 ); 00303 00304 // Build file objects 00305 $files = array(); 00306 foreach ( $res as $row ) { 00307 $files[] = $this->newFileFromRow( $row ); 00308 } 00309 return $files; 00310 } 00311 00316 function getSlaveDB() { 00317 return wfGetDB( DB_SLAVE ); 00318 } 00319 00324 function getMasterDB() { 00325 return wfGetDB( DB_MASTER ); 00326 } 00327 00335 function getSharedCacheKey( /*...*/ ) { 00336 $args = func_get_args(); 00337 return call_user_func_array( 'wfMemcKey', $args ); 00338 } 00339 00346 function invalidateImageRedirect( Title $title ) { 00347 global $wgMemc; 00348 $memcKey = $this->getSharedCacheKey( 'image_redirect', md5( $title->getDBkey() ) ); 00349 if ( $memcKey ) { 00350 // Set a temporary value for the cache key, to ensure 00351 // that this value stays purged long enough so that 00352 // it isn't refreshed with a stale value due to a 00353 // lagged slave. 00354 $wgMemc->set( $memcKey, ' PURGED', 12 ); 00355 } 00356 } 00357 }