Merge "API DB commit and sticky DC cookie fixes"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Mon, 23 Nov 2015 00:43:59 +0000 (00:43 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Mon, 23 Nov 2015 00:43:59 +0000 (00:43 +0000)
1  2 
includes/MediaWiki.php
includes/api/ApiMain.php

diff --combined includes/MediaWiki.php
@@@ -486,13 -486,22 +486,22 @@@ class MediaWiki 
                $this->doPostOutputShutdown( 'normal' );
        }
  
+       /**
+        * @see MediaWiki::preOutputCommit()
+        * @since 1.26
+        */
+       public function doPreOutputCommit() {
+               self::preOutputCommit( $this->context );
+       }
        /**
         * This function commits all DB changes as needed before
         * the user can receive a response (in case commit fails)
         *
-        * @since 1.26
+        * @param IContextSource $context
+        * @since 1.27
         */
-       public function doPreOutputCommit() {
+       public static function preOutputCommit( IContextSource $context ) {
                // Either all DBs should commit or none
                ignore_user_abort( true );
  
  
                // Set a cookie to tell all CDN edge nodes to "stick" the user to the
                // DC that handles this POST request (e.g. the "master" data center)
-               $request = $this->context->getRequest();
+               $request = $context->getRequest();
+               $config = $context->getConfig();
                if ( $request->wasPosted() && $factory->hasOrMadeRecentMasterChanges() ) {
-                       $expires = time() + $this->config->get( 'DataCenterUpdateStickTTL' );
-                       $request->response()->setCookie( 'UseDC', 'master', $expires );
+                       $expires = time() + $config->get( 'DataCenterUpdateStickTTL' );
+                       $request->response()->setCookie( 'UseDC', 'master', $expires, array( 'prefix' => '' ) );
                }
  
                // Avoid letting a few seconds of slave lag cause a month of stale data
                if ( $factory->laggedSlaveUsed() ) {
-                       $maxAge = $this->config->get( 'CdnMaxageLagged' );
-                       $this->context->getOutput()->lowerCdnMaxage( $maxAge );
+                       $maxAge = $config->get( 'CdnMaxageLagged' );
+                       $context->getOutput()->lowerCdnMaxage( $maxAge );
                        $request->response()->header( "X-Database-Lagged: true" );
                        wfDebugLog( 'replication', "Lagged DB used; CDN cache TTL limited to $maxAge seconds" );
                }
                // Commit and close up!
                $factory = wfGetLBFactory();
                $factory->commitMasterChanges();
 -              $factory->shutdown();
 +              $factory->shutdown( LBFactory::SHUTDOWN_NO_CHRONPROT );
  
                wfDebug( "Request ended normally\n" );
        }
diff --combined includes/api/ApiMain.php
@@@ -102,7 -102,13 +102,7 @@@ class ApiMain extends ApiBase 
                'phpfm' => 'ApiFormatPhp',
                'xml' => 'ApiFormatXml',
                'xmlfm' => 'ApiFormatXml',
 -              'yaml' => 'ApiFormatYaml',
 -              'yamlfm' => 'ApiFormatYaml',
                'rawfm' => 'ApiFormatJson',
 -              'txt' => 'ApiFormatTxt',
 -              'txtfm' => 'ApiFormatTxt',
 -              'dbg' => 'ApiFormatDbg',
 -              'dbgfm' => 'ApiFormatDbg',
                'none' => 'ApiFormatNone',
        );
  
                // Log the request whether or not there was an error
                $this->logRequest( microtime( true ) - $t );
  
+               // Commit DBs and send any related cookies and headers
+               MediaWiki::preOutputCommit( $this->getContext() );
                // Send cache headers after any code which might generate an error, to
                // avoid sending public cache headers for errors.
                $this->sendCacheHeaders( $isError );
  
        /**
         * Log the preceding request
 -       * @param int $time Time in seconds
 +       * @param float $time Time in seconds
         */
        protected function logRequest( $time ) {
                $request = $this->getRequest();
 -              $milliseconds = $time === null ? '?' : round( $time * 1000 );
 -              $s = 'API' .
 -                      ' ' . $request->getMethod() .
 -                      ' ' . wfUrlencode( str_replace( ' ', '_', $this->getUser()->getName() ) ) .
 -                      ' ' . $request->getIP() .
 -                      ' T=' . $milliseconds . 'ms';
 +              $logCtx = array(
 +                      'dt' => date( 'c' ),
 +                      'client_ip' => $request->getIP(),
 +                      'user_agent' => $this->getUserAgent(),
 +                      'wiki' => wfWikiId(),
 +                      'time_backend_ms' => round( $time * 1000 ),
 +                      'params' => array(),
 +              );
 +
 +              // Construct space separated message for 'api' log channel
 +              $msg = "API {$request->getMethod()} " .
 +                      wfUrlencode( str_replace( ' ', '_', $this->getUser()->getName() ) ) .
 +                      " {$logCtx['client_ip']} " .
 +                      "T={$logCtx['time_backend_ms']}ms";
 +
                foreach ( $this->getParamsUsed() as $name ) {
                        $value = $request->getVal( $name );
                        if ( $value === null ) {
                                continue;
                        }
 -                      $s .= ' ' . $name . '=';
 +
                        if ( strlen( $value ) > 256 ) {
 -                              $encValue = $this->encodeRequestLogValue( substr( $value, 0, 256 ) );
 -                              $s .= $encValue . '[...]';
 +                              $value = substr( $value, 0, 256 );
 +                              $encValue = $this->encodeRequestLogValue( $value ) . '[...]';
                        } else {
 -                              $s .= $this->encodeRequestLogValue( $value );
 +                              $encValue = $this->encodeRequestLogValue( $value );
                        }
 +
 +                      $logCtx['params'][$name] = $value;
 +                      $msg .= " {$name}={$encValue}";
                }
 -              $s .= "\n";
 -              wfDebugLog( 'api', $s, 'private' );
 +
 +              wfDebugLog( 'api', $msg, 'private' );
 +              // ApiRequest channel is for structured data consumers
 +              wfDebugLog( 'ApiRequest', '', 'private', $logCtx );
        }
  
        /**