Merge "Test ApiUserrights"
[lhc/web/wiklou.git] / includes / libs / rdbms / database / DatabaseMysqlBase.php
index b0fcade..3e6190c 100644 (file)
@@ -73,6 +73,9 @@ abstract class DatabaseMysqlBase extends Database {
        // Cache getServerId() for 24 hours
        const SERVER_ID_CACHE_TTL = 86400;
 
+       /** @var float Warn if lag estimates are made for transactions older than this many seconds */
+       const LAG_STALE_WARN_THRESHOLD = 0.100;
+
        /**
         * Additional $params include:
         *   - lagDetectionMethod : set to one of (Seconds_Behind_Master,pt-heartbeat).
@@ -317,7 +320,7 @@ abstract class DatabaseMysqlBase extends Database {
        abstract protected function mysqlFetchObject( $res );
 
        /**
-        * @param ResultWrapper|resource $res
+        * @param IResultWrapper|resource $res
         * @return array|bool
         * @throws DBUnexpectedError
         */
@@ -763,6 +766,22 @@ abstract class DatabaseMysqlBase extends Database {
        protected function getLagFromPtHeartbeat() {
                $options = $this->lagDetectionOptions;
 
+               $currentTrxInfo = $this->getRecordedTransactionLagStatus();
+               if ( $currentTrxInfo ) {
+                       // There is an active transaction and the initial lag was already queried
+                       $staleness = microtime( true ) - $currentTrxInfo['since'];
+                       if ( $staleness > self::LAG_STALE_WARN_THRESHOLD ) {
+                               // Avoid returning higher and higher lag value due to snapshot age
+                               // given that the isolation level will typically be REPEATABLE-READ
+                               $this->queryLogger->warning(
+                                       "Using cached lag value for {db_server} due to active transaction",
+                                       $this->getLogContext( [ 'method' => __METHOD__, 'age' => $staleness ] )
+                               );
+                       }
+
+                       return $currentTrxInfo['lag'];
+               }
+
                if ( isset( $options['conds'] ) ) {
                        // Best method for multi-DC setups: use logical channel names
                        $data = $this->getHeartbeatData( $options['conds'] );
@@ -967,8 +986,8 @@ abstract class DatabaseMysqlBase extends Database {
                if ( $this->useGTIDs() ) {
                        // Try to use GTIDs, fallbacking to binlog positions if not possible
                        $data = $this->getServerGTIDs( __METHOD__ );
-                       // Use gtid_current_pos for MariaDB and gtid_executed for MySQL
-                       foreach ( [ 'gtid_current_pos', 'gtid_executed' ] as $name ) {
+                       // Use gtid_slave_pos for MariaDB and gtid_executed for MySQL
+                       foreach ( [ 'gtid_slave_pos', 'gtid_executed' ] as $name ) {
                                if ( isset( $data[$name] ) && strlen( $data[$name] ) ) {
                                        return new MySQLMasterPos( $data[$name], $now );
                                }
@@ -998,8 +1017,8 @@ abstract class DatabaseMysqlBase extends Database {
                if ( $this->useGTIDs() ) {
                        // Try to use GTIDs, fallbacking to binlog positions if not possible
                        $data = $this->getServerGTIDs( __METHOD__ );
-                       // Use gtid_current_pos for MariaDB and gtid_executed for MySQL
-                       foreach ( [ 'gtid_current_pos', 'gtid_executed' ] as $name ) {
+                       // Use gtid_binlog_pos for MariaDB and gtid_executed for MySQL
+                       foreach ( [ 'gtid_binlog_pos', 'gtid_executed' ] as $name ) {
                                if ( isset( $data[$name] ) && strlen( $data[$name] ) ) {
                                        $pos = new MySQLMasterPos( $data[$name], $now );
                                        break;
@@ -1395,6 +1414,26 @@ abstract class DatabaseMysqlBase extends Database {
                return $errno == 2013 || $errno == 2006;
        }
 
+       protected function wasKnownStatementRollbackError() {
+               $errno = $this->lastErrno();
+
+               if ( $errno === 1205 ) { // lock wait timeout
+                       // Note that this is uncached to avoid stale values of SET is used
+                       $row = $this->selectRow(
+                               false,
+                               [ 'innodb_rollback_on_timeout' => '@@innodb_rollback_on_timeout' ],
+                               [],
+                               __METHOD__
+                       );
+                       // https://dev.mysql.com/doc/refman/5.7/en/innodb-error-handling.html
+                       // https://dev.mysql.com/doc/refman/5.5/en/innodb-parameters.html
+                       return $row->innodb_rollback_on_timeout ? false : true;
+               }
+
+               // See https://dev.mysql.com/doc/refman/5.5/en/error-messages-server.html
+               return in_array( $errno, [ 1022, 1216, 1217, 1137 ], true );
+       }
+
        /**
         * @param string $oldName
         * @param string $newName