* Added a script to reduce disk space on a MySQL parser cache setup such as the one...
authorTim Starling <tstarling@users.mediawiki.org>
Fri, 9 Sep 2011 03:51:45 +0000 (03:51 +0000)
committerTim Starling <tstarling@users.mediawiki.org>
Fri, 9 Sep 2011 03:51:45 +0000 (03:51 +0000)
* Fixed unintentional shortcut evaluation in MultiWriteBagOStuff::doWrite(). It would have caused writes to be skipped on the second cache if the first cache failed, now writes should be attempted on all caches.

includes/objectcache/BagOStuff.php
includes/objectcache/MultiWriteBagOStuff.php
includes/objectcache/SqlBagOStuff.php
maintenance/purgeParserCache.php [new file with mode: 0644]

index 634eff3..97b6cb2 100644 (file)
@@ -91,6 +91,16 @@ abstract class BagOStuff {
                return array();
        }
 
+       /**
+        * Delete all objects expiring before a certain date. 
+        *
+        * @return true on success, false if unimplemented
+        */
+       public function deleteObjectsExpiringBefore( $date ) {
+               // stub
+               return false;
+       }
+
        /* *** Emulated functions *** */
 
        public function add( $key, $value, $exptime = 0 ) {
index 4ed1188..2b88b42 100644 (file)
@@ -89,9 +89,25 @@ class MultiWriteBagOStuff extends BagOStuff {
                array_shift( $args );
 
                foreach ( $this->caches as $cache ) {
-                       $ret = $ret && call_user_func_array( array( $cache, $method ), $args );
+                       if ( !call_user_func_array( array( $cache, $method ), $args ) ) {
+                               $ret = false;
+                       }
                }
                return $ret;
        }
 
+       /**
+        * Delete objects expiring before a certain date. 
+        *
+        * Succeed if any of the child caches succeed.
+        */
+       public function deleteObjectsExpiringBefore( $date ) {
+               $ret = false;
+               foreach ( $this->caches as $cache ) {
+                       if ( $cache->deleteObjectsExpiringBefore( $date ) ) {
+                               $ret = true;
+                       }
+               }
+               return $ret;
+       }
 }
index 7eb125a..78817d0 100644 (file)
@@ -305,21 +305,29 @@ class SqlBagOStuff extends BagOStuff {
        }
 
        public function expireAll() {
+               $this->deleteObjectsExpiringBefore( wfTimestampNow() );
+       }
+
+       /**
+        * Delete objects from the database which expire before a certain date.
+        */
+       public function deleteObjectsExpiringBefore( $timestamp ) {
                $db = $this->getDB();
-               $now = $db->timestamp();
+               $dbTimestamp = $db->timestamp( $timestamp );
 
                try {
                        for ( $i = 0; $i < $this->shards; $i++ ) {
                                $db->begin();
                                $db->delete(
                                        $this->getTableByShard( $i ), 
-                                       array( 'exptime < ' . $db->addQuotes( $now ) ), 
+                                       array( 'exptime < ' . $db->addQuotes( $dbTimestamp ) ), 
                                        __METHOD__ );
                                $db->commit();
                        }
                } catch ( DBQueryError $e ) {
                        $this->handleWriteError( $e );
                }
+               return true;
        }
 
        public function deleteAll() {
diff --git a/maintenance/purgeParserCache.php b/maintenance/purgeParserCache.php
new file mode 100644 (file)
index 0000000..4b550b6
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+
+require( dirname( __FILE__ ) . '/Maintenance.php' );
+
+class PurgeParserCache extends Maintenance {
+       function __construct() {
+               parent::__construct();
+               $this->addDescription( "Remove old objects from the parser cache. " . 
+                       "This only works when the parser cache is in an SQL database." );
+               $this->addOption( 'expiredate', 'Delete objects expiring before this date.', false, true );
+               $this->addOption( 'age', 
+                       'Delete objects created more than this many seconds ago, assuming $wgParserCacheExpireTime '.
+                               'has been consistent.', 
+                       false, true );
+       }
+
+       function execute() {
+               $inputDate = $this->getOption( 'expiredate' );
+               $inputAge = $this->getOption( 'age' );
+               if ( $inputDate !== null ) {
+                       $date = wfTimestamp( TS_MW, strtotime( $inputDate ) );
+               } elseif ( $inputAge !== null ) {
+                       global $wgParserCacheExpireTime;
+                       $date = wfTimestamp( TS_MW, time() + $wgParserCacheExpireTime - intval( $inputAge ) );
+               } else {
+                       echo "Must specify either --expiredate or --age\n";
+                       exit( 1 );
+               }
+
+               $english = Language::factory( 'en' );
+               echo "Deleting objects expiring before " . $english->timeanddate( $date ) . "\n";
+
+               $pc = wfGetParserCacheStorage();
+               $success = $pc->deleteObjectsExpiringBefore( $date );
+               if ( !$success ) {
+                       echo "Cannot purge this kind of parser cache.\n";
+                       exit( 1 );
+               }
+               echo "Done\n";
+       }
+}
+$maintClass = 'PurgeParserCache';
+require_once( RUN_MAINTENANCE_IF_MAIN );