*/
private $mTrxAutomaticAtomic = false;
+ /**
+ * Track the seconds spent in write queries for the current transaction
+ *
+ * @var float
+ */
+ private $mTrxWriteDuration = 0.0;
+
/**
* @since 1.21
* @var resource File handle for upgrade
);
}
+ /**
+ * Get the time spend running write queries for this
+ *
+ * High times could be due to scanning, updates, locking, and such
+ *
+ * @return float|bool Returns false if not transaction is active
+ * @since 1.26
+ */
+ public function pendingWriteQueryDuration() {
+ return $this->mTrxLevel ? $this->mTrxWriteDuration : false;
+ }
+
/**
* Is a connection to the database open?
* @return bool
# Do the query and handle errors
$startTime = microtime( true );
$ret = $this->doQuery( $commentedSql );
+ $queryRuntime = microtime( true ) - $startTime;
# Log the query time and feed it into the DB trx profiler
$this->getTransactionProfiler()->recordQueryCompletion(
$queryProf, $startTime, $isWriteQuery, $this->affectedRows() );
# Should be safe to silently retry (no trx and thus no callbacks)
$startTime = microtime( true );
$ret = $this->doQuery( $commentedSql );
+ $queryRuntime = microtime( true ) - $startTime;
# Log the query time and feed it into the DB trx profiler
$this->getTransactionProfiler()->recordQueryCompletion(
$queryProf, $startTime, $isWriteQuery, $this->affectedRows() );
$queryProfSection = false;
$totalProfSection = false;
+ if ( $isWriteQuery && $this->mTrxLevel ) {
+ $this->mTrxWriteDuration += $queryRuntime;
+ }
+
return $res;
}
* @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(
* @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 ) {
+ $this->mDoneWrites = microtime( true );
$this->getTransactionProfiler()->transactionWritingOut(
$this->mServer, $this->mDBname, $this->mTrxShortId );
}
$this->mTrxIdleCallbacks = array();
$this->mTrxPreCommitCallbacks = array();
$this->mTrxShortId = wfRandomString( 12 );
+ $this->mTrxWriteDuration = 0.0;
}
/**
$this->runOnTransactionPreCommitCallbacks();
$this->doCommit( $fname );
if ( $this->mTrxDoneWrites ) {
+ $this->mDoneWrites = microtime( true );
$this->getTransactionProfiler()->transactionWritingOut(
$this->mServer, $this->mDBname, $this->mTrxShortId );
}
* @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 );
}