Added $wgDataCenterId/$wgDataCenterRoles
authorAaron Schulz <aschulz@wikimedia.org>
Wed, 19 Aug 2015 23:33:03 +0000 (16:33 -0700)
committerAaron Schulz <aschulz@wikimedia.org>
Thu, 1 Oct 2015 07:52:54 +0000 (00:52 -0700)
* This is used to set sticky DC cookies to avoid
  session replication lag (which also makes sure
  ChronologyProtector works)

Bug: T91816
Change-Id: I7bc2f8185a3c05cb3ca5ccc42d300eccffae48e1

RELEASE-NOTES-1.27
includes/DefaultSettings.php
includes/GlobalFunctions.php
includes/MediaWiki.php
includes/db/loadbalancer/LBFactory.php

index eb15439..1670552 100644 (file)
@@ -16,6 +16,9 @@ production.
   1000 for the latter) are now hard-coded.
 
 === New features in 1.27 ===
+* $wgDataCenterId and $wgDataCenterRoles where added, which will serve as
+  basic configuration settings needed for multi-datacenter setups.
+  $wgDataCenterUpdateStickTTL was also added.
 
 ==== External libraries ====
 
index 69b4a24..2793161 100644 (file)
@@ -1868,6 +1868,32 @@ $wgDBservers = false;
  */
 $wgLBFactoryConf = array( 'class' => 'LBFactorySimple' );
 
+/**
+ * The ID of the current data center
+ * @since 1.27
+ */
+$wgDataCenterId = 'default';
+
+/**
+ * Map of data center IDs to their role ("master" or "slave")
+ *
+ * Multiple data centers can be setup to handle MediaWiki, with HTTP
+ * POSTs routed to the master data center and GET/HEAD/OPTION routed to
+ * any data center (usually the closest to the end user). In such setups,
+ * this setting should be set to the appropriate value in the site
+ * config for each data center.
+ * @since 1.27
+ */
+$wgDataCenterRoles = array( 'default' => 'master' );
+
+/**
+ * After a state-changing request is done by a client, this determines
+ * how many seconds that client should keep using the master datacenter.
+ * This avoids unexpected stale or 404 responses due to replication lag.
+ * @since 1.27
+ */
+$wgDataCenterUpdateStickTTL = 10;
+
 /**
  * File to log database errors to
  */
index 6fbc11d..3b9a882 100644 (file)
@@ -3605,6 +3605,28 @@ function wfSplitWikiID( $wiki ) {
        return $bits;
 }
 
+/**
+ * @see $wgDataCenterRoles
+ * @return string The current cluster ID
+ * @since 1.27
+ */
+function wfDataCenter() {
+       global $wgDataCenterId;
+
+       return $wgDataCenterId;
+}
+
+/**
+ * @see $wgDataCenterRoles
+ * @return string The current cluster role; one of (master/slave)
+ * @since 1.27
+ */
+function wfDataCenterRole() {
+       global $wgDataCenterId, $wgDataCenterRoles;
+
+       return $wgDataCenterRoles[$wgDataCenterId];
+}
+
 /**
  * Get a Database object.
  *
index fbacb25..f3fb158 100644 (file)
@@ -504,6 +504,14 @@ class MediaWiki {
                $factory->shutdown();
 
                wfDebug( __METHOD__ . ' completed; all transactions committed' );
+
+               // 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();
+               if ( $request->wasPosted() && $factory->hasOrMadeRecentMasterChanges() ) {
+                       $expires = time() + $this->config->get( 'DataCenterUpdateStickTTL' );
+                       $request->response()->setCookie( 'UseDC', 'master', $expires );
+               }
        }
 
        /**
index da0fe44..e5fb094 100644 (file)
@@ -202,9 +202,9 @@ abstract class LBFactory {
        }
 
        /**
-        * Detemine if any master connection has pending changes.
-        * @since 1.23
+        * Determine if any master connection has pending changes
         * @return bool
+        * @since 1.23
         */
        public function hasMasterChanges() {
                $ret = false;
@@ -213,6 +213,19 @@ abstract class LBFactory {
                } );
                return $ret;
        }
+
+       /**
+        * Determine if any master connection has pending/written changes from this request
+        * @return bool
+        * @since 1.27
+        */
+       public function hasOrMadeRecentMasterChanges() {
+               $ret = false;
+               $this->forEachLB( function ( LoadBalancer $lb ) use ( &$ret ) {
+                       $ret = $ret || $lb->hasOrMadeRecentMasterChanges();
+               } );
+               return $ret;
+       }
 }
 
 /**