MediaWiki  master
purgeParserCache.php
Go to the documentation of this file.
1 <?php
25 require_once __DIR__ . '/Maintenance.php';
26 
28 use Wikimedia\Timestamp\ConvertibleTimestamp;
29 
36 
38  private $lastProgress;
39 
41  private $lastTimestamp;
42 
43  private $tmpCount = 0;
44  private $usleep = 0;
45 
46  public function __construct() {
47  parent::__construct();
48  $this->addDescription( "Remove old objects from the parser cache. " .
49  "This only works when the parser cache is in an SQL database." );
50  $this->addOption( 'expiredate', 'Delete objects expiring before this date.', false, true );
51  $this->addOption(
52  'age',
53  'Delete objects created more than this many seconds ago, assuming ' .
54  '$wgParserCacheExpireTime has remained consistent.',
55  false,
56  true );
57  $this->addOption( 'dry-run', 'Perform a dry run, to verify age and date calculation.' );
58  $this->addOption( 'msleep', 'Milliseconds to sleep between purge chunks of $wgUpdateRowsPerQuery.',
59  false,
60  true );
61  $this->addOption(
62  'tag',
63  'Purge a single server only. This feature is designed for use by large wiki farms where ' .
64  'one has to purge multiple servers concurrently in order to keep up with new writes. ' .
65  'This requires using the SqlBagOStuff "servers" option in $wgObjectCaches.',
66  false,
67  true );
68  }
69 
70  public function execute() {
72 
73  $inputDate = $this->getOption( 'expiredate' );
74  $inputAge = $this->getOption( 'age' );
75  if ( $inputDate !== null ) {
76  $timestamp = strtotime( $inputDate );
77  } elseif ( $inputAge !== null ) {
78  $timestamp = time() + $wgParserCacheExpireTime - intval( $inputAge );
79  } else {
80  $this->fatalError( "Must specify either --expiredate or --age" );
81  }
82  $this->usleep = 1e3 * $this->getOption( 'msleep', 0 );
83  $this->lastTimestamp = microtime( true );
84 
85  $humanDate = ConvertibleTimestamp::convert( TS_RFC2822, $timestamp );
86  if ( $this->hasOption( 'dry-run' ) ) {
87  $this->fatalError( "\nDry run mode, would delete objects having an expiry before " . $humanDate . "\n" );
88  }
89 
90  $this->output( "Deleting objects expiring before " . $humanDate . "\n" );
91 
92  $pc = MediaWikiServices::getInstance()->getParserCache()->getCacheStorage();
93  $success = $pc->deleteObjectsExpiringBefore(
94  $timestamp,
95  [ $this, 'showProgressAndWait' ],
96  INF,
97  // Note that "0" can be a valid server tag, and must not be discarded or changed to null.
98  $this->getOption( 'tag', null )
99  );
100  if ( !$success ) {
101  $this->fatalError( "\nCannot purge this kind of parser cache." );
102  }
103  $this->showProgressAndWait( 100 );
104  $this->output( "\nDone\n" );
105  }
106 
107  public function showProgressAndWait( $percent ) {
108  // Parser caches involve mostly-unthrottled writes of large blobs. This is sometimes prone
109  // to replication lag. As such, while our purge queries are simple primary key deletes,
110  // we want to avoid adding significant load to the replication stream, by being
111  // proactively graceful with these sleeps between each batch.
112  // The reason we don't explicitly wait for replication is that that would require the script
113  // to be aware of cross-dc replicas, which we prefer not to, and waiting for replication
114  // and confirmation latency might actually be *too* graceful and take so long that the
115  // purge script would not be able to finish within 24 hours for large wiki farms.
116  // (T150124).
117  usleep( $this->usleep );
118  $this->tmpCount++;
119 
120  $percentString = sprintf( "%.1f", $percent );
121  if ( $percentString === $this->lastProgress ) {
122  // Only print a line if we've progressed >= 0.1% since the last printed line.
123  // This does not mean every 0.1% step is printed since we only run this callback
124  // once after a deletion batch. How often and how many lines we print depends on the
125  // batch size (SqlBagOStuff::deleteObjectsExpiringBefore, $wgUpdateRowsPerQuery),
126  // and on how many table rows there are.
127  return;
128  }
129  $now = microtime( true );
130  $sec = sprintf( "%.1f", $now - $this->lastTimestamp );
131 
132  // Give a sense of how much time is spent in the delete operations vs the sleep time,
133  // by recording the number of iterations we've completed since the last progress update.
134  $this->output( "... {$percentString}% done (+{$this->tmpCount} iterations in {$sec}s)\n" );
135 
136  $this->lastProgress = $percentString;
137  $this->tmpCount = 0;
138  $this->lastTimestamp = $now;
139  }
140 }
141 
142 $maintClass = PurgeParserCache::class;
143 require_once RUN_MAINTENANCE_IF_MAIN;
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:203
Maintenance\fatalError
fatalError( $msg, $exitCode=1)
Output a message and terminate the current script.
Definition: Maintenance.php:489
Maintenance\addDescription
addDescription( $text)
Set the description text.
Definition: Maintenance.php:329
PurgeParserCache\$tmpCount
$tmpCount
Definition: purgeParserCache.php:43
PurgeParserCache\showProgressAndWait
showProgressAndWait( $percent)
Definition: purgeParserCache.php:107
Maintenance
Abstract maintenance class for quickly writing and churning out maintenance scripts with minimal effo...
Definition: Maintenance.php:59
$success
$success
Definition: NoLocalSettings.php:42
PurgeParserCache\execute
execute()
Do the actual work.
Definition: purgeParserCache.php:70
Maintenance\addOption
addOption( $name, $description, $required=false, $withArg=false, $shortName=false, $multiOccurrence=false)
Add a parameter to the script.
Definition: Maintenance.php:249
$wgParserCacheExpireTime
$wgParserCacheExpireTime
The expiry time for the parser cache, in seconds.
Definition: DefaultSettings.php:2983
PurgeParserCache\$lastProgress
null string $lastProgress
Definition: purgeParserCache.php:38
$maintClass
$maintClass
Definition: purgeParserCache.php:142
PurgeParserCache\__construct
__construct()
Default constructor.
Definition: purgeParserCache.php:46
Maintenance\getOption
getOption( $name, $default=null)
Get an option, or return the default.
Definition: Maintenance.php:286
PurgeParserCache
Maintenance script to remove old objects from the parser cache.
Definition: purgeParserCache.php:35
PurgeParserCache\$usleep
$usleep
Definition: purgeParserCache.php:44
Maintenance\output
output( $out, $channel=null)
Throw some output to the user.
Definition: Maintenance.php:435
PurgeParserCache\$lastTimestamp
null float $lastTimestamp
Definition: purgeParserCache.php:41
Maintenance\hasOption
hasOption( $name)
Checks to see if a particular option was set.
Definition: Maintenance.php:271