[MediaWiki-commits] [Gerrit] Decouple ChronologyProtector from user sessions - change (mediawiki/core)

2015-11-12 Thread jenkins-bot (Code Review)
jenkins-bot has submitted this change and it was merged.

Change subject: Decouple ChronologyProtector from user sessions
..


Decouple ChronologyProtector from user sessions

* It now works for users without using sessions.
  Sessions should not be cluttered with things
  unrelated to authentication and tokens.
* Public services doing api.php requests on behalf
  of a users only need to set XFF headers (as normal)
  for position wait logic to trigger. They can opt out
  of ChronologyProtector via a new HTTP header
  "ChronologyProtection: false".
* Requests across subdomains, such as the SUL2 handshake
  for CentralAuth on account creation, now have position
  wait logic applied. This helps avoid anomolies were a
  row just written in the last request may not be seen.
* Use merge() to avoid rolling back master positions if
  the user has multiple tabs open and doing writes at once.
* $_SESSION global state is gone from ChronologyProtector.
* Cleaned up post-send LBFactory::shutdown() logic for
  avoiding master position writes with an explicit flag.
* Use 'replication' debug log group in more places.

Bug: T111264
Change-Id: Ib25d05994d62b25c2f89e67b7f51009c54f4bca8
---
M includes/MediaWiki.php
M includes/db/ChronologyProtector.php
M includes/db/loadbalancer/LBFactory.php
M includes/db/loadbalancer/LBFactoryMulti.php
M includes/db/loadbalancer/LBFactorySimple.php
M includes/db/loadbalancer/LoadBalancer.php
M includes/db/loadbalancer/LoadMonitorMySQL.php
M tests/phpunit/includes/db/LBFactoryTest.php
8 files changed, 264 insertions(+), 60 deletions(-)

Approvals:
  Tim Starling: Looks good to me, approved
  Ori.livneh: Looks good to me, but someone else must approve
  jenkins-bot: Verified



diff --git a/includes/MediaWiki.php b/includes/MediaWiki.php
index d048b57..d5aac07 100644
--- a/includes/MediaWiki.php
+++ b/includes/MediaWiki.php
@@ -710,7 +710,7 @@
// Commit and close up!
$factory = wfGetLBFactory();
$factory->commitMasterChanges();
-   $factory->shutdown();
+   $factory->shutdown( LBFactory::SHUTDOWN_NO_CHRONPROT );
 
