00001 <?php 00008 class DependencyWrapper { 00009 var $value; 00010 var $deps; 00011 00018 function __construct( $value = false, $deps = array() ) { 00019 $this->value = $value; 00020 if ( !is_array( $deps ) ) { 00021 $deps = array( $deps ); 00022 } 00023 $this->deps = $deps; 00024 } 00025 00029 function isExpired() { 00030 foreach ( $this->deps as $dep ) { 00031 if ( $dep->isExpired() ) { 00032 return true; 00033 } 00034 } 00035 return false; 00036 } 00037 00042 function initialiseDeps() { 00043 foreach ( $this->deps as $dep ) { 00044 $dep->loadDependencyValues(); 00045 } 00046 } 00047 00051 function getValue() { 00052 return $this->value; 00053 } 00054 00058 function storeToCache( $cache, $key, $expiry = 0 ) { 00059 $this->initialiseDeps(); 00060 $cache->set( $key, $this, $expiry ); 00061 } 00062 00080 static function getValueFromCache( $cache, $key, $expiry = 0, $callback = false, 00081 $callbackParams = array(), $deps = array() ) 00082 { 00083 $obj = $cache->get( $key ); 00084 if ( is_object( $obj ) && $obj instanceof DependencyWrapper && !$obj->isExpired() ) { 00085 $value = $obj->value; 00086 } elseif ( $callback ) { 00087 $value = call_user_func_array( $callback, $callbackParams ); 00088 # Cache the newly-generated value 00089 $wrapper = new DependencyWrapper( $value, $deps ); 00090 $wrapper->storeToCache( $cache, $key, $expiry ); 00091 } else { 00092 $value = null; 00093 } 00094 return $value; 00095 } 00096 } 00097 00101 abstract class CacheDependency { 00105 abstract function isExpired(); 00106 00110 function loadDependencyValues() { } 00111 } 00112 00116 class FileDependency extends CacheDependency { 00117 var $filename, $timestamp; 00118 00131 function __construct( $filename, $timestamp = null ) { 00132 $this->filename = $filename; 00133 $this->timestamp = $timestamp; 00134 } 00135 00136 function __sleep() { 00137 $this->loadDependencyValues(); 00138 return array( 'filename', 'timestamp' ); 00139 } 00140 00141 function loadDependencyValues() { 00142 if ( is_null( $this->timestamp ) ) { 00143 if ( !file_exists( $this->filename ) ) { 00144 # Dependency on a non-existent file 00145 # This is a valid concept! 00146 $this->timestamp = false; 00147 } else { 00148 $this->timestamp = filemtime( $this->filename ); 00149 } 00150 } 00151 } 00152 00153 function isExpired() { 00154 if ( !file_exists( $this->filename ) ) { 00155 if ( $this->timestamp === false ) { 00156 # Still nonexistent 00157 return false; 00158 } else { 00159 # Deleted 00160 wfDebug( "Dependency triggered: {$this->filename} deleted.\n" ); 00161 return true; 00162 } 00163 } else { 00164 $lastmod = filemtime( $this->filename ); 00165 if ( $lastmod > $this->timestamp ) { 00166 # Modified or created 00167 wfDebug( "Dependency triggered: {$this->filename} changed.\n" ); 00168 return true; 00169 } else { 00170 # Not modified 00171 return false; 00172 } 00173 } 00174 } 00175 } 00176 00180 class TitleDependency extends CacheDependency { 00181 var $titleObj; 00182 var $ns, $dbk; 00183 var $touched; 00184 00189 function __construct( Title $title ) { 00190 $this->titleObj = $title; 00191 $this->ns = $title->getNamespace(); 00192 $this->dbk = $title->getDBkey(); 00193 } 00194 00195 function loadDependencyValues() { 00196 $this->touched = $this->getTitle()->getTouched(); 00197 } 00198 00202 function __sleep() { 00203 return array( 'ns', 'dbk', 'touched' ); 00204 } 00205 00206 function getTitle() { 00207 if ( !isset( $this->titleObj ) ) { 00208 $this->titleObj = Title::makeTitle( $this->ns, $this->dbk ); 00209 } 00210 return $this->titleObj; 00211 } 00212 00213 function isExpired() { 00214 $touched = $this->getTitle()->getTouched(); 00215 00216 if ( $this->touched === false ) { 00217 if ( $touched === false ) { 00218 # Still missing 00219 return false; 00220 } else { 00221 # Created 00222 return true; 00223 } 00224 } elseif ( $touched === false ) { 00225 # Deleted 00226 return true; 00227 } elseif ( $touched > $this->touched ) { 00228 # Updated 00229 return true; 00230 } else { 00231 # Unmodified 00232 return false; 00233 } 00234 } 00235 } 00236 00240 class TitleListDependency extends CacheDependency { 00241 var $linkBatch; 00242 var $timestamps; 00243 00247 function __construct( LinkBatch $linkBatch ) { 00248 $this->linkBatch = $linkBatch; 00249 } 00250 00251 function calculateTimestamps() { 00252 # Initialise values to false 00253 $timestamps = array(); 00254 00255 foreach ( $this->getLinkBatch()->data as $ns => $dbks ) { 00256 if ( count( $dbks ) > 0 ) { 00257 $timestamps[$ns] = array(); 00258 foreach ( $dbks as $dbk => $value ) { 00259 $timestamps[$ns][$dbk] = false; 00260 } 00261 } 00262 } 00263 00264 # Do the query 00265 if ( count( $timestamps ) ) { 00266 $dbr = wfGetDB( DB_SLAVE ); 00267 $where = $this->getLinkBatch()->constructSet( 'page', $dbr ); 00268 $res = $dbr->select( 00269 'page', 00270 array( 'page_namespace', 'page_title', 'page_touched' ), 00271 $where, 00272 __METHOD__ 00273 ); 00274 00275 while ( $row = $dbr->fetchObject( $res ) ) { 00276 $timestamps[$row->page_namespace][$row->page_title] = $row->page_touched; 00277 } 00278 } 00279 return $timestamps; 00280 } 00281 00282 function loadDependencyValues() { 00283 $this->timestamps = $this->calculateTimestamps(); 00284 } 00285 00286 function __sleep() { 00287 return array( 'timestamps' ); 00288 } 00289 00290 function getLinkBatch() { 00291 if ( !isset( $this->linkBatch ) ) { 00292 $this->linkBatch = new LinkBatch; 00293 $this->linkBatch->setArray( $this->timestamps ); 00294 } 00295 return $this->linkBatch; 00296 } 00297 00298 function isExpired() { 00299 $newTimestamps = $this->calculateTimestamps(); 00300 foreach ( $this->timestamps as $ns => $dbks ) { 00301 foreach ( $dbks as $dbk => $oldTimestamp ) { 00302 $newTimestamp = $newTimestamps[$ns][$dbk]; 00303 00304 if ( $oldTimestamp === false ) { 00305 if ( $newTimestamp === false ) { 00306 # Still missing 00307 } else { 00308 # Created 00309 return true; 00310 } 00311 } elseif ( $newTimestamp === false ) { 00312 # Deleted 00313 return true; 00314 } elseif ( $newTimestamp > $oldTimestamp ) { 00315 # Updated 00316 return true; 00317 } else { 00318 # Unmodified 00319 } 00320 } 00321 } 00322 return false; 00323 } 00324 } 00325 00329 class GlobalDependency extends CacheDependency { 00330 var $name, $value; 00331 00332 function __construct( $name ) { 00333 $this->name = $name; 00334 $this->value = $GLOBALS[$name]; 00335 } 00336 00337 function isExpired() { 00338 return $GLOBALS[$this->name] != $this->value; 00339 } 00340 } 00341 00345 class ConstantDependency extends CacheDependency { 00346 var $name, $value; 00347 00348 function __construct( $name ) { 00349 $this->name = $name; 00350 $this->value = constant( $name ); 00351 } 00352 00353 function isExpired() { 00354 return constant( $this->name ) != $this->value; 00355 } 00356 }