Merge "rdbms: change "profiler" argument in Database::factory so it works again"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Fri, 15 Mar 2019 00:02:35 +0000 (00:02 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Fri, 15 Mar 2019 00:02:35 +0000 (00:02 +0000)
1  2 
includes/libs/rdbms/database/Database.php

@@@ -260,7 -260,7 +260,7 @@@ abstract class Database implements IDat
        /** @var int[] Prior flags member variable values */
        private $priorFlags = [];
  
-       /** @var mixed Class name or object With profileIn/profileOut methods */
+       /** @var callable|null */
        protected $profiler;
        /** @var TransactionProfiler */
        protected $trxProfiler;
  
                $this->srvCache = $params['srvCache'] ?? new HashBagOStuff();
  
-               $this->profiler = $params['profiler'];
+               $this->profiler = is_callable( $params['profiler'] ) ? $params['profiler'] : null;
                $this->trxProfiler = $params['trxProfiler'];
                $this->connLogger = $params['connLogger'];
                $this->queryLogger = $params['queryLogger'];
         *      used to adjust lock timeouts or encoding modes and the like.
         *   - connLogger: Optional PSR-3 logger interface instance.
         *   - queryLogger: Optional PSR-3 logger interface instance.
-        *   - profiler: Optional class name or object with profileIn()/profileOut() methods.
-        *      These will be called in query(), using a simplified version of the SQL that also
-        *      includes the agent as a SQL comment.
+        *   - profiler : Optional callback that takes a section name argument and returns
+        *      a ScopedCallback instance that ends the profile section in its destructor.
+        *      These will be called in query(), using a simplified version of the SQL that
+        *      also includes the agent as a SQL comment.
         *   - trxProfiler: Optional TransactionProfiler instance.
         *   - errorLogger: Optional callback that takes an Exception and logs it.
         *   - deprecationLogger: Optional callback that takes a string and logs it.
                                        # option is ROLLBACK, since the snapshots would have been released.
                                        $this->trxStatus = self::STATUS_TRX_ERROR;
                                        $this->trxStatusCause =
 -                                              $this->makeQueryException( $lastError, $lastErrno, $sql, $fname );
 +                                              $this->getQueryExceptionAndLog( $lastError, $lastErrno, $sql, $fname );
                                        $tempIgnore = false; // cannot recover
                                        $this->trxStatusIgnoredCause = null;
                                }
                $queryProf .= $this->trxShortId ? " [TRX#{$this->trxShortId}]" : "";
  
                $startTime = microtime( true );
-               if ( $this->profiler ) {
-                       $this->profiler->profileIn( $queryProf );
-               }
+               $ps = $this->profiler ? ( $this->profiler )( $queryProf ) : null;
                $this->affectedRowCount = null;
                $ret = $this->doQuery( $commentedSql );
                $this->affectedRowCount = $this->affectedRows();
-               if ( $this->profiler ) {
-                       $this->profiler->profileOut( $queryProf );
-               }
+               unset( $ps ); // profile out (if set)
                $queryRuntime = max( microtime( true ) - $startTime, 0.0 );
  
-               unset( $queryProfSection ); // profile out (if set)
                if ( $ret !== false ) {
                        $this->lastPing = $startTime;
                        if ( $isWrite && $this->trxLevel ) {
                if ( $tempIgnore ) {
                        $this->queryLogger->debug( "SQL ERROR (ignored): $error\n" );
                } else {
 -                      $exception = $this->makeQueryException( $error, $errno, $sql, $fname );
 +                      $exception = $this->getQueryExceptionAndLog( $error, $errno, $sql, $fname );
  
                        throw $exception;
                }
         * @param string $fname
         * @return DBError
         */
 -      private function makeQueryException( $error, $errno, $sql, $fname ) {
 +      private function getQueryExceptionAndLog( $error, $errno, $sql, $fname ) {
                $sql1line = mb_substr( str_replace( "\n", "\\n", $sql ), 0, 5 * 1024 );
                $this->queryLogger->error(
                        "{fname}\t{db_server}\t{errno}\t{error}\t{sql1line}",
                                'error' => $error,
                                'sql1line' => $sql1line,
                                'fname' => $fname,
 +                              'trace' => ( new RuntimeException() )->getTraceAsString()
                        ] )
                );
                $this->queryLogger->debug( "SQL ERROR: " . $error . "\n" );
                        return;
                }
  
 +              $uniqueIndexes = (array)$uniqueIndexes;
                // Single row case
                if ( !is_array( reset( $rows ) ) ) {
                        $rows = [ $rows ];
                $this->query( $sql, $fname );
        }
  
 -      public function upsert( $table, array $rows, array $uniqueIndexes, array $set,
 +      public function upsert( $table, array $rows, $uniqueIndexes, array $set,
                $fname = __METHOD__
        ) {
                if ( $rows === [] ) {
                        return true; // nothing to do
                }
  
 +              $uniqueIndexes = (array)$uniqueIndexes;
                if ( !is_array( reset( $rows ) ) ) {
                        $rows = [ $rows ];
                }