Hello Krinkle, Hashar,

I'd like you to do a code review.  Please visit

    https://gerrit.wikimedia.org/r/289368

to review the following change.

Change subject: Make it TransactionProfiler's job to report query times to the 
profiler
......................................................................

Make it TransactionProfiler's job to report query times to the profiler

* Move DatabaseBase::generalizeSQL() -> TransactionProfiler::generalizeSQL()
* Only generalize SQL if we need to log the query (that is, if an expectation
  has been violated, or if a profiler is running.) This gets rid of a lot of
  pointless DatabaseBase::generalizeSQL() calls, especially in the unit tests.
* Use TransactionProfiler::reportExpectationViolated() to report maxAffected
  violations. Do this by making 'expectBy' optional.
* Make it TransactionProfiler's job to report the query to the Profiler 
instance.
  This required adding $isMaster and $id parameters to
  TransactionProfiler::reportExpectationViolated(), but it has no callers
  outside core, and there are already other methods on TransactionProfilers
  that take these parameters.

Change-Id: Ib927376a73cef8b51d8e97bf28e4766a399f29c4
---
M includes/db/Database.php
M includes/profiler/TransactionProfiler.php
2 files changed, 70 insertions(+), 63 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core 
refs/changes/68/289368/1

diff --git a/includes/db/Database.php b/includes/db/Database.php
index 92e89b0..3c87899 100644
--- a/includes/db/Database.php
+++ b/includes/db/Database.php
@@ -820,23 +820,6 @@
                }
 
                $isMaster = !is_null( $this->getLBInfo( 'master' ) );
-               # generalizeSQL will probably cut down the query to reasonable
-               # logging size most of the time. The substr is really just a 
sanity check.
-               if ( $isMaster ) {
-                       $queryProf = 'query-m: ' . substr( 
DatabaseBase::generalizeSQL( $sql ), 0, 255 );
-                       $totalProf = 'DatabaseBase::query-master';
-               } else {
-                       $queryProf = 'query: ' . substr( 
DatabaseBase::generalizeSQL( $sql ), 0, 255 );
-                       $totalProf = 'DatabaseBase::query';
-               }
-               # Include query transaction state
-               $queryProf .= $this->mTrxShortId ? " 
[TRX#{$this->mTrxShortId}]" : "";
-
-               $profiler = Profiler::instance();
-               if ( !$profiler instanceof ProfilerStub ) {
-                       $totalProfSection = $profiler->scopedProfileIn( 
$totalProf );
-                       $queryProfSection = $profiler->scopedProfileIn( 
$queryProf );
-               }
 
                if ( $this->debug() ) {
                        wfDebugLog( 'queries', sprintf( "%s: %s", 
$this->mDBname, $commentedSql ) );
@@ -853,7 +836,7 @@
                $queryRuntime = microtime( true ) - $startTime;
                # Log the query time and feed it into the DB trx profiler
                $this->getTransactionProfiler()->recordQueryCompletion(
-                       $queryProf, $startTime, $isWriteQuery, 
$this->affectedRows() );
+                       $sql, $startTime, $isWriteQuery, $this->affectedRows(), 
$isMaster, $this->mTrxShortId );
 
                MWDebug::queryTime( $queryId );
 
@@ -889,7 +872,7 @@
                                        $queryRuntime = microtime( true ) - 
$startTime;
                                        # Log the query time and feed it into 
the DB trx profiler
                                        
$this->getTransactionProfiler()->recordQueryCompletion(
-                                               $queryProf, $startTime, 
$isWriteQuery, $this->affectedRows() );
+                                               $sql, $startTime, 
$isWriteQuery, $this->affectedRows(), $isMaster );
                                }
                        } else {
                                wfDebug( "Failed\n" );
@@ -902,10 +885,6 @@
                }
 
                $res = $this->resultObject( $ret );
-
-               // Destroy profile sections in the opposite order to their 
creation
-               ScopedCallback::consume( $queryProfSection );
-               ScopedCallback::consume( $totalProfSection );
 
                if ( $isWriteQuery && $this->mTrxLevel ) {
                        $this->mTrxWriteDuration += $queryRuntime;
@@ -1334,35 +1313,6 @@
                return $rows;
        }
 
