*/
protected $allViews = null;
+ /** @var TransactionProfiler */
+ protected $trxProfiler;
+
/**
* A string describing the current software version, and possibly
* other details in a user-friendly way. Will be listed on Special:Version, etc.
public function setFakeMaster( $enabled = true ) {
}
+ /**
+ * @return TransactionProfiler
+ */
+ protected function getTransactionProfiler() {
+ return $this->trxProfiler
+ ? $this->trxProfiler
+ : Profiler::instance()->getTransactionProfiler();
+ }
+
/**
* Returns true if this database supports (and uses) cascading deletes
*
$this->mForeign = $foreign;
+ if ( isset( $params['trxProfiler'] ) ) {
+ $this->trxProfiler = $params['trxProfiler']; // override
+ }
+
if ( $user ) {
$this->open( $server, $user, $password, $dbName );
}
-
- $isMaster = !is_null( $this->getLBInfo( 'master' ) );
- $trxProf = Profiler::instance()->getTransactionProfiler();
- $trxProf->recordConnection( $this->mServer, $this->mDBname, $isMaster );
}
/**
# Keep track of whether the transaction has write queries pending
if ( $this->mTrxLevel && !$this->mTrxDoneWrites && $isWriteQuery ) {
$this->mTrxDoneWrites = true;
- Profiler::instance()->getTransactionProfiler()->transactionWritingIn(
+ $this->getTransactionProfiler()->transactionWritingIn(
$this->mServer, $this->mDBname, $this->mTrxShortId );
}
$startTime = microtime( true );
$ret = $this->doQuery( $commentedSql );
# Log the query time and feed it into the DB trx profiler
- $profiler->getTransactionProfiler()->recordQueryCompletion(
+ $this->getTransactionProfiler()->recordQueryCompletion(
$queryProf, $startTime, $isWriteQuery, $this->affectedRows() );
MWDebug::queryTime( $queryId );
$startTime = microtime( true );
$ret = $this->doQuery( $commentedSql );
# Log the query time and feed it into the DB trx profiler
- $profiler->getTransactionProfiler()->recordQueryCompletion(
+ $this->getTransactionProfiler()->recordQueryCompletion(
$queryProf, $startTime, $isWriteQuery, $this->affectedRows() );
}
} else {
* @throws DBQueryError
*/
public function reportQueryError( $error, $errno, $sql, $fname, $tempIgnore = false ) {
- # Ignore errors during error handling to avoid infinite recursion
- $ignore = $this->ignoreErrors( true );
++$this->mErrorCount;
- if ( $ignore || $tempIgnore ) {
+ if ( $this->ignoreErrors() || $tempIgnore ) {
wfDebug( "SQL ERROR (ignored): $error\n" );
- $this->ignoreErrors( $ignore );
} else {
$sql1line = mb_substr( str_replace( "\n", "\\n", $sql ), 0, 5 * 1024 );
wfLogDBError(
/**
* Adds quotes and backslashes.
*
- * @param string $s
+ * @param string|Blob $s
* @return string
*/
public function addQuotes( $s ) {
+ if ( $s instanceof Blob ) {
+ $s = $s->fetch();
+ }
if ( $s === null ) {
return 'NULL';
} else {
* @return bool
*/
public function deadlockLoop() {
- $this->begin( __METHOD__ );
$args = func_get_args();
$function = array_shift( $args );
- $oldIgnore = $this->ignoreErrors( true );
$tries = self::DEADLOCK_TRIES;
-
if ( is_array( $function ) ) {
$fname = $function[0];
} else {
$fname = $function;
}
- do {
- $retVal = call_user_func_array( $function, $args );
- $error = $this->lastError();
- $errno = $this->lastErrno();
- $sql = $this->lastQuery();
+ $this->begin( __METHOD__ );
- if ( $errno ) {
+ $e = null;
+ do {
+ try {
+ $retVal = call_user_func_array( $function, $args );
+ break;
+ } catch ( DBQueryError $e ) {
+ $error = $this->lastError();
+ $errno = $this->lastErrno();
+ $sql = $this->lastQuery();
if ( $this->wasDeadlock() ) {
- # Retry
+ // Retry after a randomized delay
usleep( mt_rand( self::DEADLOCK_DELAY_MIN, self::DEADLOCK_DELAY_MAX ) );
} else {
- $this->reportQueryError( $error, $errno, $sql, $fname );
+ // Throw the error back up
+ throw $e;
}
}
- } while ( $this->wasDeadlock() && --$tries > 0 );
-
- $this->ignoreErrors( $oldIgnore );
+ } while ( --$tries > 0 );
if ( $tries <= 0 ) {
+ // Too many deadlocks; give up
$this->rollback( __METHOD__ );
- $this->reportQueryError( $error, $errno, $sql, $fname );
-
- return false;
+ throw $e;
} else {
$this->commit( __METHOD__ );
if ( !$this->mTrxLevel ) {
$this->begin( $fname );
$this->mTrxAutomatic = true;
- $this->mTrxAutomaticAtomic = true;
+ // If DBO_TRX is set, a series of startAtomic/endAtomic pairs will result
+ // in all changes being in one transaction to keep requests transactional.
+ if ( !$this->getFlag( DBO_TRX ) ) {
+ $this->mTrxAutomaticAtomic = true;
+ }
}
$this->mTrxAtomicLevels->push( $fname );
$this->runOnTransactionPreCommitCallbacks();
$this->doCommit( $fname );
if ( $this->mTrxDoneWrites ) {
- Profiler::instance()->getTransactionProfiler()->transactionWritingOut(
+ $this->mDoneWrites = microtime( true );
+ $this->getTransactionProfiler()->transactionWritingOut(
$this->mServer, $this->mDBname, $this->mTrxShortId );
}
$this->runOnTransactionIdleCallbacks();
$this->runOnTransactionPreCommitCallbacks();
$this->doCommit( $fname );
if ( $this->mTrxDoneWrites ) {
- Profiler::instance()->getTransactionProfiler()->transactionWritingOut(
+ $this->mDoneWrites = microtime( true );
+ $this->getTransactionProfiler()->transactionWritingOut(
$this->mServer, $this->mDBname, $this->mTrxShortId );
}
$this->runOnTransactionIdleCallbacks();
$this->mTrxPreCommitCallbacks = array(); // cancel
$this->mTrxAtomicLevels = new SplStack;
if ( $this->mTrxDoneWrites ) {
- Profiler::instance()->getTransactionProfiler()->transactionWritingOut(
+ $this->getTransactionProfiler()->transactionWritingOut(
$this->mServer, $this->mDBname, $this->mTrxShortId );
}
}
* in result objects. Pass the object through this function to return the
* original string.
*
- * @param string $b
+ * @param string|Blob $b
* @return string
*/
public function decodeBlob( $b ) {
+ if ( $b instanceof Blob ) {
+ $b = $b->fetch();
+ }
return $b;
}
* @return string
*/
public function decodeExpiry( $expiry, $format = TS_MW ) {
- return ( $expiry == '' || $expiry == $this->getInfinity() )
+ return ( $expiry == '' || $expiry == 'infinity' || $expiry == $this->getInfinity() )
? 'infinity'
: wfTimestamp( $format, $expiry );
}