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 }