-       /**
-        * Removes most variables from an SQL query and replaces them with X or 
N for numbers.
-        * It's only slightly flawed. Don't use for anything important.
-        *
-        * @param string $sql A SQL Query
-        *
-        * @return string
-        */
-       protected static function generalizeSQL( $sql ) {
-               # This does the same as the regexp below would do, but in such 
a way
-               # as to avoid crashing php on some large strings.
-               # $sql = preg_replace( 
"/'([^\\\\']|\\\\.)*'|\"([^\\\\\"]|\\\\.)*\"/", "'X'", $sql );
-
-               $sql = str_replace( "\\\\", '', $sql );
-               $sql = str_replace( "\\'", '', $sql );
-               $sql = str_replace( "\\\"", '', $sql );
-               $sql = preg_replace( "/'.*'/s", "'X'", $sql );
-               $sql = preg_replace( '/".*"/s', "'X'", $sql );
-
-               # All newlines, tabs, etc replaced by single space
-               $sql = preg_replace( '/\s+/', ' ', $sql );
-
-               # All numbers => N,
-               # except the ones surrounded by characters, e.g. l10n
-               $sql = preg_replace( '/-?\d+(,-?\d+)+/s', 'N,...,N', $sql );
-               $sql = preg_replace( '/(?<![a-zA-Z])-?\d+(?![a-zA-Z])/s', 'N', 
$sql );
-
-               return $sql;
-       }
 
        public function fieldExists( $table, $field, $fname = __METHOD__ ) {
                $info = $this->fieldInfo( $table, $field );
diff --git a/includes/profiler/TransactionProfiler.php 
b/includes/profiler/TransactionProfiler.php
index 1aba71c..37817d5 100644
--- a/includes/profiler/TransactionProfiler.php
+++ b/includes/profiler/TransactionProfiler.php
@@ -129,6 +129,36 @@
        }
 
        /**
+        * Removes most variables from an SQL query and replaces them with X or 
N for numbers.
+        * It's only slightly flawed. Don't use for anything important.
+        *
+        * @param string $sql A SQL Query
+        *
+        * @return string
+        */
+       protected static function generalizeSQL( $sql ) {
+               # This does the same as the regexp below would do, but in such 
a way
+               # as to avoid crashing php on some large strings.
+               # $sql = preg_replace( 
"/'([^\\\\']|\\\\.)*'|\"([^\\\\\"]|\\\\.)*\"/", "'X'", $sql );
+
+               $sql = str_replace( "\\\\", '', $sql );
+               $sql = str_replace( "\\'", '', $sql );
+               $sql = str_replace( "\\\"", '', $sql );
+               $sql = preg_replace( "/'.*'/s", "'X'", $sql );
+               $sql = preg_replace( '/".*"/s', "'X'", $sql );
+
+               # All newlines, tabs, etc replaced by single space
+               $sql = preg_replace( '/\s+/', ' ', $sql );
+
+               # All numbers => N,
+               # except the ones surrounded by characters, e.g. l10n
+               $sql = preg_replace( '/-?\d+(,-?\d+)+/s', 'N,...,N', $sql );
+               $sql = preg_replace( '/(?<![a-zA-Z])-?\d+(?![a-zA-Z])/s', 'N', 
$sql );
+
+               return $sql;
+       }
+
+       /**
         * Mark a DB as having been connected to with a new handle
         *
         * Note that there can be multiple connections to a single DB.
@@ -178,18 +208,41 @@
         *
         * This assumes that all queries are synchronous (non-overlapping)
         *
-        * @param string $query Function name or generalized SQL
+        * @param string $query SQL query
         * @param float $sTime Starting UNIX wall time
         * @param bool $isWrite Whether this is a write query
         * @param integer $n Number of affected rows
+        * @param bool $isMaster Whether this is a query of the master database
+        * @param string $id ID string of transaction, if any
         */
-       public function recordQueryCompletion( $query, $sTime, $isWrite = 
false, $n = 0 ) {
+       public function recordQueryCompletion( $query, $sTime, $isWrite, $n = 
0, $isMaster = false, $id = '' ) {
                $eTime = microtime( true );
                $elapsed = ( $eTime - $sTime );
 
+               $profiler = Profiler::instance();
+               if ( !$profiler instanceof ProfilerStub ) {
+                       // generalizeSQL will probably cut down the query to 
reasonable
+                       // logging size most of the time. The substr is really 
just a sanity check.
+                       if ( $isMaster ) {
+                               $queryProf = 'query-m: ';
+                               $totalProf = 'DatabaseBase::query-master';
+                       } else {
+                               $queryProf = 'query: ';
+                               $totalProf = 'DatabaseBase::query';
+                       }
+                       $queryProf .= substr( self::generalizeSQL( $sql ), 0, 
255 );
+                       // Include query transaction state
+                       $queryProf .= $id ? " [TRX#{$id}]" : "";
+                       $totalProfSection = $profiler->scopedProfileIn( 
$totalProf );
+                       $queryProfSection = $profiler->scopedProfileIn( 
$queryProf );
+                       // Destroy profile sections in the opposite order to 
their creation
+                       ScopedCallback::consume( $queryProfSection );
+                       ScopedCallback::consume( $totalProfSection );
+
+               }
+
                if ( $isWrite && $n > $this->expect['maxAffected'] ) {
-                       $this->logger->info( "Query affected $n row(s):\n" . 
$query . "\n" .
-                               wfBacktrace( true ) );
+                       $this->reportExpectationViolated( 'maxAffected', 
$query, $n );
                }
 
                // Report when too many writes/queries happen...
@@ -302,13 +355,17 @@
         * @param string|float|int $actual [optional]
         */
        protected function reportExpectationViolated( $expect, $query, $actual 
= null ) {
-               $n = $this->expect[$expect];
-               $by = $this->expectBy[$expect];
-               $actual = ( $actual !== null ) ? " (actual: $actual)" : "";
+               $query = self::generalizeSQL( $query );
 
-               $this->logger->info(
-                       "Expectation ($expect <= $n) by $by not 
met$actual:\n$query\n" .
-                       wfBacktrace( true )
-               );
+               $msg = "Expectation ($expect <= {$this->expect[$expect]})";
+               if ( isset( $this->expectBy[$expect] ) ) {
+                       $msg .= " by {$this->expectBy[$expect]}";
+               }
+               $msg .= ' not met';
+               if ( $actual !== null ) {
+                       $msg .= " (actual: $actual)";
+               }
+               $msg .= ":\n$query\n" . wfBacktrace( true );
+               $this->logger->info( $msg );
        }
 }

-- 
To view, visit https://gerrit.wikimedia.org/r/289368
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib927376a73cef8b51d8e97bf28e4766a399f29c4
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Ori.livneh <[email protected]>
Gerrit-Reviewer: Hashar <[email protected]>
Gerrit-Reviewer: Krinkle <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to