Main Page | Namespace List | Class Hierarchy | Class List | File List | Class Members | File Members | Related Pages

LinkCache.php

Go to the documentation of this file.
00001 <?php 00002 # Cache for article titles (prefixed DB keys) and ids linked from one source 00003 00004 # These are used in incrementalSetup() 00005 define ('LINKCACHE_GOOD', 0); 00006 define ('LINKCACHE_BAD', 1); 00007 define ('LINKCACHE_IMAGE', 2); 00008 00009 class LinkCache { 00010 // Increment $mClassVer whenever old serialized versions of this class 00011 // becomes incompatible with the new version. 00012 /* private */ var $mClassVer = 2; 00013 00014 /* private */ var $mGoodLinks, $mBadLinks, $mActive; 00015 /* private */ var $mImageLinks, $mCategoryLinks; 00016 /* private */ var $mPreFilled, $mOldGoodLinks, $mOldBadLinks; 00017 00018 /* private */ function getKey( $title ) { 00019 global $wgDBname; 00020 return "$wgDBname:lc:title:$title"; 00021 } 00022 00023 function LinkCache() 00024 { 00025 $this->mActive = true; 00026 $this->mPreFilled = false; 00027 $this->mGoodLinks = array(); 00028 $this->mBadLinks = array(); 00029 $this->mImageLinks = array(); 00030 $this->mCategoryLinks = array(); 00031 $this->mOldGoodLinks = array(); 00032 $this->mOldBadLinks = array(); 00033 } 00034 00035 function getGoodLinkID( $title ) 00036 { 00037 if ( array_key_exists( $title, $this->mGoodLinks ) ) { 00038 return $this->mGoodLinks[$title]; 00039 } else { 00040 return 0; 00041 } 00042 } 00043 00044 function isBadLink( $title ) 00045 { 00046 return array_key_exists( $title, $this->mBadLinks ); 00047 } 00048 00049 function addGoodLink( $id, $title ) 00050 { 00051 if ( $this->mActive ) { 00052 $this->mGoodLinks[$title] = $id; 00053 } 00054 } 00055 00056 function addBadLink( $title ) 00057 { 00058 if ( $this->mActive && ( ! $this->isBadLink( $title ) ) ) { 00059 $this->mBadLinks[$title] = 1; 00060 } 00061 } 00062 00063 function addImageLink( $title ) 00064 { 00065 if ( $this->mActive ) { $this->mImageLinks[$title] = 1; } 00066 } 00067 00068 function addImageLinkObj( $nt ) 00069 { 00070 if ( $this->mActive ) { $this->mImageLinks[$nt->getDBkey()] = 1; } 00071 } 00072 00073 function addCategoryLink( $title, $sortkey ) { 00074 if ( $this->mActive ) { $this->mCategoryLinks[$title] = $sortkey; } 00075 } 00076 00077 function addCategoryLinkObj( &$nt, $sortkey ) { 00078 $this->addCategoryLink( $nt->getDBkey(), $sortkey ); 00079 } 00080 00081 function clearBadLink( $title ) 00082 { 00083 unset( $this->mBadLinks[$title] ); 00084 $this->clearLink( $title ); 00085 } 00086 00087 function clearLink( $title ) 00088 { 00089 global $wgMemc, $wgLinkCacheMemcached; 00090 if( $wgLinkCacheMemcached ) 00091 $wgMemc->delete( $this->getKey( $title ) ); 00092 } 00093 00094 function suspend() { $this->mActive = false; } 00095 function resume() { $this->mActive = true; } 00096 function getGoodLinks() { return $this->mGoodLinks; } 00097 function getBadLinks() { return array_keys( $this->mBadLinks ); } 00098 function getImageLinks() { return $this->mImageLinks; } 00099 function getCategoryLinks() { return $this->mCategoryLinks; } 00100 00101 function addLink( $title ) 00102 { 00103 $nt = Title::newFromDBkey( $title ); 00104 if( $nt ) { 00105 return $this->addLinkObj( $nt ); 00106 } else { 00107 return 0; 00108 } 00109 } 00110 00111 function addLinkObj( &$nt ) 00112 { 00113 global $wgMemc, $wgLinkCacheMemcached; 00114 $title = $nt->getPrefixedDBkey(); 00115 if ( $this->isBadLink( $title ) ) { return 0; } 00116 $id = $this->getGoodLinkID( $title ); 00117 if ( 0 != $id ) { return $id; } 00118 00119 $fname = "LinkCache::addLinkObj"; 00120 wfProfileIn( $fname ); 00121 00122 $ns = $nt->getNamespace(); 00123 $t = $nt->getDBkey(); 00124 00125 if ( "" == $title ) { 00126 wfProfileOut( $fname ); 00127 return 0; 00128 } 00129 00130 $id = NULL; 00131 if( $wgLinkCacheMemcached ) 00132 $id = $wgMemc->get( $key = $this->getKey( $title ) ); 00133 if( ! is_integer( $id ) ) { 00134 $sql = "SELECT cur_id FROM cur WHERE cur_namespace=" . 00135 "{$ns} AND cur_title='" . wfStrencode( $t ) . "'"; 00136 $res = wfQuery( $sql, DB_READ, "LinkCache::addLink" ); 00137 00138 if ( 0 == wfNumRows( $res ) ) { 00139 $id = 0; 00140 } else { 00141 $s = wfFetchObject( $res ); 00142 $id = $s->cur_id; 00143 } 00144 if( $wgLinkCacheMemcached ) 00145 $wgMemc->add( $key, $id, 3600*24 ); 00146 } 00147 00148 if ( 0 == $id ) { $this->addBadLink( $title ); } 00149 else { $this->addGoodLink( $id, $title ); } 00150 wfProfileOut( $fname ); 00151 return $id; 00152 } 00153 00154 function preFill( &$fromtitle ) 00155 { 00156 global $wgEnablePersistentLC; 00157 00158 $fname = "LinkCache::preFill"; 00159 wfProfileIn( $fname ); 00160 # Note -- $fromtitle is a Title *object* 00161 00162 $this->suspend(); 00163 $id = $fromtitle->getArticleID(); 00164 $this->resume(); 00165 00166 if( $id == 0 ) { 00167 wfDebug( "$fname - got id 0 for title '" . $fromtitle->getPrefixedDBkey() . "'\n" ); 00168 wfProfileOut( $fname ); 00169 return; 00170 } 00171 00172 if ( $wgEnablePersistentLC ) { 00173 if( $this->fillFromLinkscc( $id ) ){ 00174 wfProfileOut( $fname ); 00175 return; 00176 } 00177 } 00178 00179 $sql = "SELECT cur_id,cur_namespace,cur_title 00180 FROM cur,links 00181 WHERE cur_id=l_to AND l_from=$id"; 00182 $res = wfQuery( $sql, DB_READ, $fname ); 00183 while( $s = wfFetchObject( $res ) ) { 00184 $this->addGoodLink( $s->cur_id, 00185 Title::makeName( $s->cur_namespace, $s->cur_title ) 00186 ); 00187 } 00188 00189 $sql = "SELECT bl_to 00190 FROM brokenlinks 00191 WHERE bl_from='{$id}'"; 00192 $res = wfQuery( $sql, DB_READ, "LinkCache::preFill" ); 00193 while( $s = wfFetchObject( $res ) ) { 00194 $this->addBadLink( $s->bl_to ); 00195 } 00196 00197 $this->mOldBadLinks = $this->mBadLinks; 00198 $this->mOldGoodLinks = $this->mGoodLinks; 00199 $this->mPreFilled = true; 00200 00201 if ( $wgEnablePersistentLC ) { 00202 $this->saveToLinkscc( $id ); 00203 } 00204 wfProfileOut( $fname ); 00205 } 00206 00207 function getGoodAdditions() 00208 { 00209 return array_diff( $this->mGoodLinks, $this->mOldGoodLinks ); 00210 } 00211 00212 function getBadAdditions() 00213 { 00214 #wfDebug( "mOldBadLinks: " . implode( ', ', array_keys( $this->mOldBadLinks ) ) . "\n" ); 00215 #wfDebug( "mBadLinks: " . implode( ', ', array_keys( $this->mBadLinks ) ) . "\n" ); 00216 return array_values( array_diff( array_keys( $this->mBadLinks ), array_keys( $this->mOldBadLinks ) ) ); 00217 } 00218 00219 function getImageAdditions() 00220 { 00221 return array_diff_assoc( $this->mImageLinks, $this->mOldImageLinks ); 00222 } 00223 00224 function getGoodDeletions() 00225 { 00226 return array_diff( $this->mOldGoodLinks, $this->mGoodLinks ); 00227 } 00228 00229 function getBadDeletions() 00230 { 00231 return array_values( array_diff( array_keys( $this->mOldBadLinks ), array_keys( $this->mBadLinks ) )); 00232 } 00233 00234 function getImageDeletions() 00235 { 00236 return array_diff_assoc( $this->mOldImageLinks, $this->mImageLinks ); 00237 } 00238 00239 # Parameters: $which is one of the LINKCACHE_xxx constants, $del and $add are 00240 # the incremental update arrays which will be filled. Returns whether or not it's 00241 # worth doing the incremental version. For example, if [[List of mathematical topics]] 00242 # was blanked, it would take a long, long time to do incrementally. 00243 function incrementalSetup( $which, &$del, &$add ) 00244 { 00245 if ( ! $this->mPreFilled ) { 00246 return false; 00247 } 00248 00249 switch ( $which ) { 00250 case LINKCACHE_GOOD: 00251 $old =& $this->mOldGoodLinks; 00252 $cur =& $this->mGoodLinks; 00253 $del = $this->getGoodDeletions(); 00254 $add = $this->getGoodAdditions(); 00255 break; 00256 case LINKCACHE_BAD: 00257 $old =& $this->mOldBadLinks; 00258 $cur =& $this->mBadLinks; 00259 $del = $this->getBadDeletions(); 00260 $add = $this->getBadAdditions(); 00261 break; 00262 default: # LINKCACHE_IMAGE 00263 return false; 00264 } 00265 00266 return true; 00267 } 00268 00269 # Clears cache but leaves old preFill copies alone 00270 function clear() 00271 { 00272 $this->mGoodLinks = array(); 00273 $this->mBadLinks = array(); 00274 $this->mImageLinks = array(); 00275 } 00276 00277 /* private */ function fillFromLinkscc( $id ){ 00278 $id = IntVal( $id ); 00279 $res = wfQuery("SELECT lcc_cacheobj FROM linkscc WHERE lcc_pageid = $id", 00280 DB_READ); 00281 $row = wfFetchObject( $res ); 00282 if( $row == FALSE) 00283 return false; 00284 00285 $cacheobj = false; 00286 if( function_exists( "gzuncompress" ) ) 00287 $cacheobj = @gzuncompress( $row->lcc_cacheobj ); 00288 00289 if($cacheobj == FALSE){ 00290 $cacheobj = $row->lcc_cacheobj; 00291 } 00292 $cc = @unserialize( $cacheobj ); 00293 if( isset( $cc->mClassVer ) and ($cc->mClassVer == $this->mClassVer ) ){ 00294 $this->mOldGoodLinks = $this->mGoodLinks = $cc->mGoodLinks; 00295 $this->mOldBadLinks = $this->mBadLinks = $cc->mBadLinks; 00296 $this->mPreFilled = true; 00297 return TRUE; 00298 } else { 00299 return FALSE; 00300 } 00301 00302 } 00303 00304 /* private */ function saveToLinkscc( $pid ){ 00305 global $wgCompressedPersistentLC, $wgIsMySQL; 00306 if( $wgCompressedPersistentLC and function_exists( "gzcompress" ) ) { 00307 $ser = wfStrencode( gzcompress( serialize( $this ), 3 )); 00308 } else { 00309 $ser = wfStrencode( serialize( $this ) ); 00310 } 00311 if ($wgIsMySQL) { 00312 wfQuery("REPLACE INTO linkscc(lcc_pageid,lcc_cacheobj) " . 00313 "VALUES({$pid}, '{$ser}')", DB_WRITE); 00314 } else { 00315 wfQuery("DELETE FROM linkscc WHERE lcc_pageid={$pid}",DB_WRITE); 00316 wfQuery("INSERT INTO linkscc(lcc_pageid,lcc_cacheobj) " . 00317 "VALUES({$pid}, '{$ser}')", DB_WRITE); 00318 } 00319 } 00320 00321 # $pid is a page id 00322 /* static */ function linksccClearLinksTo( $pid ){ 00323 global $wgEnablePersistentLC, $wgIsMySQL; 00324 if ( $wgEnablePersistentLC ) { 00325 $pid = intval( $pid ); 00326 if ($wgIsMySQL) { 00327 wfQuery("DELETE linkscc FROM linkscc,links ". 00328 "WHERE lcc_pageid=links.l_from AND l_to={$pid}", DB_WRITE); 00329 } else { 00330 wfQuery("DELETE FROM linkscc WHERE lcc_pageid IN ". 00331 "(SELECT l_from FROM links WHERE l_to={$pid})", DB_WRITE); 00332 } 00333 wfQuery("DELETE FROM linkscc WHERE lcc_pageid='{$pid}'", DB_WRITE); 00334 } 00335 } 00336 00337 # $title is a prefixed db title, for example like Title->getPrefixedDBkey() returns. 00338 /* static */ function linksccClearBrokenLinksTo( $title ){ 00339 global $wgEnablePersistentLC,$wgIsMySQL; 00340 if ( $wgEnablePersistentLC ) { 00341 $title = wfStrencode( $title ); 00342 if ($wgIsMySQL) { 00343 wfQuery("DELETE linkscc FROM linkscc,brokenlinks ". 00344 "WHERE lcc_pageid=bl_from AND bl_to='{$title}'", DB_WRITE); 00345 } else { 00346 wfQuery("DELETE FROM linkscc WHERE lcc_pageid IN ". 00347 "(SELECT bl_from FROM brokenlinks ". 00348 "WHERE bl_to='{$title}')",DB_WRITE); 00349 } 00350 } 00351 } 00352 00353 # $pid is a page id 00354 /* static */ function linksccClearPage( $pid ){ 00355 global $wgEnablePersistentLC; 00356 if ( $wgEnablePersistentLC ) { 00357 $pid = intval( $pid ); 00358 wfQuery("DELETE FROM linkscc WHERE lcc_pageid='{$pid}'", DB_WRITE); 00359 } 00360 } 00361 } 00362 ?>

Generated on Tue Jun 29 23:40:05 2004 for Mediawiki by doxygen 1.3.7