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