MediaWiki  REL1_22
CacheDependency.php
Go to the documentation of this file.
00001 <?php
00030 class DependencyWrapper {
00031     var $value;
00032     var $deps;
00033 
00040     function __construct( $value = false, $deps = array() ) {
00041         $this->value = $value;
00042 
00043         if ( !is_array( $deps ) ) {
00044             $deps = array( $deps );
00045         }
00046 
00047         $this->deps = $deps;
00048     }
00049 
00055     function isExpired() {
00056         foreach ( $this->deps as $dep ) {
00057             if ( $dep->isExpired() ) {
00058                 return true;
00059             }
00060         }
00061 
00062         return false;
00063     }
00064 
00069     function initialiseDeps() {
00070         foreach ( $this->deps as $dep ) {
00071             $dep->loadDependencyValues();
00072         }
00073     }
00074 
00079     function getValue() {
00080         return $this->value;
00081     }
00082 
00090     function storeToCache( $cache, $key, $expiry = 0 ) {
00091         $this->initialiseDeps();
00092         $cache->set( $key, $this, $expiry );
00093     }
00094 
00112     static function getValueFromCache( $cache, $key, $expiry = 0, $callback = false,
00113         $callbackParams = array(), $deps = array() )
00114     {
00115         $obj = $cache->get( $key );
00116 
00117         if ( is_object( $obj ) && $obj instanceof DependencyWrapper && !$obj->isExpired() ) {
00118             $value = $obj->value;
00119         } elseif ( $callback ) {
00120             $value = call_user_func_array( $callback, $callbackParams );
00121             # Cache the newly-generated value
00122             $wrapper = new DependencyWrapper( $value, $deps );
00123             $wrapper->storeToCache( $cache, $key, $expiry );
00124         } else {
00125             $value = null;
00126         }
00127 
00128         return $value;
00129     }
00130 }
00131 
00135 abstract class CacheDependency {
00139     abstract function isExpired();
00140 
00144     function loadDependencyValues() { }
00145 }
00146 
00150 class FileDependency extends CacheDependency {
00151     var $filename, $timestamp;
00152 
00165     function __construct( $filename, $timestamp = null ) {
00166         $this->filename = $filename;
00167         $this->timestamp = $timestamp;
00168     }
00169 
00173     function __sleep() {
00174         $this->loadDependencyValues();
00175         return array( 'filename', 'timestamp' );
00176     }
00177 
00178     function loadDependencyValues() {
00179         if ( is_null( $this->timestamp ) ) {
00180             if ( !file_exists( $this->filename ) ) {
00181                 # Dependency on a non-existent file
00182                 # This is a valid concept!
00183                 $this->timestamp = false;
00184             } else {
00185                 $this->timestamp = filemtime( $this->filename );
00186             }
00187         }
00188     }
00189 
00193     function isExpired() {
00194         if ( !file_exists( $this->filename ) ) {
00195             if ( $this->timestamp === false ) {
00196                 # Still nonexistent
00197                 return false;
00198             } else {
00199                 # Deleted
00200                 wfDebug( "Dependency triggered: {$this->filename} deleted.\n" );
00201                 return true;
00202             }
00203         } else {
00204             $lastmod = filemtime( $this->filename );
00205             if ( $lastmod > $this->timestamp ) {
00206                 # Modified or created
00207                 wfDebug( "Dependency triggered: {$this->filename} changed.\n" );
00208                 return true;
00209             } else {
00210                 # Not modified
00211                 return false;
00212             }
00213         }
00214     }
00215 }
00216 
00220 class TitleDependency extends CacheDependency {
00221     var $titleObj;
00222     var $ns, $dbk;
00223     var $touched;
00224 
00229     function __construct( Title $title ) {
00230         $this->titleObj = $title;
00231         $this->ns = $title->getNamespace();
00232         $this->dbk = $title->getDBkey();
00233     }
00234 
00235     function loadDependencyValues() {
00236         $this->touched = $this->getTitle()->getTouched();
00237     }
00238 
00244     function __sleep() {
00245         return array( 'ns', 'dbk', 'touched' );
00246     }
00247 
00251     function getTitle() {
00252         if ( !isset( $this->titleObj ) ) {
00253             $this->titleObj = Title::makeTitle( $this->ns, $this->dbk );
00254         }
00255 
00256         return $this->titleObj;
00257     }
00258 
00262     function isExpired() {
00263         $touched = $this->getTitle()->getTouched();
00264 
00265         if ( $this->touched === false ) {
00266             if ( $touched === false ) {
00267                 # Still missing
00268                 return false;
00269             } else {
00270                 # Created
00271                 return true;
00272             }
00273         } elseif ( $touched === false ) {
00274             # Deleted
00275             return true;
00276         } elseif ( $touched > $this->touched ) {
00277             # Updated
00278             return true;
00279         } else {
00280             # Unmodified
00281             return false;
00282         }
00283     }
00284 }
00285 
00289 class TitleListDependency extends CacheDependency {
00290     var $linkBatch;
00291     var $timestamps;
00292 
00297     function __construct( LinkBatch $linkBatch ) {
00298         $this->linkBatch = $linkBatch;
00299     }
00300 
00304     function calculateTimestamps() {
00305         # Initialise values to false
00306         $timestamps = array();
00307 
00308         foreach ( $this->getLinkBatch()->data as $ns => $dbks ) {
00309             if ( count( $dbks ) > 0 ) {
00310                 $timestamps[$ns] = array();
00311 
00312                 foreach ( $dbks as $dbk => $value ) {
00313                     $timestamps[$ns][$dbk] = false;
00314                 }
00315             }
00316         }
00317 
00318         # Do the query
00319         if ( count( $timestamps ) ) {
00320             $dbr = wfGetDB( DB_SLAVE );
00321             $where = $this->getLinkBatch()->constructSet( 'page', $dbr );
00322             $res = $dbr->select(
00323                 'page',
00324                 array( 'page_namespace', 'page_title', 'page_touched' ),
00325                 $where,
00326                 __METHOD__
00327             );
00328 
00329             foreach ( $res as $row ) {
00330                 $timestamps[$row->page_namespace][$row->page_title] = $row->page_touched;
00331             }
00332         }
00333 
00334         return $timestamps;
00335     }
00336 
00337     function loadDependencyValues() {
00338         $this->timestamps = $this->calculateTimestamps();
00339     }
00340 
00344     function __sleep() {
00345         return array( 'timestamps' );
00346     }
00347 
00351     function getLinkBatch() {
00352         if ( !isset( $this->linkBatch ) ) {
00353             $this->linkBatch = new LinkBatch;
00354             $this->linkBatch->setArray( $this->timestamps );
00355         }
00356         return $this->linkBatch;
00357     }
00358 
00362     function isExpired() {
00363         $newTimestamps = $this->calculateTimestamps();
00364 
00365         foreach ( $this->timestamps as $ns => $dbks ) {
00366             foreach ( $dbks as $dbk => $oldTimestamp ) {
00367                 $newTimestamp = $newTimestamps[$ns][$dbk];
00368 
00369                 if ( $oldTimestamp === false ) {
00370                     if ( $newTimestamp === false ) {
00371                         # Still missing
00372                     } else {
00373                         # Created
00374                         return true;
00375                     }
00376                 } elseif ( $newTimestamp === false ) {
00377                     # Deleted
00378                     return true;
00379                 } elseif ( $newTimestamp > $oldTimestamp ) {
00380                     # Updated
00381                     return true;
00382                 } else {
00383                     # Unmodified
00384                 }
00385             }
00386         }
00387 
00388         return false;
00389     }
00390 }
00391 
00395 class GlobalDependency extends CacheDependency {
00396     var $name, $value;
00397 
00398     function __construct( $name ) {
00399         $this->name = $name;
00400         $this->value = $GLOBALS[$name];
00401     }
00402 
00406     function isExpired() {
00407         if ( !isset( $GLOBALS[$this->name] ) ) {
00408             return true;
00409         }
00410         return $GLOBALS[$this->name] != $this->value;
00411     }
00412 }
00413 
00417 class ConstantDependency extends CacheDependency {
00418     var $name, $value;
00419 
00420     function __construct( $name ) {
00421         $this->name = $name;
00422         $this->value = constant( $name );
00423     }
00424 
00428     function isExpired() {
00429         return constant( $this->name ) != $this->value;
00430     }
00431 }