*/
private $mTrxAutomaticAtomic = false;
+ /**
+ * Track the write query callers of the current transaction
+ *
+ * @var string[]
+ */
+ private $mTrxWriteCallers = array();
+
/**
* Track the seconds spent in write queries for the current transaction
*
*/
private $mTrxWriteDuration = 0.0;
+ /** @var array Map of (name => 1) for locks obtained via lock() */
+ private $mNamedLocksHeld = array();
+
/** @var IDatabase|null Lazy handle to the master DB this server replicates from */
private $lazyMasterHandle;
* @return TransactionProfiler
*/
protected function getTransactionProfiler() {
- return $this->trxProfiler
- ? $this->trxProfiler
- : Profiler::instance()->getTransactionProfiler();
+ if ( !$this->trxProfiler ) {
+ $this->trxProfiler = new TransactionProfiler();
+ }
+
+ return $this->trxProfiler;
+ }
+
+ /**
+ * @param TransactionProfiler $profiler
+ * @since 1.27
+ */
+ public function setTransactionProfiler( TransactionProfiler $profiler ) {
+ $this->trxProfiler = $profiler;
}
/**
return $this->mTrxLevel ? $this->mTrxWriteDuration : false;
}
+ public function pendingWriteCallers() {
+ return $this->mTrxLevel ? $this->mTrxWriteCallers : array();
+ }
+
public function isOpen() {
return $this->mOpened;
}
$msg = __METHOD__ . ": lost connection to $server; reconnected";
wfDebugLog( 'DBPerformance', "$msg:\n" . wfBacktrace( true ) );
- if ( $hadTrx ) {
+ if ( $hadTrx || $this->mNamedLocksHeld ) {
# Leave $ret as false and let an error be reported.
# Callers may catch the exception and continue to use the DB.
$this->reportQueryError( $lastError, $lastErrno, $sql, $fname, $tempIgnore );
if ( $isWriteQuery && $this->mTrxLevel ) {
$this->mTrxWriteDuration += $queryRuntime;
+ $this->mTrxWriteCallers[] = $fname;
}
return $res;
$this->mTrxPreCommitCallbacks = array();
$this->mTrxShortId = wfRandomString( 12 );
$this->mTrxWriteDuration = 0.0;
+ $this->mTrxWriteCallers = array();
// First SELECT after BEGIN will establish the snapshot in REPEATABLE-READ.
// Get an estimate of the slave lag before then, treating estimate staleness
// as lag itself just to be safe
if ( !$this->mTrxLevel ) {
wfWarn( "$fname: No transaction to rollback, something got out of sync!" );
return; // nothing to do
- } elseif ( $this->mTrxAutomatic ) {
- wfWarn( "$fname: Explicit rollback of implicit transaction. Something may be out of sync!" );
}
} else {
if ( !$this->mTrxLevel ) {
return; // nothing to do
- } elseif ( !$this->mTrxAutomatic ) {
- wfWarn( "$fname: Flushing an explicit transaction, getting out of sync!" );
}
}
}
public function lock( $lockName, $method, $timeout = 5 ) {
+ $this->mNamedLocksHeld[$lockName] = 1;
+
return true;
}
public function unlock( $lockName, $method ) {
+ unset( $this->mNamedLocksHeld[$lockName] );
+
return true;
}
+ public function getScopedLockAndFlush( $lockKey, $fname, $timeout ) {
+ if ( !$this->lock( $lockKey, $fname, $timeout ) ) {
+ return null;
+ }
+
+ $that = $this;
+ $unlocker = new ScopedCallback( function () use ( $that, $lockKey, $fname ) {
+ $that->commit( __METHOD__, 'flush' );
+ $that->unlock( $lockKey, $fname );
+ } );
+
+ $this->commit( __METHOD__, 'flush' );
+
+ return $unlocker;
+ }
+
public function namedLocksEnqueue() {
return false;
}