/** @var LoadBalancer */
protected $lb;
+ /** @var array */
protected $serverInfos;
/** @var array */
/** @var string */
protected $tableName = 'objectcache';
+ /** @var bool */
+ protected $slaveOnly = false;
+
/** @var array UNIX timestamps */
protected $connFailureTimes = array();
* required to hold the largest shard index. Data will be
* distributed across all tables by key hash. This is for
* MySQL bugs 61735 and 61736.
+ * - slaveOnly: Whether to only use slave DBs and avoid triggering
+ * garbage collection logic of expired items. This only
+ * makes sense if the primary DB is used and only if get()
+ * calls will be used. This is used by ReplicatedBagOStuff.
*
* @param array $params
*/
if ( isset( $params['shards'] ) ) {
$this->shards = intval( $params['shards'] );
}
+ $this->slaveOnly = !empty( $params['slaveOnly'] );
}
/**
$type = isset( $info['type'] ) ? $info['type'] : 'mysql';
$host = isset( $info['host'] ) ? $info['host'] : '[unknown]';
$this->logger->debug( __CLASS__ . ": connecting to $host" );
+ // Use a blank trx profiler to ignore expections as this is a cache
+ $info['trxProfiler'] = new TransactionProfiler();
$db = DatabaseBase::factory( $type, $info );
$db->clearFlag( DBO_TRX );
} else {
* However, SQLite has an opposite behavior. And PostgreSQL needs to know
* if we are in transaction or no
*/
- if ( wfGetDB( DB_MASTER )->getType() == 'mysql' ) {
+ $index = $this->slaveOnly ? DB_SLAVE : DB_MASTER;
+ if ( wfGetDB( $index )->getType() == 'mysql' ) {
$this->lb = wfGetLBFactory()->newMainLB();
- $db = $this->lb->getConnection( DB_MASTER );
+ $db = $this->lb->getConnection( $index );
$db->clearFlag( DBO_TRX ); // auto-commit mode
} else {
- $db = wfGetDB( DB_MASTER );
+ $db = wfGetDB( $index );
}
}
if ( $wgDebugDBTransactions ) {
try {
$db = $this->getDB( $row->serverIndex );
if ( $this->isExpired( $db, $row->exptime ) ) { // MISS
- $this->debug( "get: key has expired, deleting" );
- # Put the expiry time in the WHERE condition to avoid deleting a
- # newly-inserted value
- $db->delete( $row->tableName,
- array( 'keyname' => $key, 'exptime' => $row->exptime ),
- __METHOD__ );
+ $this->debug( "get: key has expired" );
} else { // HIT
$values[$key] = $this->unserialize( $db->decodeBlob( $row->value ) );
}
return $result;
}
-
-
/**
* @param string $key
* @param mixed $value
return $newValue;
}
+ public function merge( $key, $callback, $exptime = 0, $attempts = 10 ) {
+ if ( !is_callable( $callback ) ) {
+ throw new Exception( "Got invalid callback." );
+ }
+
+ return $this->mergeViaCas( $key, $callback, $exptime, $attempts );
+ }
+
/**
* @param DatabaseBase $db
* @param string $exptime
}
protected function garbageCollect() {
- if ( !$this->purgePeriod ) {
+ if ( !$this->purgePeriod || $this->slaveOnly ) {
// Disabled
return;
}
*/
protected function unserialize( $serial ) {
if ( function_exists( 'gzinflate' ) ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$decomp = gzinflate( $serial );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( false !== $decomp ) {
$serial = $decomp;
$this->markServerDown( $exception, $serverIndex );
}
if ( $exception->db && $exception->db->wasReadOnlyError() ) {
- try {
- $exception->db->rollback( __METHOD__ );
- } catch ( DBError $e ) {
+ if ( $exception->db->trxLevel() ) {
+ try {
+ $exception->db->rollback( __METHOD__ );
+ } catch ( DBError $e ) {
+ }
}
}