/**
* 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;
}
/**
* 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 );
require( dirname( __FILE__ ) . '/Maintenance.php' );
class PurgeParserCache extends Maintenance {
+ var $lastProgress;
+
function __construct() {
parent::__construct();
$this->addDescription( "Remove old objects from the parser cache. " .
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';