X-Git-Url: https://git.heureux-cyclage.org/?p=lhc%2Fweb%2Fwiklou.git;a=blobdiff_plain;f=includes%2Flibs%2Frdbms%2Fdatabase%2FDatabase.php;h=5f59f348227da9ef3e54b9aaefbf875c2d7da645;hp=084500ac8e1297561f46ddf313182a479581dd7e;hb=88e3a888cc6823f11df79ac53eb963a7e4d2871a;hpb=c1d51d0c703a61010eb8cc73207e8a074d8c8e2e diff --git a/includes/libs/rdbms/database/Database.php b/includes/libs/rdbms/database/Database.php index 084500ac8e..5f59f34822 100644 --- a/includes/libs/rdbms/database/Database.php +++ b/includes/libs/rdbms/database/Database.php @@ -174,6 +174,9 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware /** @var float Query rount trip time estimate */ private $lastRoundTripEstimate = 0.0; + /** @var int|null Integer ID of the managing LBFactory instance or null if none */ + private $ownerId; + /** @var string Lock granularity is on the level of the entire database */ const ATTR_DB_LEVEL_LOCKING = 'db-level-locking'; /** @var string The SCHEMA keyword refers to a grouping of tables in a database */ @@ -268,6 +271,8 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware $params['schema'] != '' ? $params['schema'] : null, $params['tablePrefix'] ); + + $this->ownerId = $params['ownerId'] ?? null; } /** @@ -355,7 +360,8 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware * - cliMode: Whether to consider the execution context that of a CLI script. * - agent: Optional name used to identify the end-user in query profiling/logging. * - srvCache: Optional BagOStuff instance to an APC-style cache. - * - nonNativeInsertSelectBatchSize: Optional batch size for non-native INSERT SELECT emulation. + * - nonNativeInsertSelectBatchSize: Optional batch size for non-native INSERT SELECT. + * - ownerId: Optional integer ID of a LoadBalancer instance that manages this instance. * @param int $connect One of the class constants (NEW_CONNECTED, NEW_UNCONNECTED) [optional] * @return Database|null If the database driver or extension cannot be found * @throws InvalidArgumentException If the database driver or extension cannot be found @@ -375,7 +381,8 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware 'flags' => 0, 'variables' => [], 'cliMode' => ( PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg' ), - 'agent' => basename( $_SERVER['SCRIPT_NAME'] ) . '@' . gethostname() + 'agent' => basename( $_SERVER['SCRIPT_NAME'] ) . '@' . gethostname(), + 'ownerId' => null ]; $normalizedParams = [ @@ -866,8 +873,8 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware ); } - final public function close() { - $exception = null; // error to throw after disconnecting + final public function close( $fname = __METHOD__, $owner = null ) { + $error = null; // error to throw after disconnecting $wasOpen = (bool)$this->conn; // This should mostly do nothing if the connection is already closed @@ -877,34 +884,22 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware if ( $this->trxAtomicLevels ) { // Cannot let incomplete atomic sections be committed $levels = $this->flatAtomicSectionList(); - $exception = new DBUnexpectedError( - $this, - __METHOD__ . ": atomic sections $levels are still open" - ); + $error = "$fname: atomic sections $levels are still open"; } elseif ( $this->trxAutomatic ) { // Only the connection manager can commit non-empty DBO_TRX transactions // (empty ones we can silently roll back) if ( $this->writesOrCallbacksPending() ) { - $exception = new DBUnexpectedError( - $this, - __METHOD__ . - ": mass commit/rollback of peer transaction required (DBO_TRX set)" - ); + $error = "$fname: " . + "expected mass rollback of all peer transactions (DBO_TRX set)"; } } else { // Manual transactions should have been committed or rolled // back, even if empty. - $exception = new DBUnexpectedError( - $this, - __METHOD__ . ": transaction is still open (from {$this->trxFname})" - ); + $error = "$fname: transaction is still open (from {$this->trxFname})"; } - if ( $this->trxEndCallbacksSuppressed ) { - $exception = $exception ?: new DBUnexpectedError( - $this, - __METHOD__ . ': callbacks are suppressed; cannot properly commit' - ); + if ( $this->trxEndCallbacksSuppressed && $error === null ) { + $error = "$fname: callbacks are suppressed; cannot properly commit"; } // Rollback the changes and run any callbacks as needed @@ -919,9 +914,16 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware $this->conn = null; - // Throw any unexpected errors after having disconnected - if ( $exception instanceof Exception ) { - throw $exception; + // Log or throw any unexpected errors after having disconnected + if ( $error !== null ) { + // T217819, T231443: if this is probably just LoadBalancer trying to recover from + // errors and shutdown, then log any problems and move on since the request has to + // end one way or another. Throwing errors is not very useful at some point. + if ( $this->ownerId !== null && $owner === $this->ownerId ) { + $this->queryLogger->error( $error ); + } else { + throw new DBUnexpectedError( $this, $error ); + } } // Note that various subclasses call close() at the start of open(), which itself is @@ -1332,10 +1334,11 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware // Avoid the overhead of logging calls unless debug mode is enabled if ( $this->getFlag( self::DBO_DEBUG ) ) { $this->queryLogger->debug( - "{method} [{runtime}s] {db_host}: $sql", + "{method} [{runtime}s] {db_host}: {sql}", [ 'method' => $fname, 'db_host' => $this->getServer(), + 'sql' => $sql, 'domain' => $this->getDomainID(), 'runtime' => round( $queryRuntime, 3 ) ] @@ -1487,6 +1490,8 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware $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( @@ -1499,6 +1504,13 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware } } + /** + * Reset any additional subclass trx* and session* fields + */ + protected function doHandleSessionLossPreconnect() { + // no-op + } + /** * Clean things up after session (and thus transaction) loss after reconnect */ @@ -1672,12 +1684,13 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware * Returns an optional USE INDEX clause to go after the table, and a * string to go at the end of the query. * + * @see Database::select() + * * @param array $options Associative array of options to be turned into * an SQL query, valid keys are listed in the function. * @return array - * @see Database::select() */ - protected function makeSelectOptions( $options ) { + protected function makeSelectOptions( array $options ) { $preLimitTail = $postLimitTail = ''; $startOpts = ''; @@ -3522,7 +3535,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware if ( in_array( $entry[2], $sectionIds, true ) ) { $callback = $entry[0]; $this->trxEndCallbacks[$key][0] = function () use ( $callback ) { - // @phan-suppress-next-line PhanInfiniteRecursion No recursion at all here, phan is confused + // @phan-suppress-next-line PhanInfiniteRecursion, PhanUndeclaredInvokeInCallable return $callback( self::TRIGGER_ROLLBACK, $this ); }; // This "on resolution" callback no longer belongs to a section. @@ -3647,6 +3660,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware try { ++$count; list( $phpCallback ) = $callback; + // @phan-suppress-next-line PhanUndeclaredInvokeInCallable $phpCallback( $this ); } catch ( Exception $ex ) { ( $this->errorLogger )( $ex ); @@ -3682,6 +3696,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware foreach ( $callbacks as $entry ) { if ( $sectionIds === null || in_array( $entry[2], $sectionIds, true ) ) { try { + // @phan-suppress-next-line PhanUndeclaredInvokeInCallable $entry[0]( $trigger, $this ); } catch ( Exception $ex ) { ( $this->errorLogger )( $ex ); @@ -3969,17 +3984,17 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware if ( $this->trxLevel() ) { if ( $this->trxAtomicLevels ) { $levels = $this->flatAtomicSectionList(); - $msg = "$fname: Got explicit BEGIN while atomic section(s) $levels are open"; + $msg = "$fname: got explicit BEGIN while atomic section(s) $levels are open"; throw new DBUnexpectedError( $this, $msg ); } elseif ( !$this->trxAutomatic ) { - $msg = "$fname: Explicit transaction already active (from {$this->trxFname})"; + $msg = "$fname: explicit transaction already active (from {$this->trxFname})"; throw new DBUnexpectedError( $this, $msg ); } else { - $msg = "$fname: Implicit transaction already active (from {$this->trxFname})"; + $msg = "$fname: implicit transaction already active (from {$this->trxFname})"; throw new DBUnexpectedError( $this, $msg ); } } elseif ( $this->getFlag( self::DBO_TRX ) && $mode !== self::TRANSACTION_INTERNAL ) { - $msg = "$fname: Implicit transaction expected (DBO_TRX set)"; + $msg = "$fname: implicit transaction expected (DBO_TRX set)"; throw new DBUnexpectedError( $this, $msg ); } @@ -4033,7 +4048,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware $levels = $this->flatAtomicSectionList(); throw new DBUnexpectedError( $this, - "$fname: Got COMMIT while atomic sections $levels are still open" + "$fname: got COMMIT while atomic sections $levels are still open" ); } @@ -4043,17 +4058,17 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware } elseif ( !$this->trxAutomatic ) { throw new DBUnexpectedError( $this, - "$fname: Flushing an explicit transaction, getting out of sync" + "$fname: flushing an explicit transaction, getting out of sync" ); } } elseif ( !$this->trxLevel() ) { $this->queryLogger->error( - "$fname: No transaction to commit, something got out of sync" ); + "$fname: no transaction to commit, something got out of sync" ); return; // nothing to do } elseif ( $this->trxAutomatic ) { throw new DBUnexpectedError( $this, - "$fname: Expected mass commit of all peer transactions (DBO_TRX set)" + "$fname: expected mass commit of all peer transactions (DBO_TRX set)" ); }