X-Git-Url: http://git.cyclocoop.org/%7B%24www_url%7Dadmin/compta/operations/recherche.php?a=blobdiff_plain;f=includes%2Flibs%2Frdbms%2Fdatabase%2FDatabaseMysqlBase.php;h=b079eb0e0d97fc4d7476ae1f56f297cd7a61f490;hb=9ce9f5c4e4b0279a61988e066099d2e2ac2e89cf;hp=a5220b9a2e7a3501f94f0a14b611e8a0406af6bf;hpb=6e65e0ab0d0dc5e7e0ea000f024a3481da35505b;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/libs/rdbms/database/DatabaseMysqlBase.php b/includes/libs/rdbms/database/DatabaseMysqlBase.php index a5220b9a2e..b079eb0e0d 100644 --- a/includes/libs/rdbms/database/DatabaseMysqlBase.php +++ b/includes/libs/rdbms/database/DatabaseMysqlBase.php @@ -70,6 +70,12 @@ abstract class DatabaseMysqlBase extends Database { /** @var stdClass|null */ private $replicationInfoRow = null; + // 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). @@ -558,17 +564,24 @@ abstract class DatabaseMysqlBase extends Database { * Takes same arguments as Database::select() * * @param string|array $table - * @param string|array $vars + * @param string|array $var * @param string|array $conds * @param string $fname * @param string|array $options + * @param array $join_conds * @return bool|int */ - public function estimateRowCount( $table, $vars = '*', $conds = '', - $fname = __METHOD__, $options = [] + public function estimateRowCount( $table, $var = '*', $conds = '', + $fname = __METHOD__, $options = [], $join_conds = [] ) { + $conds = $this->normalizeConditions( $conds, $fname ); + $column = $this->extractSingleFieldFromList( $var ); + if ( is_string( $column ) && !in_array( $column, [ '*', '1' ] ) ) { + $conds[] = "$column IS NOT NULL"; + } + $options['EXPLAIN'] = true; - $res = $this->select( $table, $vars, $conds, $fname, $options ); + $res = $this->select( $table, $var, $conds, $fname, $options, $join_conds ); if ( $res === false ) { return false; } @@ -739,6 +752,7 @@ abstract class DatabaseMysqlBase extends Database { protected function getLagFromSlaveStatus() { $res = $this->query( 'SHOW SLAVE STATUS', __METHOD__ ); $row = $res ? $res->fetchObject() : false; + // If the server is not replicating, there will be no row if ( $row && strval( $row->Seconds_Behind_Master ) !== '' ) { return intval( $row->Seconds_Behind_Master ); } @@ -752,6 +766,20 @@ abstract class DatabaseMysqlBase extends Database { protected function getLagFromPtHeartbeat() { $options = $this->lagDetectionOptions; + $staleness = $this->trxLevel + ? microtime( true ) - $this->trxTimestamp() + : 0; + 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__ ] ) + ); + + return $this->getTransactionLagStatus()['lag']; + } + if ( isset( $options['conds'] ) ) { // Best method for multi-DC setups: use logical channel names $data = $this->getHeartbeatData( $options['conds'] ); @@ -846,7 +874,8 @@ abstract class DatabaseMysqlBase extends Database { // Note: this would use "TIMESTAMPDIFF(MICROSECOND,ts,UTC_TIMESTAMP(6))" but the // percision field is not supported in MySQL <= 5.5. $res = $this->query( - "SELECT ts FROM heartbeat.heartbeat WHERE $whereSQL ORDER BY ts DESC LIMIT 1" + "SELECT ts FROM heartbeat.heartbeat WHERE $whereSQL ORDER BY ts DESC LIMIT 1", + __METHOD__ ); $row = $res ? $res->fetchObject() : false; } finally { @@ -891,6 +920,13 @@ abstract class DatabaseMysqlBase extends Database { $rpos = $this->getReplicaPos(); $gtidsWait = $rpos ? MySQLMasterPos::getCommonDomainGTIDs( $pos, $rpos ) : []; if ( !$gtidsWait ) { + $this->queryLogger->error( + "No GTIDs with the same domain between master ($pos) and replica ($rpos)", + $this->getLogContext( [ + 'method' => __METHOD__, + ] ) + ); + return -1; // $pos is from the wrong cluster? } // Wait on the GTID set (MariaDB only) @@ -1281,10 +1317,6 @@ abstract class DatabaseMysqlBase extends Database { return $this->lastErrno() == 1205; } - public function wasErrorReissuable() { - return $this->lastErrno() == 2013 || $this->lastErrno() == 2006; - } - /** * Determines if the last failure was due to the database being read-only. * @@ -1418,44 +1450,19 @@ abstract class DatabaseMysqlBase extends Database { return in_array( $name, $this->listViews( $prefix ) ); } + protected function isTransactableQuery( $sql ) { + return parent::isTransactableQuery( $sql ) && + !preg_match( '/^SELECT\s+(GET|RELEASE|IS_FREE)_LOCK\(/', $sql ); + } + /** - * Allows for index remapping in queries where this is not consistent across DBMS - * - * @param string $index + * @param string $field Field or column to cast * @return string */ - protected function indexName( $index ) { - /** - * When SQLite indexes were introduced in r45764, it was noted that - * SQLite requires index names to be unique within the whole database, - * not just within a schema. As discussed in CR r45819, to avoid the - * need for a schema change on existing installations, the indexes - * were implicitly mapped from the new names to the old names. - * - * This mapping can be removed if DB patches are introduced to alter - * the relevant tables in existing installations. Note that because - * this index mapping applies to table creation, even new installations - * of MySQL have the old names (except for installations created during - * a period where this mapping was inappropriately removed, see - * T154872). - */ - $renamed = [ - 'ar_usertext_timestamp' => 'usertext_timestamp', - 'un_user_id' => 'user_id', - 'un_user_ip' => 'user_ip', - ]; - - if ( isset( $renamed[$index] ) ) { - return $renamed[$index]; - } else { - return $index; - } + public function buildIntegerCast( $field ) { + return 'CAST( ' . $field . ' AS SIGNED )'; } - protected function isTransactableQuery( $sql ) { - return parent::isTransactableQuery( $sql ) && - !preg_match( '/^SELECT\s+(GET|RELEASE|IS_FREE)_LOCK\(/', $sql ); - } } class_alias( DatabaseMysqlBase::class, 'DatabaseMysqlBase' );