From 8653947b065aa57164a38fb5d4cdf0e1b8717f70 Mon Sep 17 00:00:00 2001 From: Tim Starling Date: Tue, 17 Feb 2009 14:06:42 +0000 Subject: [PATCH] * Skip COMMIT query when no write queries have been done. * Improvement to ChronologyProtector: only record the master position if a write query was done. This should help to avoid the worst of the ChronologyProtector side-effects, such as having action=raw CSS requests block for a time equivalent to the slave lag on every page view, while maintaining the benefits, like preventing a 404 from being displayed after page creation. --- includes/db/Database.php | 23 ++++++++++++++++++++++- includes/db/LBFactory.php | 26 ++++++++++++++++++-------- includes/db/LoadBalancer.php | 2 +- 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/includes/db/Database.php b/includes/db/Database.php index 38399186c9..97b77460fd 100644 --- a/includes/db/Database.php +++ b/includes/db/Database.php @@ -26,6 +26,7 @@ class Database { #------------------------------------------------------------------------------ protected $mLastQuery = ''; + protected $mDoneWrites = false; protected $mPHPError = false; protected $mServer, $mUser, $mPassword, $mConn = null, $mDBname; @@ -210,7 +211,14 @@ class Database { * @return String */ function lastQuery() { return $this->mLastQuery; } - + + + /** + * Returns true if the connection may have been used for write queries. + * Should return true if unsure. + */ + function doneWrites() { return $this->mDoneWrites; } + /** * Is a connection to the database open? * @return Boolean @@ -492,6 +500,14 @@ class Database { } } + /** + * Determine whether a query writes to the DB. + * Should return true if unsure. + */ + function isWriteQuery( $sql ) { + return !preg_match( '/^(?:SELECT|BEGIN|COMMIT|SET|SHOW)\b/i', $sql ); + } + /** * Usually aborts on failure. If errors are explicitly ignored, returns success. * @@ -527,6 +543,11 @@ class Database { } $this->mLastQuery = $sql; + if ( !$this->mDoneWrites && $this->isWriteQuery( $sql ) ) { + // Set a flag indicating that writes have been done + wfDebug( __METHOD__.": Writes done: $sql\n" ); + $this->mDoneWrites = true; + } # Add a comment for easy SHOW PROCESSLIST interpretation #if ( $fname ) { diff --git a/includes/db/LBFactory.php b/includes/db/LBFactory.php index 256875d722..3876d71f70 100644 --- a/includes/db/LBFactory.php +++ b/includes/db/LBFactory.php @@ -236,15 +236,25 @@ class ChronologyProtector { * @param LoadBalancer $lb */ function shutdownLB( $lb ) { - if ( session_id() != '' && $lb->getServerCount() > 1 ) { - $masterName = $lb->getServerName( 0 ); - if ( !isset( $this->shutdownPos[$masterName] ) ) { - $pos = $lb->getMasterPos(); - $info = $lb->parentInfo(); - wfDebug( __METHOD__.": LB " . $info['id'] . " has master pos $pos\n" ); - $this->shutdownPos[$masterName] = $pos; - } + // Don't start a session, don't bother with non-replicated setups + if ( strval( session_id() ) == '' || $lb->getServerCount() <= 1 ) { + return; + } + $masterName = $lb->getServerName( 0 ); + if ( isset( $this->shutdownPos[$masterName] ) ) { + // Already done + return; + } + // 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; } + $pos = $db->getMasterPos(); + wfDebug( __METHOD__.": LB {$info['id']} has master pos $pos\n" ); + $this->shutdownPos[$masterName] = $pos; } /** diff --git a/includes/db/LoadBalancer.php b/includes/db/LoadBalancer.php index f847fe22af..0b8ef05a08 100644 --- a/includes/db/LoadBalancer.php +++ b/includes/db/LoadBalancer.php @@ -824,7 +824,7 @@ class LoadBalancer { continue; } foreach ( $conns2[$masterIndex] as $conn ) { - if ( $conn->lastQuery() != '' ) { + if ( $conn->doneWrites() ) { $conn->commit(); } } -- 2.20.1