Merge "Added post-commit callback support to DB classes."
authorCatrope <roan.kattouw@gmail.com>
Wed, 29 Aug 2012 20:53:04 +0000 (20:53 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 29 Aug 2012 20:53:04 +0000 (20:53 +0000)
includes/db/Database.php
includes/db/DatabaseIbm_db2.php
includes/db/DatabaseMssql.php
includes/db/DatabaseOracle.php
includes/db/DatabaseSqlite.php

index ae5335b..3354f98 100644 (file)
@@ -225,12 +225,12 @@ abstract class DatabaseBase implements DatabaseType {
 
        protected $mServer, $mUser, $mPassword, $mDBname;
 
-       /**
-        * @var DatabaseBase
-        */
        protected $mConn = null;
        protected $mOpened = false;
 
+       /** @var Array */
+       protected $trxIdleCallbacks = array();
+
        protected $mTablePrefix;
        protected $mFlags;
        protected $mTrxLevel = 0;
@@ -2825,12 +2825,62 @@ abstract class DatabaseBase implements DatabaseType {
                }
        }
 
+       /**
+        * Run an anonymous function as soon as there is no transaction pending.
+        * If there is a transaction and it is rolled back, then the callback is cancelled.
+        * Callbacks must commit any transactions that they begin.
+        *
+        * This is useful for updates to different systems or separate transactions are needed.
+        *
+        * @param Closure $callback
+        * @return void
+        */
+       final public function onTransactionIdle( Closure $callback ) {
+               if ( $this->mTrxLevel ) {
+                       $this->trxIdleCallbacks[] = $callback;
+               } else {
+                       $callback();
+               }
+       }
+
+       /**
+        * Actually run the "on transaction idle" callbacks
+        */
+       protected function runOnTransactionIdleCallbacks() {
+               $e = null; // last exception
+               do { // callbacks may add callbacks :)
+                       $callbacks = $this->trxIdleCallbacks;
+                       $this->trxIdleCallbacks = array(); // recursion guard
+                       foreach ( $callbacks as $callback ) {
+                               try {
+                                       $callback();
+                               } catch ( Exception $e ) {}
+                       }
+               } while ( count( $this->trxIdleCallbacks ) );
+
+               if ( $e instanceof Exception ) {
+                       throw $e; // re-throw any last exception
+               }
+       }
+
        /**
         * Begin a transaction
         *
         * @param $fname string
         */
-       public function begin( $fname = 'DatabaseBase::begin' ) {
+       final public function begin( $fname = 'DatabaseBase::begin' ) {
+               if ( $this->mTrxLevel ) { // implicit commit
+                       $this->doCommit( $fname );
+                       $this->runOnTransactionIdleCallbacks();
+               }
+               $this->doBegin( $fname );
+       }
+
+       /**
+        * @see DatabaseBase::begin()
+        * @param type $fname
+        */
+       protected function doBegin( $fname ) {
                $this->query( 'BEGIN', $fname );
                $this->mTrxLevel = 1;
        }
@@ -2840,7 +2890,16 @@ abstract class DatabaseBase implements DatabaseType {
         *
         * @param $fname string
         */
-       public function commit( $fname = 'DatabaseBase::commit' ) {
+       final public function commit( $fname = 'DatabaseBase::commit' ) {
+               $this->doCommit( $fname );
+               $this->runOnTransactionIdleCallbacks();
+       }
+
+       /**
+        * @see DatabaseBase::commit()
+        * @param type $fname
+        */
+       protected function doCommit( $fname ) {
                if ( $this->mTrxLevel ) {
                        $this->query( 'COMMIT', $fname );
                        $this->mTrxLevel = 0;
@@ -2853,7 +2912,16 @@ abstract class DatabaseBase implements DatabaseType {
         *
         * @param $fname string
         */
-       public function rollback( $fname = 'DatabaseBase::rollback' ) {
+       final public function rollback( $fname = 'DatabaseBase::rollback' ) {
+               $this->doRollback( $fname );
+               $this->trxIdleCallbacks = array(); // cancel
+       }
+
+       /**
+        * @see DatabaseBase::rollback()
+        * @param type $fname
+        */
+       protected function doRollback( $fname ) {
                if ( $this->mTrxLevel ) {
                        $this->query( 'ROLLBACK', $fname, true );
                        $this->mTrxLevel = 0;
index 80220af..f1f6dfc 100644 (file)
@@ -807,7 +807,7 @@ class DatabaseIbm_db2 extends DatabaseBase {
        /**
         * Start a transaction (mandatory)
         */
-       public function begin( $fname = 'DatabaseIbm_db2::begin' ) {
+       protected function doBegin( $fname = 'DatabaseIbm_db2::begin' ) {
                // BEGIN is implicit for DB2
                // However, it requires that AutoCommit be off.
 
@@ -823,7 +823,7 @@ class DatabaseIbm_db2 extends DatabaseBase {
         * End a transaction
         * Must have a preceding begin()
         */
-       public function commit( $fname = 'DatabaseIbm_db2::commit' ) {
+       protected function doCommit( $fname = 'DatabaseIbm_db2::commit' ) {
                db2_commit( $this->mConn );
 
                // Some MediaWiki code is still transaction-less (?).
@@ -837,7 +837,7 @@ class DatabaseIbm_db2 extends DatabaseBase {
        /**
         * Cancel a transaction
         */
-       public function rollback( $fname = 'DatabaseIbm_db2::rollback' ) {
+       protected function doRollback( $fname = 'DatabaseIbm_db2::rollback' ) {
                db2_rollback( $this->mConn );
                // turn auto-commit back on
                // not sure if this is appropriate
index 3846e96..914ab40 100644 (file)
@@ -694,7 +694,7 @@ class DatabaseMssql extends DatabaseBase {
        /**
         * Begin a transaction, committing any previously open transaction
         */
-       function begin( $fname = 'DatabaseMssql::begin' ) {
+       protected function doBegin( $fname = 'DatabaseMssql::begin' ) {
                sqlsrv_begin_transaction( $this->mConn );
                $this->mTrxLevel = 1;
        }
@@ -702,7 +702,7 @@ class DatabaseMssql extends DatabaseBase {
        /**
         * End a transaction
         */
-       function commit( $fname = 'DatabaseMssql::commit' ) {
+       protected function doCommit( $fname = 'DatabaseMssql::commit' ) {
                sqlsrv_commit( $this->mConn );
                $this->mTrxLevel = 0;
        }
@@ -711,7 +711,7 @@ class DatabaseMssql extends DatabaseBase {
         * Rollback a transaction.
         * No-op on non-transactional databases.
         */
-       function rollback( $fname = 'DatabaseMssql::rollback' ) {
+       protected function doRollback( $fname = 'DatabaseMssql::rollback' ) {
                sqlsrv_rollback( $this->mConn );
                $this->mTrxLevel = 0;
        }
index cf3e45d..7d8884f 100644 (file)
@@ -955,12 +955,12 @@ class DatabaseOracle extends DatabaseBase {
                return $this->fieldInfoMulti ($table, $field);
        }
 
-       function begin( $fname = 'DatabaseOracle::begin' ) {
+       protected function doBegin( $fname = 'DatabaseOracle::begin' ) {
                $this->mTrxLevel = 1;
                $this->doQuery( 'SET CONSTRAINTS ALL DEFERRED' );
        }
 
-       function commit( $fname = 'DatabaseOracle::commit' ) {
+       protected function doCommit( $fname = 'DatabaseOracle::commit' ) {
                if ( $this->mTrxLevel ) {
                        $ret = oci_commit( $this->mConn );
                        if ( !$ret ) {
@@ -971,7 +971,7 @@ class DatabaseOracle extends DatabaseBase {
                }
        }
 
-       function rollback( $fname = 'DatabaseOracle::rollback' ) {
+       protected function doRollback( $fname = 'DatabaseOracle::rollback' ) {
                if ( $this->mTrxLevel ) {
                        oci_rollback( $this->mConn );
                        $this->mTrxLevel = 0;
index cb3da1e..f1e553d 100644 (file)
@@ -645,7 +645,7 @@ class DatabaseSqlite extends DatabaseBase {
                return false;
        }
 
-       function begin( $fname = '' ) {
+       protected function doBegin( $fname = '' ) {
                if ( $this->mTrxLevel == 1 ) {
                        $this->commit( __METHOD__ );
                }
@@ -653,7 +653,7 @@ class DatabaseSqlite extends DatabaseBase {
                $this->mTrxLevel = 1;
        }
 
-       function commit( $fname = '' ) {
+       protected function doCommit( $fname = '' ) {
                if ( $this->mTrxLevel == 0 ) {
                        return;
                }
@@ -661,7 +661,7 @@ class DatabaseSqlite extends DatabaseBase {
                $this->mTrxLevel = 0;
        }
 
-       function rollback( $fname = '' ) {
+       protected function doRollback( $fname = '' ) {
                if ( $this->mTrxLevel == 0 ) {
                        return;
                }