* @param string $date The reference date in MW format
* @param callable|bool $progressCallback Optional, a function which will be called
* regularly during long-running operations with the percentage progress
- * as the first parameter.
+ * as the first parameter. [optional]
+ * @param int $limit Maximum number of keys to delete [default: INF]
*
* @return bool Success, false if unimplemented
*/
- public function deleteObjectsExpiringBefore( $date, $progressCallback = false ) {
+ public function deleteObjectsExpiringBefore( $date, $progressCallback = false, $limit = INF ) {
// stub
return false;
}
$this->backend->setDebug( $bool );
}
- public function deleteObjectsExpiringBefore( $date, $progressCallback = false ) {
- parent::deleteObjectsExpiringBefore( $date, $progressCallback );
- return $this->backend->deleteObjectsExpiringBefore( $date, $progressCallback );
+ public function deleteObjectsExpiringBefore( $date, $progressCallback = false, $limit = INF ) {
+ parent::deleteObjectsExpiringBefore( $date, $progressCallback, $limit );
+ return $this->backend->deleteObjectsExpiringBefore( $date, $progressCallback, $limit );
}
public function makeKeyInternal( $keyspace, $args ) {
return $this->caches[0]->unlock( $key );
}
- /**
- * Delete objects expiring before a certain date.
- *
- * Succeed if any of the child caches succeed.
- * @param string $date
- * @param bool|callable $progressCallback
- * @return bool
- */
- public function deleteObjectsExpiringBefore( $date, $progressCallback = false ) {
+ public function deleteObjectsExpiringBefore( $date, $progressCallback = false, $limit = INF ) {
$ret = false;
foreach ( $this->caches as $cache ) {
- if ( $cache->deleteObjectsExpiringBefore( $date, $progressCallback ) ) {
+ if ( $cache->deleteObjectsExpiringBefore( $date, $progressCallback, $limit ) ) {
$ret = true;
}
}
/** @var int */
protected $lastExpireAll = 0;
/** @var int */
- protected $purgePeriod = 100;
+ protected $purgePeriod = 10;
+ /** @var int */
+ protected $purgeLimit = 100;
/** @var int */
protected $shards = 1;
/** @var string */
* when a cluster is replicated to another site (with different host names)
* but each server has a corresponding replica in the other cluster.
*
- * - purgePeriod: The average number of object cache requests in between
+ * - purgePeriod: The average number of object cache writes in between
* garbage collection operations, where expired entries
* are removed from the database. Or in other words, the
* reciprocal of the probability of purging on any given
- * request. If this is set to zero, purging will never be
- * done.
+ * write. If this is set to zero, purging will never be done.
+ *
+ * - purgeLimit: Maximum number of rows to purge at once.
*
* - tableName: The table name to use, default is "objectcache".
*
if ( isset( $params['purgePeriod'] ) ) {
$this->purgePeriod = intval( $params['purgePeriod'] );
}
+ if ( isset( $params['purgeLimit'] ) ) {
+ $this->purgeLimit = intval( $params['purgeLimit'] );
+ }
if ( isset( $params['tableName'] ) ) {
$this->tableName = $params['tableName'];
}
$keysByTable[$serverIndex][$tableName][] = $key;
}
- $this->garbageCollect(); // expire old entries if any
-
$dataRows = [];
foreach ( $keysByTable as $serverIndex => $serverKeys ) {
try {
// Disabled
return;
}
- // Only purge on one in every $this->purgePeriod requests.
+ // Only purge on one in every $this->purgePeriod writes
if ( $this->purgePeriod !== 1 && mt_rand( 0, $this->purgePeriod - 1 ) ) {
return;
}
// Avoid repeating the delete within a few seconds
if ( $now > ( $this->lastExpireAll + 1 ) ) {
$this->lastExpireAll = $now;
- $this->expireAll();
+ $this->deleteObjectsExpiringBefore(
+ wfTimestamp( TS_MW, $now ),
+ false,
+ $this->purgeLimit
+ );
}
}
$this->deleteObjectsExpiringBefore( wfTimestampNow() );
}
- /**
- * Delete objects from the database which expire before a certain date.
- * @param string $timestamp
- * @param bool|callable $progressCallback
- * @return bool
- */
- public function deleteObjectsExpiringBefore( $timestamp, $progressCallback = false ) {
+ public function deleteObjectsExpiringBefore(
+ $timestamp,
+ $progressCallback = false,
+ $limit = INF
+ ) {
/** @noinspection PhpUnusedLocalVariableInspection */
$silenceScope = $this->silenceTransactionProfiler();
+
+ $count = 0;
for ( $serverIndex = 0; $serverIndex < $this->numServers; $serverIndex++ ) {
$db = null;
try {
[ 'keyname', 'exptime' ],
$conds,
__METHOD__,
- [ 'LIMIT' => 100, 'ORDER BY' => 'exptime' ] );
+ [ 'LIMIT' => 100, 'ORDER BY' => 'exptime' ]
+ );
if ( $rows === false || !$rows->numRows() ) {
break;
}
'exptime < ' . $db->addQuotes( $dbTimestamp ),
'keyname' => $keys
],
- __METHOD__ );
+ __METHOD__
+ );
+ $count += $db->affectedRows();
+ if ( $count >= $limit ) {
+ return true;
+ }
- if ( $progressCallback ) {
+ if ( is_callable( $progressCallback ) ) {
if ( intval( $totalSeconds ) === 0 ) {
$percent = 0;
} else {
return false;
}
}
+
return true;
}