From: jenkins-bot Date: Fri, 2 Mar 2018 19:26:49 +0000 (+0000) Subject: Merge "rdbms: make LoadBalancer::getConnection() ignore CONN_TRX_AUTO when unusable" X-Git-Tag: 1.31.0-rc.0~460 X-Git-Url: http://git.cyclocoop.org/%7B%24www_url%7Dadmin/compta/exercices/supprimer.php?a=commitdiff_plain;h=52ced406061caadb6014300d993e1a20dfa017ba;hp=-c;p=lhc%2Fweb%2Fwiklou.git Merge "rdbms: make LoadBalancer::getConnection() ignore CONN_TRX_AUTO when unusable" --- 52ced406061caadb6014300d993e1a20dfa017ba diff --combined includes/libs/rdbms/database/Database.php index b8c15be9bf,c699374c7f..8ccccc34d1 --- a/includes/libs/rdbms/database/Database.php +++ b/includes/libs/rdbms/database/Database.php @@@ -59,6 -59,9 +59,9 @@@ abstract class Database implements IDat const SLOW_WRITE_SEC = 0.500; const SMALL_WRITE_ROWS = 100; + /** @var string Whether lock granularity is on the level of the entire database */ + const ATTR_DB_LEVEL_LOCKING = 'db-level-locking'; + /** @var string SQL query */ protected $lastQuery = ''; /** @var float|bool UNIX timestamp of last write query */ @@@ -385,6 -388,21 +388,21 @@@ return $conn; } + /** + * @param string $dbType A possible DB type (sqlite, mysql, postgres,...) + * @param string|null $driver Optional name of a specific DB client driver + * @return array Map of (Database::ATTRIBUTE_* constant => value) for all such constants + * @throws InvalidArgumentException + * @since 1.31 + */ + final public static function attributesFromType( $dbType, $driver = null ) { + static $defaults = [ self::ATTR_DB_LEVEL_LOCKING => false ]; + + $class = self::getClass( $dbType, $driver ); + + return call_user_func( [ $class, 'getAttributes' ] ) + $defaults; + } + /** * @param string $dbType A possible DB type (sqlite, mysql, postgres,...) * @param string|null $driver Optional name of a specific DB client driver @@@ -441,6 -459,14 +459,14 @@@ return $class; } + /** + * @return array Map of (Database::ATTRIBUTE_* constant => value + * @since 1.31 + */ + protected static function getAttributes() { + return []; + } + /** * Set the PSR-3 logger interface to use for query logging. (The logger * interfaces for connection logging and error logging can be set with the @@@ -1435,27 -1461,14 +1461,27 @@@ list( $startOpts, $useIndex, $preLimitTail, $postLimitTail, $ignoreIndex ) = $this->makeSelectOptions( $options ); - if ( !empty( $conds ) ) { - if ( is_array( $conds ) ) { - $conds = $this->makeList( $conds, self::LIST_AND ); - } + if ( is_array( $conds ) ) { + $conds = $this->makeList( $conds, self::LIST_AND ); + } + + if ( $conds === null || $conds === false ) { + $this->queryLogger->warning( + __METHOD__ + . ' called from ' + . $fname + . ' with incorrect parameters: $conds must be a string or an array' + ); + $conds = ''; + } + + if ( $conds === '' ) { + $sql = "SELECT $startOpts $vars $from $useIndex $ignoreIndex $preLimitTail"; + } elseif ( is_string( $conds ) ) { $sql = "SELECT $startOpts $vars $from $useIndex $ignoreIndex " . "WHERE $conds $preLimitTail"; } else { - $sql = "SELECT $startOpts $vars $from $useIndex $ignoreIndex $preLimitTail"; + throw new DBUnexpectedError( $this, __METHOD__ . ' called with incorrect parameters' ); } if ( isset( $options['LIMIT'] ) ) { @@@ -2132,8 -2145,8 +2158,8 @@@ } // We can't separate explicit JOIN clauses with ',', use ' ' for those - $implicitJoins = !empty( $ret ) ? implode( ',', $ret ) : ""; - $explicitJoins = !empty( $retJOIN ) ? implode( ' ', $retJOIN ) : ""; + $implicitJoins = $ret ? implode( ',', $ret ) : ""; + $explicitJoins = $retJOIN ? implode( ' ', $retJOIN ) : ""; // Compile our final table clause return implode( ' ', [ $implicitJoins, $explicitJoins ] ); @@@ -2279,8 -2292,11 +2305,8 @@@ $rows = [ $rows ]; } - $useTrx = !$this->trxLevel; - if ( $useTrx ) { - $this->begin( $fname, self::TRANSACTION_INTERNAL ); - } try { + $this->startAtomic( $fname ); $affectedRowCount = 0; foreach ( $rows as $row ) { // Delete rows which collide with this one @@@ -2313,12 -2329,17 +2339,12 @@@ $this->insert( $table, $row, $fname ); $affectedRowCount += $this->affectedRows(); } + $this->endAtomic( $fname ); + $this->affectedRowCount = $affectedRowCount; } catch ( Exception $e ) { - if ( $useTrx ) { - $this->rollback( $fname, self::FLUSHING_INTERNAL ); - } + $this->rollback( $fname, self::FLUSHING_INTERNAL ); throw $e; } - if ( $useTrx ) { - $this->commit( $fname, self::FLUSHING_INTERNAL ); - } - - $this->affectedRowCount = $affectedRowCount; } /** @@@ -2384,8 -2405,11 +2410,8 @@@ } $affectedRowCount = 0; - $useTrx = !$this->trxLevel; - if ( $useTrx ) { - $this->begin( $fname, self::TRANSACTION_INTERNAL ); - } try { + $this->startAtomic( $fname ); # Update any existing conflicting row(s) if ( $where !== false ) { $ok = $this->update( $table, $set, $where, $fname ); @@@ -2396,12 -2420,16 +2422,12 @@@ # Now insert any non-conflicting row(s) $ok = $this->insert( $table, $rows, $fname, [ 'IGNORE' ] ) && $ok; $affectedRowCount += $this->affectedRows(); + $this->endAtomic( $fname ); + $this->affectedRowCount = $affectedRowCount; } catch ( Exception $e ) { - if ( $useTrx ) { - $this->rollback( $fname, self::FLUSHING_INTERNAL ); - } + $this->rollback( $fname, self::FLUSHING_INTERNAL ); throw $e; } - if ( $useTrx ) { - $this->commit( $fname, self::FLUSHING_INTERNAL ); - } - $this->affectedRowCount = $affectedRowCount; return $ok; } @@@ -2459,16 -2487,11 +2485,16 @@@ return $this->query( $sql, $fname ); } - public function insertSelect( + final public function insertSelect( $destTable, $srcTable, $varMap, $conds, $fname = __METHOD__, $insertOptions = [], $selectOptions = [], $selectJoinConds = [] ) { - if ( $this->cliMode ) { + static $hints = [ 'NO_AUTO_COLUMNS' ]; + + $insertOptions = (array)$insertOptions; + $selectOptions = (array)$selectOptions; + + if ( $this->cliMode && $this->isInsertSelectSafe( $insertOptions, $selectOptions ) ) { // For massive migrations with downtime, we don't want to select everything // into memory and OOM, so do all this native on the server side if possible. return $this->nativeInsertSelect( @@@ -2477,7 -2500,7 +2503,7 @@@ $varMap, $conds, $fname, - $insertOptions, + array_diff( $insertOptions, $hints ), $selectOptions, $selectJoinConds ); @@@ -2489,22 -2512,12 +2515,22 @@@ $varMap, $conds, $fname, - $insertOptions, + array_diff( $insertOptions, $hints ), $selectOptions, $selectJoinConds ); } + /** + * @param array $insertOptions INSERT options + * @param array $selectOptions SELECT options + * @return bool Whether an INSERT SELECT with these options will be replication safe + * @since 1.31 + */ + protected function isInsertSelectSafe( array $insertOptions, array $selectOptions ) { + return true; + } + /** * Implementation of insertSelect() based on select() and insert() * @@@ -2524,6 -2537,8 +2550,6 @@@ $fname = __METHOD__, $insertOptions = [], $selectOptions = [], $selectJoinConds = [] ) { - $insertOptions = array_diff( (array)$insertOptions, [ 'NO_AUTO_COLUMNS' ] ); - // For web requests, do a locking SELECT and then INSERT. This puts the SELECT burden // on only the master (without needing row-based-replication). It also makes it easy to // know how big the INSERT is going to be. @@@ -2568,10 -2583,12 +2594,10 @@@ $this->affectedRowCount = $affectedRowCount; } else { $this->rollback( $fname, self::FLUSHING_INTERNAL ); - $this->affectedRowCount = 0; } return $ok; } catch ( Exception $e ) { $this->rollback( $fname, self::FLUSHING_INTERNAL ); - $this->affectedRowCount = 0; throw $e; } } @@@ -2600,6 -2617,7 +2626,6 @@@ if ( !is_array( $insertOptions ) ) { $insertOptions = [ $insertOptions ]; } - $insertOptions = array_diff( (array)$insertOptions, [ 'NO_AUTO_COLUMNS' ] ); $insertOptions = $this->makeInsertOptions( $insertOptions ); @@@ -3202,8 -3220,6 +3228,8 @@@ } catch ( Exception $e ) { // already logged; let LoadBalancer move on during mass-rollback } + + $this->affectedRowCount = 0; // for the sake of consistency } /**