use HashBagOStuff;
use LogicException;
use InvalidArgumentException;
+use UnexpectedValueException;
use Exception;
use RuntimeException;
$this->flags |= self::DBO_TRX;
}
}
+ // Disregard deprecated DBO_IGNORE flag (T189999)
+ $this->flags &= ~self::DBO_IGNORE;
$this->sessionVars = $params['variables'];
return $res;
}
- /**
- * Turns on (false) or off (true) the automatic generation and sending
- * of a "we're sorry, but there has been a database error" page on
- * database errors. Default is on (false). When turned off, the
- * code should use lastErrno() and lastError() to handle the
- * situation as appropriate.
- *
- * Do not use this function outside of the Database classes.
- *
- * @param null|bool $ignoreErrors
- * @return bool The previous value of the flag.
- */
- protected function ignoreErrors( $ignoreErrors = null ) {
- $res = $this->getFlag( self::DBO_IGNORE );
- if ( $ignoreErrors !== null ) {
- // setFlag()/clearFlag() do not allow DBO_IGNORE changes for sanity
- if ( $ignoreErrors ) {
- $this->flags |= self::DBO_IGNORE;
- } else {
- $this->flags &= ~self::DBO_IGNORE;
- }
- }
-
- return $res;
- }
-
public function trxLevel() {
return $this->trxLevel;
}
);
}
+ /**
+ * @return string|null
+ */
+ final protected function getTransactionRoundId() {
+ // If transaction round participation is enabled, see if one is active
+ if ( $this->getFlag( self::DBO_TRX ) ) {
+ $id = $this->getLBInfo( 'trxRoundId' );
+
+ return is_string( $id ) ? $id : null;
+ }
+
+ return null;
+ }
+
public function pendingWriteQueryDuration( $type = self::ESTIMATE_TOTAL ) {
if ( !$this->trxLevel ) {
return false;
public function setFlag( $flag, $remember = self::REMEMBER_NOTHING ) {
if ( ( $flag & self::DBO_IGNORE ) ) {
- throw new \UnexpectedValueException( "Modifying DBO_IGNORE is not allowed." );
+ throw new UnexpectedValueException( "Modifying DBO_IGNORE is not allowed." );
}
if ( $remember === self::REMEMBER_PRIOR ) {
public function clearFlag( $flag, $remember = self::REMEMBER_NOTHING ) {
if ( ( $flag & self::DBO_IGNORE ) ) {
- throw new \UnexpectedValueException( "Modifying DBO_IGNORE is not allowed." );
+ throw new UnexpectedValueException( "Modifying DBO_IGNORE is not allowed." );
}
if ( $remember === self::REMEMBER_PRIOR ) {
* @throws DBQueryError
*/
public function reportQueryError( $error, $errno, $sql, $fname, $tempIgnore = false ) {
- if ( $this->ignoreErrors() || $tempIgnore ) {
+ if ( $tempIgnore ) {
$this->queryLogger->debug( "SQL ERROR (ignored): $error\n" );
} else {
$sql1line = mb_substr( str_replace( "\n", "\\n", $sql ), 0, 5 * 1024 );
}
final public function onTransactionIdle( callable $callback, $fname = __METHOD__ ) {
+ if ( !$this->trxLevel && $this->getTransactionRoundId() ) {
+ // Start an implicit transaction similar to how query() does
+ $this->begin( __METHOD__, self::TRANSACTION_INTERNAL );
+ $this->trxAutomatic = true;
+ }
+
$this->trxIdleCallbacks[] = [ $callback, $fname ];
if ( !$this->trxLevel ) {
$this->runOnTransactionIdleCallbacks( self::TRIGGER_IDLE );
}
final public function onTransactionPreCommitOrIdle( callable $callback, $fname = __METHOD__ ) {
- if ( $this->trxLevel || $this->getFlag( self::DBO_TRX ) ) {
- // As long as DBO_TRX is set, writes will accumulate until the load balancer issues
- // an implicit commit of all peer databases. This is true even if a transaction has
- // not yet been triggered by writes; make sure $callback runs *after* any such writes.
+ if ( !$this->trxLevel && $this->getTransactionRoundId() ) {
+ // Start an implicit transaction similar to how query() does
+ $this->begin( __METHOD__, self::TRANSACTION_INTERNAL );
+ $this->trxAutomatic = true;
+ }
+
+ if ( $this->trxLevel ) {
$this->trxPreCommitCallbacks[] = [ $callback, $fname ];
} else {
// No transaction is active nor will start implicitly, so make one for this callback
$this->trxWriteAdjQueryCount = 0;
$this->trxWriteCallers = [];
// First SELECT after BEGIN will establish the snapshot in REPEATABLE-READ.
- // Get an estimate of the replica DB lag before then, treating estimate staleness
- // as lag itself just to be safe
- $status = $this->getApproximateLagStatus();
- $this->trxReplicaLag = $status['lag'] + ( microtime( true ) - $status['since'] );
+ // Get an estimate of the replication lag before any such queries.
+ $this->trxReplicaLag = $this->getApproximateLagStatus()['lag'];
// T147697: make explicitTrxActive() return true until begin() finishes. This way, no
// caller will think its OK to muck around with the transaction just because startAtomic()
// has not yet completed (e.g. setting trxAtomicLevels).
* @return array|null ('lag': seconds or false on error, 'since': UNIX timestamp of BEGIN)
* @since 1.27
*/
- protected function getTransactionLagStatus() {
+ final protected function getTransactionLagStatus() {
return $this->trxLevel
? [ 'lag' => $this->trxReplicaLag, 'since' => $this->trxTimestamp() ]
: null;