use Wikimedia\Rdbms\DBError;
use Wikimedia\Rdbms\DBQueryError;
use Wikimedia\Rdbms\DBConnectionError;
+use Wikimedia\Rdbms\IMaintainableDatabase;
use Wikimedia\Rdbms\LoadBalancer;
use Wikimedia\ScopedCallback;
use Wikimedia\WaitConditionLoop;
*
* @ingroup Cache
*/
-class SqlBagOStuff extends BagOStuff {
+class SqlBagOStuff extends MediumSpecificBagOStuff {
/** @var array[] (server index => server config) */
protected $serverInfos;
/** @var string[] (server index => tag/host name) */
protected $tableName = 'objectcache';
/** @var bool */
protected $replicaOnly = false;
- /** @var int */
- protected $syncTimeout = 3;
/** @var LoadBalancer|null */
protected $separateMainLB;
protected $connFailureErrors = [];
/** @var int */
- private static $GARBAGE_COLLECT_DELAY_SEC = 1;
+ private static $GC_DELAY_SEC = 1;
/** @var string */
private static $OP_SET = 'set';
if ( isset( $params['shards'] ) ) {
$this->shards = intval( $params['shards'] );
}
- if ( isset( $params['syncTimeout'] ) ) {
- $this->syncTimeout = $params['syncTimeout'];
- }
// Backwards-compatibility for < 1.34
$this->replicaOnly = $params['replicaOnly'] ?? ( $params['slaveOnly'] ?? false );
}
* Get a connection to the specified database
*
* @param int $serverIndex
- * @return Database
+ * @return IMaintainableDatabase
* @throws MWException
*/
protected function getDB( $serverIndex ) {
- if ( !isset( $this->conns[$serverIndex] ) ) {
- if ( $serverIndex >= $this->numServers ) {
- throw new MWException( __METHOD__ . ": Invalid server index \"$serverIndex\"" );
- }
+ if ( $serverIndex >= $this->numServers ) {
+ throw new MWException( __METHOD__ . ": Invalid server index \"$serverIndex\"" );
+ }
- # Don't keep timing out trying to connect for each call if the DB is down
- if ( isset( $this->connFailureErrors[$serverIndex] )
- && ( time() - $this->connFailureTimes[$serverIndex] ) < 60
- ) {
- throw $this->connFailureErrors[$serverIndex];
- }
+ # Don't keep timing out trying to connect for each call if the DB is down
+ if (
+ isset( $this->connFailureErrors[$serverIndex] ) &&
+ ( $this->getCurrentTime() - $this->connFailureTimes[$serverIndex] ) < 60
+ ) {
+ throw $this->connFailureErrors[$serverIndex];
+ }
- if ( $this->serverInfos ) {
+ if ( $this->serverInfos ) {
+ if ( !isset( $this->conns[$serverIndex] ) ) {
// Use custom database defined by server connection info
$info = $this->serverInfos[$serverIndex];
$type = $info['type'] ?? 'mysql';
$this->logger->debug( __CLASS__ . ": connecting to $host" );
$db = Database::factory( $type, $info );
$db->clearFlag( DBO_TRX ); // auto-commit mode
+ $this->conns[$serverIndex] = $db;
+ }
+ $db = $this->conns[$serverIndex];
+ } else {
+ // Use the main LB database
+ $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
+ $index = $this->replicaOnly ? DB_REPLICA : DB_MASTER;
+ if ( $lb->getServerType( $lb->getWriterIndex() ) !== 'sqlite' ) {
+ // Keep a separate connection to avoid contention and deadlocks
+ $db = $lb->getConnectionRef( $index, [], false, $lb::CONN_TRX_AUTOCOMMIT );
} else {
- // Use the main LB database
- $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
- $index = $this->replicaOnly ? DB_REPLICA : DB_MASTER;
- if ( $lb->getServerType( $lb->getWriterIndex() ) !== 'sqlite' ) {
- // Keep a separate connection to avoid contention and deadlocks
- $db = $lb->getConnection( $index, [], false, $lb::CONN_TRX_AUTOCOMMIT );
- } else {
- // However, SQLite has the opposite behavior due to DB-level locking.
- // Stock sqlite MediaWiki installs use a separate sqlite cache DB instead.
- $db = $lb->getConnection( $index );
- }
+ // However, SQLite has the opposite behavior due to DB-level locking.
+ // Stock sqlite MediaWiki installs use a separate sqlite cache DB instead.
+ $db = $lb->getConnectionRef( $index );
}
-
- $this->logger->debug( sprintf( "Connection %s will be used for SqlBagOStuff", $db ) );
- $this->conns[$serverIndex] = $db;
}
- return $this->conns[$serverIndex];
+ $this->logger->debug( sprintf( "Connection %s will be used for SqlBagOStuff", $db ) );
+
+ return $db;
}
/**
$keysByTable[$serverIndex][$tableName][] = $key;
}
- $exptime = $this->convertToExpiry( $exptime );
+ $exptime = $this->getExpirationAsTimestamp( $exptime );
$result = true;
/** @noinspection PhpUnusedLocalVariableInspection */
protected function cas( $casToken, $key, $value, $exptime = 0, $flags = 0 ) {
list( $serverIndex, $tableName ) = $this->getTableByKey( $key );
- $exptime = $this->convertToExpiry( $exptime );
+ $exptime = $this->getExpirationAsTimestamp( $exptime );
/** @noinspection PhpUnusedLocalVariableInspection */
$silenceScope = $this->silenceTransactionProfiler();
return $ok;
}
- protected function doChangeTTLMulti( array $keys, $exptime, $flags = 0 ) {
+ public function changeTTLMulti( array $keys, $exptime, $flags = 0 ) {
return $this->modifyMulti(
array_fill_keys( $keys, null ),
$exptime,
protected function isExpired( $db, $exptime ) {
return (
$exptime != $this->getMaxDateTime( $db ) &&
- wfTimestamp( TS_UNIX, $exptime ) < time()
+ wfTimestamp( TS_UNIX, $exptime ) < $this->getCurrentTime()
);
}
* @return string
*/
protected function getMaxDateTime( $db ) {
- if ( time() > 0x7fffffff ) {
+ if ( (int)$this->getCurrentTime() > 0x7fffffff ) {
return $db->timestamp( 1 << 62 );
} else {
return $db->timestamp( 0x7fffffff );
// Only purge on one in every $this->purgePeriod writes
mt_rand( 0, $this->purgePeriod - 1 ) == 0 &&
// Avoid repeating the delete within a few seconds
- ( time() - $this->lastGarbageCollect ) > self::$GARBAGE_COLLECT_DELAY_SEC
+ ( $this->getCurrentTime() - $this->lastGarbageCollect ) > self::$GC_DELAY_SEC
) {
$garbageCollector = function () use ( $db ) {
- $this->deleteServerObjectsExpiringBefore( $db, time(), null, $this->purgeLimit );
+ $this->deleteServerObjectsExpiringBefore(
+ $db, $this->getCurrentTime(),
+ null,
+ $this->purgeLimit
+ );
$this->lastGarbageCollect = time();
};
if ( $this->asyncHandler ) {
- $this->lastGarbageCollect = time(); // avoid duplicate enqueues
+ $this->lastGarbageCollect = $this->getCurrentTime(); // avoid duplicate enqueues
( $this->asyncHandler )( $garbageCollector );
} else {
$garbageCollector();
}
public function expireAll() {
- $this->deleteObjectsExpiringBefore( time() );
+ $this->deleteObjectsExpiringBefore( $this->getCurrentTime() );
}
public function deleteObjectsExpiringBefore(
protected function markServerDown( DBError $exception, $serverIndex ) {
unset( $this->conns[$serverIndex] ); // bug T103435
+ $now = $this->getCurrentTime();
if ( isset( $this->connFailureTimes[$serverIndex] ) ) {
- if ( time() - $this->connFailureTimes[$serverIndex] >= 60 ) {
+ if ( $now - $this->connFailureTimes[$serverIndex] >= 60 ) {
unset( $this->connFailureTimes[$serverIndex] );
unset( $this->connFailureErrors[$serverIndex] );
} else {
return;
}
}
- $now = time();
$this->logger->info( __METHOD__ . ": Server #$serverIndex down until " . ( $now + 60 ) );
$this->connFailureTimes[$serverIndex] = $now;
$this->connFailureErrors[$serverIndex] = $exception;