$this->trxAtomicCounter = 0;
$this->trxIdleCallbacks = []; // T67263; transaction already lost
$this->trxPreCommitCallbacks = []; // T67263; transaction already lost
+ // Clear additional subclass fields
+ $this->doHandleSessionLossPreconnect();
// @note: leave trxRecurringCallbacks in place
if ( $this->trxDoneWrites ) {
$this->trxProfiler->transactionWritingOut(
}
}
+ /**
+ * Reset any additional subclass trx* and session* fields
+ */
+ protected function doHandleSessionLossPreconnect() {
+ // no-op
+ }
+
/**
* Clean things up after session (and thus transaction) loss after reconnect
*/
protected $lockMgr;
/** @var array List of shared database already attached to this connection */
- private $alreadyAttached = [];
+ private $sessionAttachedDbs = [];
/** @var string[] See https://www.sqlite.org/lang_transaction.html */
private static $VALID_TRX_MODES = [ '', 'DEFERRED', 'IMMEDIATE', 'EXCLUSIVE' ];
if ( in_array( $sync, [ 'EXTRA', 'FULL', 'NORMAL', 'OFF' ], true ) ) {
$this->query( "PRAGMA synchronous = $sync", __METHOD__, $flags );
}
+ $this->attachDatabasesFromTableAliases();
} catch ( Exception $e ) {
throw $this->newExceptionAfterConnectError( $e->getMessage() );
}
public function setTableAliases( array $aliases ) {
parent::setTableAliases( $aliases );
+ if ( $this->isOpen() ) {
+ $this->attachDatabasesFromTableAliases();
+ }
+ }
+
+ /**
+ * Issue ATTATCH statements for all unattached foreign DBs in table aliases
+ */
+ private function attachDatabasesFromTableAliases() {
foreach ( $this->tableAliases as $params ) {
- if ( isset( $this->alreadyAttached[$params['dbname']] ) ) {
- continue;
+ if (
+ $params['dbname'] !== $this->getDBname() &&
+ !isset( $this->sessionAttachedDbs[$params['dbname']] )
+ ) {
+ $this->attachDatabase( $params['dbname'] );
+ $this->sessionAttachedDbs[$params['dbname']] = true;
}
- $this->attachDatabase( $params['dbname'] );
- $this->alreadyAttached[$params['dbname']] = true;
}
}
return true;
}
+ protected function doHandleSessionLossPreconnect() {
+ $this->sessionAttachedDbs = [];
+ }
+
/**
* @return PDO
*/
$server['flags'] = $server['flags'] ?? IDatabase::DBO_DEFAULT;
// Create a live connection object
- try {
- $conn = Database::factory( $server['type'], $server );
- // Log when many connection are made on requests
- ++$this->connectionCounter;
- $currentConnCount = $this->getCurrentConnectionCount();
- if ( $currentConnCount >= self::CONN_HELD_WARN_THRESHOLD ) {
- $this->perfLogger->warning(
- __METHOD__ . ": {connections}+ connections made (master={masterdb})",
- [ 'connections' => $currentConnCount, 'masterdb' => $masterName ]
- );
- }
- } catch ( DBConnectionError $e ) {
- // FIXME: This is probably the ugliest thing I have ever done to
- // PHP. I'm half-expecting it to segfault, just out of disgust. -- TS
- $conn = $e->db;
- }
-
+ $conn = Database::factory( $server['type'], $server, Database::NEW_UNCONNECTED );
$conn->setLBInfo( $server );
$conn->setLazyMasterHandle(
$this->getLazyConnectionRef( self::DB_MASTER, [], $conn->getDomainID() )
$conn->setTableAliases( $this->tableAliases );
$conn->setIndexAliases( $this->indexAliases );
+ try {
+ $conn->initConnection();
+ ++$this->connectionCounter;
+ } catch ( DBConnectionError $e ) {
+ // ignore; let the DB handle the logging
+ }
+
if ( $server['serverIndex'] === $this->getWriterIndex() ) {
if ( $this->trxRoundId !== false ) {
$this->applyTransactionRoundFlags( $conn );
$this->lazyLoadReplicationPositions(); // session consistency
+ // Log when many connection are made on requests
+ $count = $this->getCurrentConnectionCount();
+ if ( $count >= self::CONN_HELD_WARN_THRESHOLD ) {
+ $this->perfLogger->warning(
+ __METHOD__ . ": {connections}+ connections made (master={masterdb})",
+ [
+ 'connections' => $count,
+ 'dbserver' => $conn->getServer(),
+ 'masterdb' => $conn->getLBInfo( 'clusterMasterHost' )
+ ]
+ );
+ }
+
return $conn;
}