wfDebug( "Request ended normally\n" );
}
diff --git a/includes/db/ChronologyProtector.php 
b/includes/db/ChronologyProtector.php
index 6840d17..1ef26d2 100644
--- a/includes/db/ChronologyProtector.php
+++ b/includes/db/ChronologyProtector.php
@@ -26,19 +26,59 @@
  * Kind of like Hawking's [[Chronology Protection Agency]].
  */
 class ChronologyProtector {
-   /** @var array (DB master name => position) */
-   protected $startupPositions = array();
+   /** @var BagOStuff */
+   protected $store;
 
-   /** @var array (DB master name => position) */
+   /** @var string Storage key name */
+   protected $key;
+   /** @var array Map of (ip: , agent: ) */
+   protected $client;
+   /** @var bool Whether to no-op all method calls */
+   protected $enabled = true;
+   /** @var bool Whether to check and wait on positions */
+   protected $wait = true;
+
+   /** @var bool Whether the client data was loaded */
+   protected $initialized = false;
+   /** @var DBMasterPos[] Map of (DB master name => position) */
+   protected $startupPositions = array();
+   /** @var DBMasterPos[] Map of (DB master name => position) */
protected $shutdownPositions = array();
 
-   /** @var bool Whether the session data was loaded */
-   protected $initialized = false;
+   /**
+* @param BagOStuff $store
+* @param array $client Map of (ip: , agent: )
+* @since 1.27
+*/
+   public function __construct( BagOStuff $store, array $client ) {
+   $this->store = $store;
+   $this->client = $client;
+   $this->key = $store->makeGlobalKey(
+   'ChronologyProtector',
+   md5( $client['ip'] . "\n" . $client['agent'] )
+   );
+   }
+
+   /**
+* @param bool $enabled Whether to no-op all method calls
+* @since 1.27
+*/
+   public function setEnabled( $enabled ) {
+   $this->enabled = $enabled;
+   }
+
+   /**
+* @param bool $enabled Whether to check and wait on positions
+* @since 1.27
+*/
+   public function setWaitEnabled( $enabled ) {
+   $this->wait = $enabled;
+   }
 
/**
 * Initialise a LoadBalancer to give it appropriate chronology 
protection.
 *
-* If the session has a previous master position recorded, this will 
try to
+* If the stash has a previous master position recorded, this will try 
to
 * make sure that the next query to a slave of that master will see 
changes up
 * to that position by delaying execution. The delay may timeout and 
allow stale
 * data if no non-lagged slaves 

[MediaWiki-commits] [Gerrit] Decouple ChronologyProtector from user sessions - change (mediawiki/core)

2015-10-18 Thread Aaron Schulz (Code Review)
Aaron Schulz has uploaded a new change for review.

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

Change subject: Decouple ChronologyProtector from user sessions
..

Decouple ChronologyProtector from user sessions

* This now works for users without sessions and for
  requests across subdomains.
* Use merge() to avoid rolling back master positions
  if the user has multiple tabs open at once.
* The global state is now removed.
* toString() method is no longer missing from DBMasterPos.

Change-Id: Ib25d05994d62b25c2f89e67b7f51009c54f4bca8
---
M includes/db/ChronologyProtector.php
M includes/db/DatabaseUtility.php
M includes/db/loadbalancer/LBFactoryMulti.php
M includes/db/loadbalancer/LBFactorySimple.php
4 files changed, 111 insertions(+), 21 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core 
refs/changes/78/247178/1

diff --git a/includes/db/ChronologyProtector.php 
b/includes/db/ChronologyProtector.php
index 0c7b612..a44faa6 100644
--- a/includes/db/ChronologyProtector.php
+++ b/includes/db/ChronologyProtector.php
@@ -26,14 +26,44 @@
  * Kind of like Hawking's [[Chronology Protection Agency]].
  */
 class ChronologyProtector {
-   /** @var array (DB master name => position) */
-   protected $startupPositions = array();
+   /** @var BagOStuff */
+   protected $store;
 
-   /** @var array (DB master name => position) */
+   /** @var string Storage key name */
+   protected $key;
+   /** @var array Map of (ip: , agent: ) */
+   protected $client;
+   /** @var DBMasterPos[] Map of (DB master name => position) */
+   protected $startupPositions = array();
+   /** @var DBMasterPos[] Map of (DB master name => position) */
protected $shutdownPositions = array();
 
+   /** @var bool Whether to actually wait on and record positions */
+   protected $enabled = true;
/** @var bool Whether the session data was loaded */
protected $initialized = false;
+
+   /**
+* @param BagOStuff $store
+* @param array $client Map of (ip: , agent: )
+* @since 1.27
+*/
+   public function __construct( BagOStuff $store, array $client ) {
+   $this->store = $store;
+   $this->client = $client;
+   $this->key = $store->makeGlobalKey(
+   'ChronologyProtector',
+   md5( $client['ip'] . "\n" . $client['agent'] )
+   );
+   }
+
+   /**
+* @param bool $enabled
+* @since 1.27
+*/
+   public function setEnabled( $enabled ) {
+   $this->enabled = $enabled;
+   }
 
/**
 * Initialise a LoadBalancer to give it appropriate chronology 
protection.
@@ -47,15 +77,12 @@
 * @return void
 */
public function initLB( LoadBalancer $lb ) {
-   if ( $lb->getServerCount() <= 1 ) {
-   return; // non-replicated setup
+   if ( !$this->enabled || $lb->getServerCount() <= 1 ) {
+   return; // non-replicated setup or disabled
}
-   if ( !$this->initialized ) {
-   $this->initialized = true;
-   if ( isset( $_SESSION[__CLASS__] ) && is_array( 
$_SESSION[__CLASS__] ) ) {
-   $this->startupPositions = $_SESSION[__CLASS__];
-   }
-   }
+
+   $this->initialize();
+
$masterName = $lb->getServerName( 0 );
if ( !empty( $this->startupPositions[$masterName] ) ) {
$info = $lb->parentInfo();
@@ -73,21 +100,26 @@
 * @return void
 */
public function shutdownLB( LoadBalancer $lb ) {
-   if ( session_id() == '' || $lb->getServerCount() <= 1 ) {
-   return; // don't start a session; don't bother with 
non-replicated setups
+   if ( !$this->enabled || $lb->getServerCount() <= 1 ) {
+   return; // non-replicated setup or disabled
}
+
+   $info = $lb->parentInfo();
$masterName = $lb->getServerName( 0 );
if ( isset( $this->shutdownPositions[$masterName] ) ) {
+   wfDebug( __METHOD__ . ": LB {$info['id']} already shut 
down\n" );
+
return; // already done
}
+
// Only save the position if writes have been done on the 
connection
$db = $lb->getAnyOpenConnection( 0 );
-   $info = $lb->parentInfo();
if ( !$db || !$db->doneWrites() ) {
wfDebug( __METHOD__ . ": LB {$info['id']}, no writes 
done\n" );
 
-   return;
+   return; // nothing to do
}
+
$pos = $db->getMasterPos();
wfDebug(