From 0dd19856b044cfc19697327575dda1f732ac3ab1 Mon Sep 17 00:00:00 2001 From: Aaron Schulz Date: Mon, 19 Sep 2016 14:15:05 -0700 Subject: [PATCH] Avoid TransactionProfiler notices for TEMPORARY table writes * Make Database detect and track temporary tables for the session. Creating, dropping, and updating them do not count as "write" queries. Even a read-only mysql slave can have these operations performed on it and it can be useful for complex read queries that need temporary results. * Rename handleTransactionLoss() to handleSessionLoss() and cover named locks too. Bug: T145947 Change-Id: I826439e9e9f550f32a9c46b3dd60e8e8015aa274 --- includes/libs/rdbms/database/Database.php | 41 ++++++++++++++++++++--- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/includes/libs/rdbms/database/Database.php b/includes/libs/rdbms/database/Database.php index f9e9296b62..538d0b85bd 100644 --- a/includes/libs/rdbms/database/Database.php +++ b/includes/libs/rdbms/database/Database.php @@ -203,6 +203,8 @@ abstract class Database implements IDatabase, LoggerAwareInterface { /** @var array Map of (name => 1) for locks obtained via lock() */ private $mNamedLocksHeld = []; + /** @var array Map of (table name => 1) for TEMPORARY tables */ + private $mSessionTempTables = []; /** @var IDatabase|null Lazy handle to the master DB this server replicates from */ private $lazyMasterHandle; @@ -772,11 +774,40 @@ abstract class Database implements IDatabase, LoggerAwareInterface { return !in_array( $verb, [ 'BEGIN', 'COMMIT', 'ROLLBACK', 'SHOW', 'SET' ], true ); } + /** + * @param string $sql A SQL query + * @return bool Whether $sql is SQL for creating/dropping a new TEMPORARY table + */ + protected function registerTempTableOperation( $sql ) { + if ( preg_match( + '/^(CREATE|DROP)\s+TEMPORARY\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?[`"\']?(\w+)[`"\']?/i', + $sql, + $matches + ) ) { + list( , $verb, $table ) = $matches; + if ( $verb === 'CREATE' ) { + $this->mSessionTempTables[$table] = 1; + } else { + unset( $this->mSessionTempTables[$table] ); + } + + return true; + } elseif ( preg_match( + '/^(?:INSERT\s+(?:\w+\s+)?INTO|UPDATE|DELETE\s+FROM)\s+[`"\']?(\w+)[`"\']?/i', + $sql, + $matches + ) ) { + return isset( $this->mSessionTempTables[$matches[1]] ); + } + + return false; + } + public function query( $sql, $fname = __METHOD__, $tempIgnore = false ) { $priorWritesPending = $this->writesOrCallbacksPending(); $this->mLastQuery = $sql; - $isWrite = $this->isWriteQuery( $sql ); + $isWrite = $this->isWriteQuery( $sql ) && !$this->registerTempTableOperation( $sql ); if ( $isWrite ) { $reason = $this->getReadOnlyReason(); if ( $reason !== false ) { @@ -822,7 +853,7 @@ abstract class Database implements IDatabase, LoggerAwareInterface { $lastError = $this->lastError(); $lastErrno = $this->lastErrno(); # Update state tracking to reflect transaction loss due to disconnection - $this->handleTransactionLoss(); + $this->handleSessionLoss(); if ( $this->reconnect() ) { $msg = __METHOD__ . ": lost connection to {$this->getServer()}; reconnected"; $this->connLogger->warning( $msg ); @@ -851,7 +882,7 @@ abstract class Database implements IDatabase, LoggerAwareInterface { $tempIgnore = false; // not recoverable } # Update state tracking to reflect transaction loss - $this->handleTransactionLoss(); + $this->handleSessionLoss(); } $this->reportQueryError( @@ -964,10 +995,12 @@ abstract class Database implements IDatabase, LoggerAwareInterface { return true; } - private function handleTransactionLoss() { + private function handleSessionLoss() { $this->mTrxLevel = 0; $this->mTrxIdleCallbacks = []; // bug 65263 $this->mTrxPreCommitCallbacks = []; // bug 65263 + $this->mSessionTempTables = []; + $this->mNamedLocksHeld = []; try { // Handle callbacks in mTrxEndCallbacks $this->runOnTransactionIdleCallbacks( self::TRIGGER_ROLLBACK ); -- 2.20.1