This is in intended to replace the DataUpdate transaction round logic.
It could also be useful for doing transaction rounds in maintenance
scripts.
Also renamed $db => $conn in a few LB methods for consistency.
Change-Id: If21c2ba5e8bac48c250b96137279e7edaa8289f7
return $this->__call( __FUNCTION__, func_get_args() );
}
- public function setFlag( $flag ) {
+ public function setFlag( $flag, $remember = self::REMEMBER_NOTHING ) {
return $this->__call( __FUNCTION__, func_get_args() );
}
- public function clearFlag( $flag ) {
+ public function clearFlag( $flag, $remember = self::REMEMBER_NOTHING ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function restoreFlags( $state = self::RESTORE_PRIOR ) {
return $this->__call( __FUNCTION__, func_get_args() );
}
/** @var float UNIX timestamp */
protected $lastPing = 0.0;
+ /** @var int[] Prior mFlags values */
+ private $priorFlags = [];
+
/** @var TransactionProfiler */
protected $trxProfiler;
return $this->mOpened;
}
- public function setFlag( $flag ) {
+ public function setFlag( $flag, $remember = self::REMEMBER_NOTHING ) {
+ if ( $remember === self::REMEMBER_PRIOR ) {
+ array_push( $this->priorFlags, $this->mFlags );
+ }
$this->mFlags |= $flag;
}
- public function clearFlag( $flag ) {
+ public function clearFlag( $flag, $remember = self::REMEMBER_NOTHING ) {
+ if ( $remember === self::REMEMBER_PRIOR ) {
+ array_push( $this->priorFlags, $this->mFlags );
+ }
$this->mFlags &= ~$flag;
}
+ public function restoreFlags( $state = self::RESTORE_PRIOR ) {
+ if ( !$this->priorFlags ) {
+ return;
+ }
+
+ if ( $state === self::RESTORE_INITIAL ) {
+ $this->mFlags = reset( $this->priorFlags );
+ $this->priorFlags = [];
+ } else {
+ $this->mFlags = array_pop( $this->priorFlags );
+ }
+ }
+
public function getFlag( $flag ) {
return !!( $this->mFlags & $flag );
}
/** @var string Transaction operation comes from the database class internally */
const FLUSHING_INTERNAL = 'flush';
+ /** @var string No not remember the prior flags */
+ const REMEMBER_NOTHING = '';
+ /** @var string Remember the prior flags */
+ const REMEMBER_PRIOR = 'remember';
+ /** @var string Restore to the prior flag state */
+ const RESTORE_PRIOR = 'prior';
+ /** @var string Restore to the initial flag state */
+ const RESTORE_INITIAL = 'initial';
+
/**
* A string describing the current software version, and possibly
* other details in a user-friendly way. Will be listed on Special:Version, etc.
* - DBO_DEFAULT: automatically sets DBO_TRX if not in command line mode
* and removes it in command line mode
* - DBO_PERSISTENT: use persistant database connection
+ * @param string $remember IDatabase::REMEMBER_* constant [default: REMEMBER_NOTHING]
*/
- public function setFlag( $flag );
+ public function setFlag( $flag, $remember = self::REMEMBER_NOTHING );
/**
* Clear a flag for this connection
* - DBO_DEFAULT: automatically sets DBO_TRX if not in command line mode
* and removes it in command line mode
* - DBO_PERSISTENT: use persistant database connection
+ * @param string $remember IDatabase::REMEMBER_* constant [default: REMEMBER_NOTHING]
+ */
+ public function clearFlag( $flag, $remember = self::REMEMBER_NOTHING );
+
+ /**
+ * Restore the flags to their prior state before the last setFlag/clearFlag call
+ *
+ * @param string $state IDatabase::RESTORE_* constant. [default: RESTORE_PRIOR]
+ * @since 1.28
*/
- public function clearFlag( $flag );
+ public function restoreFlags( $state = self::RESTORE_PRIOR );
/**
* Returns a boolean whether the flag $flag is set for this connection
);
}
+ /**
+ * Flush any master transaction snapshots and set DBO_TRX (if DBO_DEFAULT is set)
+ *
+ * The DBO_TRX setting will be reverted to the default in each of these methods:
+ * - commitMasterChanges()
+ * - rollbackMasterChanges()
+ * - commitAll()
+ * This allows for custom transaction rounds from any outer transaction scope.
+ *
+ * @param string $fname
+ * @since 1.28
+ */
+ public function beginMasterChanges( $fname = __METHOD__ ) {
+ $this->forEachLBCallMethod( 'beginMasterChanges', [ $fname ] );
+ }
+
/**
* Commit on all connections. Done for two reasons:
* 1. To commit changes to the masters.
*/
public function commitAll( $fname = __METHOD__ ) {
$this->forEachOpenConnection( function ( DatabaseBase $conn ) use ( $fname ) {
- $conn->commit( $fname, IDatabase::FLUSHING_ALL_PEERS );
+ $conn->commit( $fname, $conn::FLUSHING_ALL_PEERS );
} );
}
} );
}
+ /**
+ * Flush any master transaction snapshots and set DBO_TRX (if DBO_DEFAULT is set)
+ *
+ * The DBO_TRX setting will be reverted to the default in each of these methods:
+ * - commitMasterChanges()
+ * - rollbackMasterChanges()
+ * - commitAll()
+ * This allows for custom transaction rounds from any outer transaction scope.
+ *
+ * @param string $fname
+ * @since 1.28
+ */
+ public function beginMasterChanges( $fname = __METHOD__ ) {
+ $this->forEachOpenMasterConnection( function ( DatabaseBase $conn ) use ( $fname ) {
+ if ( $conn->writesOrCallbacksPending() ) {
+ throw new DBTransactionError(
+ $conn,
+ "Transaction with pending writes still active."
+ );
+ } elseif ( $conn->trxLevel() ) {
+ $conn->commit( $fname, $conn::FLUSHING_ALL_PEERS );
+ }
+ if ( $conn->getFlag( DBO_DEFAULT ) ) {
+ // DBO_TRX is controlled entirely by CLI mode presence with DBO_DEFAULT.
+ // Force DBO_TRX even in CLI mode since a commit round is expected soon.
+ $conn->setFlag( DBO_TRX, $conn::REMEMBER_PRIOR );
+ $conn->onTransactionResolution( function () use ( $conn ) {
+ $conn->restoreFlags( $conn::RESTORE_PRIOR );
+ } );
+ } else {
+ // Config has explicitly requested DBO_TRX be either on or off; respect that.
+ // This is useful for things like blob stores which use auto-commit mode.
+ }
+ } );
+ }
+
/**
* Issue COMMIT on all master connections where writes where done
* @param string $fname Caller name
public function commitMasterChanges( $fname = __METHOD__ ) {
$this->forEachOpenMasterConnection( function ( DatabaseBase $conn ) use ( $fname ) {
if ( $conn->writesOrCallbacksPending() ) {
- $conn->commit( $fname, IDatabase::FLUSHING_ALL_PEERS );
+ $conn->commit( $fname, $conn::FLUSHING_ALL_PEERS );
}
} );
}
*/
public function runMasterPostCommitCallbacks() {
$e = null; // first exception
- $this->forEachOpenMasterConnection( function ( DatabaseBase $db ) use ( &$e ) {
- $db->setPostCommitCallbackSupression( false );
+ $this->forEachOpenMasterConnection( function ( DatabaseBase $conn ) use ( &$e ) {
+ $conn->setPostCommitCallbackSupression( false );
try {
- $db->runOnTransactionIdleCallbacks( IDatabase::TRIGGER_COMMIT );
+ $conn->runOnTransactionIdleCallbacks( $conn::TRIGGER_COMMIT );
} catch ( Exception $ex ) {
$e = $e ?: $ex;
}
foreach ( $conns2[$masterIndex] as $conn ) {
if ( $conn->trxLevel() && $conn->writesOrCallbacksPending() ) {
try {
- $conn->rollback( $fname, IDatabase::FLUSHING_ALL_PEERS );
+ $conn->rollback( $fname, $conn::FLUSHING_ALL_PEERS );
} catch ( DBError $e ) {
MWExceptionHandler::logException( $e );
$failedServers[] = $conn->getServer();
$this->dropFunctions();
$this->functionTest = false;
}
+ $this->db->restoreFlags( IDatabase::RESTORE_INITIAL );
}
/**
* @covers DatabaseBase::dropTable
$db->begin( __METHOD__ );
throw new RunTimeException( "Uh oh!" );
}
+
+ /**
+ * @covers DatabaseBase::getFlag(
+ * @covers DatabaseBase::setFlag()
+ * @covers DatabaseBase::restoreFlags()
+ */
+ public function testFlagSetting() {
+ $db = $this->db;
+ $origTrx = $db->getFlag( DBO_TRX );
+ $origSsl = $db->getFlag( DBO_SSL );
+
+ if ( $origTrx ) {
+ $db->clearFlag( DBO_TRX, $db::REMEMBER_PRIOR );
+ } else {
+ $db->setFlag( DBO_TRX, $db::REMEMBER_PRIOR );
+ }
+ $this->assertEquals( !$origTrx, $db->getFlag( DBO_TRX ) );
+
+ if ( $origSsl ) {
+ $db->clearFlag( DBO_SSL, $db::REMEMBER_PRIOR );
+ } else {
+ $db->setFlag( DBO_SSL, $db::REMEMBER_PRIOR );
+ }
+ $this->assertEquals( !$origSsl, $db->getFlag( DBO_SSL ) );
+
+ $db2 = clone $db;
+ $db2->restoreFlags( $db::RESTORE_INITIAL );
+ $this->assertEquals( $origTrx, $db2->getFlag( DBO_TRX ) );
+ $this->assertEquals( $origSsl, $db2->getFlag( DBO_SSL ) );
+
+ $db->restoreFlags();
+ $this->assertEquals( $origSsl, $db->getFlag( DBO_SSL ) );
+ $this->assertEquals( !$origTrx, $db->getFlag( DBO_TRX ) );
+
+ $db->restoreFlags();
+ $this->assertEquals( $origSsl, $db->getFlag( DBO_SSL ) );
+ $this->assertEquals( $origTrx, $db->getFlag( DBO_TRX ) );
+ }
}
function __construct() {
}
- function clearFlag( $arg ) {
+ function clearFlag( $arg, $remember = self::REMEMBER_NOTHING ) {
}
- function setFlag( $arg ) {
+ function setFlag( $arg, $remember = self::REMEMBER_NOTHING ) {
}
public function insert( $table, $a, $fname = __METHOD__, $options = [] ) {