rdbms: Introduce TransactionManager class to move out the logic
This would make Database class smaller and encapsulates the transaction logic making it easier to understand and change. Bug: T299698 Change-Id: I409a474209ab4b714c5f62e5e7c0b7a62b9e82c1
This commit is contained in:
parent
c51065fb99
commit
83adf1eb88
3 changed files with 99 additions and 27 deletions
|
|
@ -1861,6 +1861,7 @@ $wgAutoloadLocalClasses = [
|
|||
'Wikimedia\\Rdbms\\Subquery' => __DIR__ . '/includes/libs/rdbms/encasing/Subquery.php',
|
||||
'Wikimedia\\Rdbms\\TimestampType' => __DIR__ . '/includes/libs/rdbms/dbal/TimestampType.php',
|
||||
'Wikimedia\\Rdbms\\TinyIntType' => __DIR__ . '/includes/libs/rdbms/dbal/TinyIntType.php',
|
||||
'Wikimedia\\Rdbms\\TransactionManager' => __DIR__ . '/includes/libs/rdbms/database/TransactionManager.php',
|
||||
'Wikimedia\\Rdbms\\TransactionProfiler' => __DIR__ . '/includes/libs/rdbms/TransactionProfiler.php',
|
||||
'Wikimedia\\Reflection\\GhostFieldAccessTrait' => __DIR__ . '/includes/libs/GhostFieldAccessTrait.php',
|
||||
'WikitextContent' => __DIR__ . '/includes/content/WikitextContent.php',
|
||||
|
|
|
|||
|
|
@ -68,6 +68,8 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
|
|||
protected $profiler;
|
||||
/** @var TransactionProfiler */
|
||||
protected $trxProfiler;
|
||||
/** @var TransactionManager */
|
||||
private $transactionManager;
|
||||
|
||||
/** @var DatabaseDomain */
|
||||
protected $currentDomain;
|
||||
|
|
@ -127,16 +129,12 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
|
|||
/** @var array Map of (table name => 1) for current TEMPORARY tables */
|
||||
protected $sessionDirtyTempTables = [];
|
||||
|
||||
/** @var string Application-side ID of the active transaction or an empty string otherwise */
|
||||
private $trxId = '';
|
||||
/** @var int Transaction status */
|
||||
private $trxStatus = self::STATUS_TRX_NONE;
|
||||
/** @var Throwable|null The last error that caused the status to become STATUS_TRX_ERROR */
|
||||
private $trxStatusCause;
|
||||
/** @var array|null Error details of the last statement-only rollback */
|
||||
private $trxStatusIgnoredCause;
|
||||
/** @var float|null UNIX timestamp at the time of BEGIN for the last transaction */
|
||||
private $trxTimestamp = null;
|
||||
/** @var array|null Replication lag estimate at the time of BEGIN for the last transaction */
|
||||
private $trxReplicaLagStatus = null;
|
||||
/** @var string|null Name of the function that start the last transaction */
|
||||
|
|
@ -282,6 +280,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
|
|||
* @param array $params Parameters passed from Database::factory()
|
||||
*/
|
||||
public function __construct( array $params ) {
|
||||
$this->transactionManager = new TransactionManager();
|
||||
$this->connectionParams = [
|
||||
self::CONN_HOST => ( isset( $params['host'] ) && $params['host'] !== '' )
|
||||
? $params['host']
|
||||
|
|
@ -592,11 +591,17 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
|
|||
}
|
||||
|
||||
final public function trxLevel() {
|
||||
return ( $this->trxId != '' ) ? 1 : 0;
|
||||
// FIXME: A lot of tests disable constructor leading to trx manager being
|
||||
// null and breaking, this is unacceptable but hopefully this should
|
||||
// happen less by moving these functions to the transaction manager class.
|
||||
if ( !$this->transactionManager ) {
|
||||
$this->transactionManager = new TransactionManager();
|
||||
}
|
||||
return $this->transactionManager->trxLevel();
|
||||
}
|
||||
|
||||
public function trxTimestamp() {
|
||||
return $this->trxLevel() ? $this->trxTimestamp : null;
|
||||
return $this->transactionManager->trxTimestamp();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1441,7 +1446,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
|
|||
$this->trxProfiler->transactionWritingIn(
|
||||
$this->getServerName(),
|
||||
$this->getDomainID(),
|
||||
$this->trxId
|
||||
$this->transactionManager->getTrxId()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1497,7 +1502,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
|
|||
$startTime,
|
||||
$isPermWrite,
|
||||
$isPermWrite ? $this->affectedRows() : $numRows,
|
||||
$this->trxId,
|
||||
$this->transactionManager->getTrxId(),
|
||||
$this->getServerName()
|
||||
);
|
||||
|
||||
|
|
@ -1682,7 +1687,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
|
|||
// https://www.postgresql.org/docs/9.4/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS
|
||||
$this->sessionNamedLocks = [];
|
||||
// Session loss implies transaction loss
|
||||
$oldTrxId = $this->consumeTrxId();
|
||||
$oldTrxId = $this->transactionManager->consumeTrxId();
|
||||
$this->trxAtomicCounter = 0;
|
||||
$this->trxPostCommitOrIdleCallbacks = []; // T67263; transaction already lost
|
||||
$this->trxPreCommitOrIdleCallbacks = []; // T67263; transaction already lost
|
||||
|
|
@ -1719,18 +1724,6 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
|
|||
$this->runTransactionListenerCallbacks( self::TRIGGER_ROLLBACK );
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the application-side transaction ID and return the old one
|
||||
*
|
||||
* @return string The old transaction ID or an empty string if there wasn't one
|
||||
*/
|
||||
private function consumeTrxId() {
|
||||
$old = $this->trxId;
|
||||
$this->trxId = '';
|
||||
|
||||
return $old;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the cause of the error is detected to be a timeout.
|
||||
*
|
||||
|
|
@ -4901,13 +4894,11 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
|
|||
$this->completeCriticalSection( __METHOD__, $cs );
|
||||
throw $e;
|
||||
}
|
||||
static $nextTrxId;
|
||||
$nextTrxId = ( $nextTrxId !== null ? $nextTrxId++ : mt_rand() ) % 0xffff;
|
||||
$this->trxId = sprintf( '%06x', mt_rand( 0, 0xffffff ) ) . sprintf( '%04x', $nextTrxId );
|
||||
$this->transactionManager->newTrxId();
|
||||
$this->trxStatus = self::STATUS_TRX_OK;
|
||||
$this->trxStatusIgnoredCause = null;
|
||||
$this->trxAtomicCounter = 0;
|
||||
$this->trxTimestamp = microtime( true );
|
||||
$this->transactionManager->setTrxTimestamp( microtime( true ) );
|
||||
$this->trxFname = $fname;
|
||||
$this->trxDoneWrites = false;
|
||||
$this->trxAutomaticAtomic = false;
|
||||
|
|
@ -4994,7 +4985,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
|
|||
$this->completeCriticalSection( __METHOD__, $cs );
|
||||
throw $e;
|
||||
}
|
||||
$oldTrxId = $this->consumeTrxId();
|
||||
$oldTrxId = $this->transactionManager->consumeTrxId();
|
||||
$this->trxStatus = self::STATUS_TRX_NONE;
|
||||
if ( $this->trxDoneWrites ) {
|
||||
$this->lastWriteTime = microtime( true );
|
||||
|
|
@ -5053,7 +5044,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
|
|||
|
||||
$cs = $this->commenceCriticalSection( __METHOD__ );
|
||||
$this->doRollback( $fname );
|
||||
$oldTrxId = $this->consumeTrxId();
|
||||
$oldTrxId = $this->transactionManager->consumeTrxId();
|
||||
$this->trxStatus = self::STATUS_TRX_NONE;
|
||||
$this->trxAtomicLevels = [];
|
||||
// Clear callbacks that depend on transaction or transaction round commit
|
||||
|
|
|
|||
80
includes/libs/rdbms/database/TransactionManager.php
Normal file
80
includes/libs/rdbms/database/TransactionManager.php
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
/**
|
||||
* This file deals with database interface functions
|
||||
* and query specifics/optimisations.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* @file
|
||||
*/
|
||||
namespace Wikimedia\Rdbms;
|
||||
|
||||
/**
|
||||
* @ingroup Database
|
||||
* @internal
|
||||
*/
|
||||
class TransactionManager {
|
||||
/** @var string Application-side ID of the active transaction or an empty string otherwise */
|
||||
private $trxId = '';
|
||||
/** @var float|null UNIX timestamp at the time of BEGIN for the last transaction */
|
||||
private $trxTimestamp = null;
|
||||
|
||||
public function trxLevel() {
|
||||
return ( $this->trxId != '' ) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: This should be removed once all usages have been migrated here
|
||||
* @return string
|
||||
*/
|
||||
public function getTrxId(): string {
|
||||
return $this->trxId;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: This should be removed once all usages have been migrated here
|
||||
*/
|
||||
public function newTrxId() {
|
||||
static $nextTrxId;
|
||||
$nextTrxId = ( $nextTrxId !== null ? $nextTrxId++ : mt_rand() ) % 0xffff;
|
||||
$this->trxId = sprintf( '%06x', mt_rand( 0, 0xffffff ) ) . sprintf( '%04x', $nextTrxId );
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the application-side transaction ID and return the old one
|
||||
* This will become private soon.
|
||||
* @return string The old transaction ID or an empty string if there wasn't one
|
||||
*/
|
||||
public function consumeTrxId() {
|
||||
$old = $this->trxId;
|
||||
$this->trxId = '';
|
||||
|
||||
return $old;
|
||||
}
|
||||
|
||||
public function trxTimestamp(): ?float {
|
||||
return $this->trxLevel() ? $this->trxTimestamp : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float|null $trxTimestamp
|
||||
* @unstable This will be removed once usages are migrated here
|
||||
*/
|
||||
public function setTrxTimestamp( ?float $trxTimestamp ) {
|
||||
$this->trxTimestamp = $trxTimestamp;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in a new issue