* @ingroup Cache
*/
class SqlBagOStuff extends BagOStuff {
- /**
- * @var LoadBalancer
- */
- var $lb;
+ protected $serverInfos;
+
+ /** @var array */
+ protected $serverNames;
+
+ /** @var int */
+ protected $numServers;
+
+ /** @var array */
+ protected $conns;
+
+ /** @var int */
+ protected $lastExpireAll = 0;
+
+ /** @var int */
+ protected $purgePeriod = 100;
- var $serverInfos;
- var $serverNames;
- var $numServers;
- var $conns;
- var $lastExpireAll = 0;
- var $purgePeriod = 100;
- var $shards = 1;
- var $tableName = 'objectcache';
+ /** @var int */
+ protected $shards = 1;
- protected $connFailureTimes = array(); // UNIX timestamps
- protected $connFailureErrors = array(); // exceptions
+ /** @var string */
+ protected $tableName = 'objectcache';
+
+ /** @var array UNIX timestamps */
+ protected $connFailureTimes = array();
+
+ /** @var array Exceptions */
+ protected $connFailureErrors = array();
/**
* Constructor. Parameters are:
$db = DatabaseBase::factory( $type, $info );
$db->clearFlag( DBO_TRX );
} else {
- /*
- * We must keep a separate connection to MySQL in order to avoid deadlocks
- * However, SQLite has an opposite behavior. And PostgreSQL needs to know
- * if we are in transaction or no
- */
+ // We must keep a separate connection to MySQL in order to avoid deadlocks
+ // However, SQLite has an opposite behavior.
+ // @TODO: get this trick to work on PostgreSQL too
if ( wfGetDB( DB_MASTER )->getType() == 'mysql' ) {
- $this->lb = wfGetLBFactory()->newMainLB();
- $db = $this->lb->getConnection( DB_MASTER );
+ $lb = wfGetLBFactory()->newMainLB();
+ $db = $lb->getConnection( DB_MASTER );
$db->clearFlag( DBO_TRX ); // auto-commit mode
} else {
$db = wfGetDB( DB_MASTER );
$res = $db->select( $tableName,
array( 'keyname', 'value', 'exptime' ),
array( 'keyname' => $tableKeys ),
- __METHOD__ );
+ __METHOD__,
+ // Approximate write-on-the-fly BagOStuff API via blocking.
+ // This approximation fails if a ROLLBACK happens (which is rare).
+ // We do not want to flush the TRX as that can break callers.
+ $db->trxLevel() ? array( 'LOCK IN SHARE MODE' ) : array()
+ );
foreach ( $res as $row ) {
$row->serverIndex = $serverIndex;
$row->tableName = $tableName;
$db = $this->getDB( $row->serverIndex );
if ( $this->isExpired( $db, $row->exptime ) ) { // MISS
$this->debug( "get: key has expired, deleting" );
- $db->commit( __METHOD__, 'flush' );
# 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__ );
- $db->commit( __METHOD__, 'flush' );
- $values[$key] = false;
} else { // HIT
$values[$key] = $this->unserialize( $db->decodeBlob( $row->value ) );
}
$this->handleWriteError( $e, $row->serverIndex );
}
} else { // MISS
- $values[$key] = false;
$this->debug( 'get: no matching rows' );
}
}
}
try {
- $db->commit( __METHOD__, 'flush' );
$db->replace(
$tableName,
array( 'keyname' ),
$rows,
__METHOD__
);
- $db->commit( __METHOD__, 'flush' );
} catch ( DBError $e ) {
$this->handleWriteError( $e, $serverIndex );
$result = false;
$encExpiry = $db->timestamp( $exptime );
}
- $db->commit( __METHOD__, 'flush' );
// (bug 24425) use a replace if the db supports it instead of
// delete/insert to avoid clashes with conflicting keynames
$db->replace(
'value' => $db->encodeBlob( $this->serialize( $value ) ),
'exptime' => $encExpiry
), __METHOD__ );
- $db->commit( __METHOD__, 'flush' );
} catch ( DBError $e ) {
$this->handleWriteError( $e, $serverIndex );
return false;
}
$encExpiry = $db->timestamp( $exptime );
}
- $db->commit( __METHOD__, 'flush' );
// (bug 24425) use a replace if the db supports it instead of
// delete/insert to avoid clashes with conflicting keynames
$db->update(
),
__METHOD__
);
- $db->commit( __METHOD__, 'flush' );
} catch ( DBQueryError $e ) {
$this->handleWriteError( $e, $serverIndex );
list( $serverIndex, $tableName ) = $this->getTableByKey( $key );
try {
$db = $this->getDB( $serverIndex );
- $db->commit( __METHOD__, 'flush' );
$db->delete(
$tableName,
array( 'keyname' => $key ),
__METHOD__ );
- $db->commit( __METHOD__, 'flush' );
} catch ( DBError $e ) {
$this->handleWriteError( $e, $serverIndex );
return false;
try {
$db = $this->getDB( $serverIndex );
$step = intval( $step );
- $db->commit( __METHOD__, 'flush' );
$row = $db->selectRow(
$tableName,
array( 'value', 'exptime' ),
array( 'FOR UPDATE' ) );
if ( $row === false ) {
// Missing
- $db->commit( __METHOD__, 'flush' );
return null;
}
$db->delete( $tableName, array( 'keyname' => $key ), __METHOD__ );
if ( $this->isExpired( $db, $row->exptime ) ) {
// Expired, do not reinsert
- $db->commit( __METHOD__, 'flush' );
return null;
}
// Race condition. See bug 28611
$newValue = null;
}
- $db->commit( __METHOD__, 'flush' );
} catch ( DBError $e ) {
$this->handleWriteError( $e, $serverIndex );
return null;
$maxExpTime = $row->exptime;
}
- $db->commit( __METHOD__, 'flush' );
$db->delete(
$this->getTableNameByShard( $i ),
array(
'keyname' => $keys
),
__METHOD__ );
- $db->commit( __METHOD__, 'flush' );
if ( $progressCallback ) {
if ( intval( $totalSeconds ) === 0 ) {
try {
$db = $this->getDB( $serverIndex );
for ( $i = 0; $i < $this->shards; $i++ ) {
- $db->commit( __METHOD__, 'flush' );
$db->delete( $this->getTableNameByShard( $i ), '*', __METHOD__ );
- $db->commit( __METHOD__, 'flush' );
}
} catch ( DBError $e ) {
$this->handleWriteError( $e, $serverIndex );
if ( $exception->db && $exception->db->wasReadOnlyError() ) {
try {
$exception->db->rollback( __METHOD__ );
- } catch ( DBError $e ) {}
+ } catch ( DBError $e ) {
+ }
}
wfDebugLog( 'SQLBagOStuff', "DBError: {$exception->getMessage()}" );
if ( $exception instanceof DBConnectionError ) {
}
for ( $i = 0; $i < $this->shards; $i++ ) {
- $db->commit( __METHOD__, 'flush' );
$db->query(
'CREATE TABLE ' . $db->tableName( $this->getTableNameByShard( $i ) ) .
' LIKE ' . $db->tableName( 'objectcache' ),
__METHOD__ );
- $db->commit( __METHOD__, 'flush' );
}
}
}
/**
* Backwards compatibility alias
*/
-class MediaWikiBagOStuff extends SqlBagOStuff { }
+class MediaWikiBagOStuff extends SqlBagOStuff {
+}