purgeParserCache.php improvements:
authorTim Starling <tstarling@users.mediawiki.org>
Fri, 2 Dec 2011 02:59:11 +0000 (02:59 +0000)
committerTim Starling <tstarling@users.mediawiki.org>
Fri, 2 Dec 2011 02:59:11 +0000 (02:59 +0000)
* Do queries in batches of 100 rows instead of all at once. Note that if there are a lot of objects with the exact same expiry time, it might take multiple runs of the script to delete them all.
* Progress meter.

includes/objectcache/BagOStuff.php
includes/objectcache/MultiWriteBagOStuff.php
includes/objectcache/SqlBagOStuff.php
maintenance/purgeParserCache.php

index 5d635ed..81ad662 100644 (file)
@@ -93,10 +93,14 @@ abstract class BagOStuff {
 
        /**
         * Delete all objects expiring before a certain date.
+        * @param $date The reference date in MW format
+        * @param $progressCallback Optional, a function which will be called 
+        *     regularly during long-running operations with the percentage progress
+        *     as the first parameter.
         *
         * @return true on success, false if unimplemented
         */
-       public function deleteObjectsExpiringBefore( $date ) {
+       public function deleteObjectsExpiringBefore( $date, $progressCallback = false ) {
                // stub
                return false;
        }
index 2b88b42..0d95a84 100644 (file)
@@ -101,10 +101,10 @@ class MultiWriteBagOStuff extends BagOStuff {
         *
         * Succeed if any of the child caches succeed.
         */
-       public function deleteObjectsExpiringBefore( $date ) {
+       public function deleteObjectsExpiringBefore( $date, $progressCallback = false ) {
                $ret = false;
                foreach ( $this->caches as $cache ) {
-                       if ( $cache->deleteObjectsExpiringBefore( $date ) ) {
+                       if ( $cache->deleteObjectsExpiringBefore( $date, $progressCallback ) ) {
                                $ret = true;
                        }
                }
index 77374c7..2c43d1b 100644 (file)
@@ -311,18 +311,67 @@ class SqlBagOStuff extends BagOStuff {
        /**
         * Delete objects from the database which expire before a certain date.
         */
-       public function deleteObjectsExpiringBefore( $timestamp ) {
+       public function deleteObjectsExpiringBefore( $timestamp, $progressCallback = false ) {
                $db = $this->getDB();
                $dbTimestamp = $db->timestamp( $timestamp );
+               $totalSeconds = false;
+               $baseConds = array( 'exptime < ' . $db->addQuotes( $dbTimestamp ) );
 
                try {
                        for ( $i = 0; $i < $this->shards; $i++ ) {
-                               $db->begin();
-                               $db->delete(
-                                       $this->getTableByShard( $i ),
-                                       array( 'exptime < ' . $db->addQuotes( $dbTimestamp ) ),
-                                       __METHOD__ );
-                               $db->commit();
+                               $maxExpTime = false;
+                               while ( true ) {
+                                       $conds = $baseConds;
+                                       if ( $maxExpTime !== false ) {
+                                               $conds[] = 'exptime > ' . $db->addQuotes( $maxExpTime );
+                                       }
+                                       $rows = $db->select( 
+                                               $this->getTableByShard( $i ),
+                                               array( 'keyname', 'exptime' ),
+                                               $conds,
+                                               __METHOD__,
+                                               array( 'LIMIT' => 100, 'ORDER BY' => 'exptime' ) );
+                                       if ( !$rows->numRows() ) {
+                                               break;
+                                       }
+                                       $keys = array();
+                                       $row = $rows->current();
+                                       $minExpTime = $row->exptime;
+                                       if ( $totalSeconds === false ) {
+                                               $totalSeconds = wfTimestamp( TS_UNIX, $timestamp )
+                                                       - wfTimestamp( TS_UNIX, $minExpTime );
+                                       }
+                                       foreach ( $rows as $row ) {
+                                               $keys[] = $row->keyname;
+                                               $maxExpTime = $row->exptime;
+                                       }
+
+                                       $db->begin();
+                                       $db->delete(
+                                               $this->getTableByShard( $i ),
+                                               array( 
+                                                       'exptime >= ' . $db->addQuotes( $minExpTime ),
+                                                       'exptime < ' . $db->addQuotes( $dbTimestamp ),
+                                                       'keyname' => $keys
+                                               ),
+                                               __METHOD__ );
+                                       $db->commit();
+
+                                       if ( $progressCallback ) {
+                                               if ( intval( $totalSeconds ) === 0 ) {
+                                                       $percent = 0;
+                                               } else {
+                                                       $remainingSeconds = wfTimestamp( TS_UNIX, $timestamp ) 
+                                                               - wfTimestamp( TS_UNIX, $maxExpTime );
+                                                       if ( $remainingSeconds > $totalSeconds ) {
+                                                               $totalSeconds = $remainingSeconds;
+                                                       }
+                                                       $percent = ( $i + $remainingSeconds / $totalSeconds ) 
+                                                               / $this->shards * 100;
+                                               }
+                                               call_user_func( $progressCallback, $percent );
+                                       }
+                               }
                        }
                } catch ( DBQueryError $e ) {
                        $this->handleWriteError( $e );
index 4b550b6..7a8f6f7 100644 (file)
@@ -3,6 +3,8 @@
 require( dirname( __FILE__ ) . '/Maintenance.php' );
 
 class PurgeParserCache extends Maintenance {
+       var $lastProgress;
+
        function __construct() {
                parent::__construct();
                $this->addDescription( "Remove old objects from the parser cache. " . 
@@ -31,12 +33,26 @@ class PurgeParserCache extends Maintenance {
                echo "Deleting objects expiring before " . $english->timeanddate( $date ) . "\n";
 
                $pc = wfGetParserCacheStorage();
-               $success = $pc->deleteObjectsExpiringBefore( $date );
+               $success = $pc->deleteObjectsExpiringBefore( $date, array( $this, 'showProgress' ) );
                if ( !$success ) {
-                       echo "Cannot purge this kind of parser cache.\n";
+                       echo "\nCannot purge this kind of parser cache.\n";
                        exit( 1 );
                }
-               echo "Done\n";
+               $this->showProgress( 100 );
+               echo "\nDone\n";
+       }
+
+       function showProgress( $percent ) {
+               $percentString = sprintf( "%.2f", $percent );
+               if ( $percentString === $this->lastProgress ) {
+                       return;
+               }
+               $this->lastProgress = $percentString;
+
+               $stars = floor( $percent / 2 );
+               echo '[' . str_repeat( '*', $stars ), str_repeat( '.', 50 - $stars ) . '] ' .
+                       "$percentString%\r";
+
        }
 }
 $maintClass = 'PurgeParserCache';