public function runMasterPostTrxCallbacks( $type ) {
$e = null; // first exception
$this->forEachOpenMasterConnection( function ( DatabaseBase $conn ) use ( $type, &$e ) {
- $conn->clearSnapshot( __METHOD__ ); // clear no-op transactions
-
$conn->setTrxEndCallbackSuppression( false );
+ if ( $conn->writesOrCallbacksPending() ) {
+ // This happens if onTransactionIdle() callbacks leave callbacks on *another* DB
+ // (which finished its callbacks already). Warn and recover in this case. Let the
+ // callbacks run in the final commitMasterChanges() in LBFactory::shutdown().
+ wfWarn( __METHOD__ . ": did not expect writes/callbacks pending." );
+ return;
+ } elseif ( $conn->trxLevel() ) {
+ // This happens for single-DB setups where DB_REPLICA uses the master DB,
+ // thus leaving an implicit read-only transaction open at this point. It
+ // also happens if onTransactionIdle() callbacks leave implicit transactions
+ // open on *other* DBs (which is slightly improper). Let these COMMIT on the
+ // next call to commitMasterChanges(), possibly in LBFactory::shutdown().
+ return;
+ }
try {
$conn->runOnTransactionIdleCallbacks( $type );
} catch ( Exception $ex ) {