$lb->closeAll();
}
+
+ public function testTransactionCallbackChains() {
+ global $wgDBserver, $wgDBname, $wgDBuser, $wgDBpassword, $wgDBtype, $wgSQLiteDataDir;
+
+ $servers = [
+ [
+ 'host' => $wgDBserver,
+ 'dbname' => $wgDBname,
+ 'tablePrefix' => $this->dbPrefix(),
+ 'user' => $wgDBuser,
+ 'password' => $wgDBpassword,
+ 'type' => $wgDBtype,
+ 'dbDirectory' => $wgSQLiteDataDir,
+ 'load' => 0,
+ 'flags' => DBO_TRX // REPEATABLE-READ for consistency
+ ],
+ ];
+
+ $lb = new LoadBalancer( [
+ 'servers' => $servers,
+ 'localDomain' => new DatabaseDomain( $wgDBname, null, $this->dbPrefix() )
+ ] );
+
+ $conn1 = $lb->openConnection( $lb->getWriterIndex(), false );
+ $conn2 = $lb->openConnection( $lb->getWriterIndex(), '' );
+
+ $count = 0;
+ $lb->forEachOpenMasterConnection( function () use ( &$count ) {
+ ++$count;
+ } );
+ $this->assertEquals( 2, $count, 'Connection handle count' );
+
+ $tlCalls = 0;
+ $lb->setTransactionListener( 'test-listener', function () use ( &$tlCalls ) {
+ ++$tlCalls;
+ } );
+
+ $lb->beginMasterChanges( __METHOD__ );
+ $bc = array_fill_keys( [ 'a', 'b', 'c', 'd' ], 0 );
+ $conn1->onTransactionPreCommitOrIdle( function () use ( &$bc, $conn1, $conn2 ) {
+ $bc['a'] = 1;
+ $conn2->onTransactionPreCommitOrIdle( function () use ( &$bc, $conn1, $conn2 ) {
+ $bc['b'] = 1;
+ $conn1->onTransactionPreCommitOrIdle( function () use ( &$bc, $conn1, $conn2 ) {
+ $bc['c'] = 1;
+ $conn1->onTransactionPreCommitOrIdle( function () use ( &$bc, $conn1, $conn2 ) {
+ $bc['d'] = 1;
+ } );
+ } );
+ } );
+ } );
+ $lb->finalizeMasterChanges();
+ $lb->approveMasterChanges( [] );
+ $lb->commitMasterChanges( __METHOD__ );
+ $lb->runMasterTransactionIdleCallbacks();
+ $lb->runMasterTransactionListenerCallbacks();
+
+ $this->assertEquals( array_fill_keys( [ 'a', 'b', 'c', 'd' ], 1 ), $bc );
+ $this->assertEquals( 2, $tlCalls );
+
+ $tlCalls = 0;
+ $lb->beginMasterChanges( __METHOD__ );
+ $ac = array_fill_keys( [ 'a', 'b', 'c', 'd' ], 0 );
+ $conn1->onTransactionIdle( function () use ( &$ac, $conn1, $conn2 ) {
+ $ac['a'] = 1;
+ $conn2->onTransactionIdle( function () use ( &$ac, $conn1, $conn2 ) {
+ $ac['b'] = 1;
+ $conn1->onTransactionIdle( function () use ( &$ac, $conn1, $conn2 ) {
+ $ac['c'] = 1;
+ $conn1->onTransactionIdle( function () use ( &$ac, $conn1, $conn2 ) {
+ $ac['d'] = 1;
+ } );
+ } );
+ } );
+ } );
+ $lb->finalizeMasterChanges();
+ $lb->approveMasterChanges( [] );
+ $lb->commitMasterChanges( __METHOD__ );
+ $lb->runMasterTransactionIdleCallbacks();
+ $lb->runMasterTransactionListenerCallbacks();
+
+ $this->assertEquals( array_fill_keys( [ 'a', 'b', 'c', 'd' ], 1 ), $ac );
+ $this->assertEquals( 2, $tlCalls );
+
+ $conn1->close();
+ $conn2->close();
+ }
}