[Database] Tweaked LoadMonitor::getLagTimes() to further reduce stampedes
authorAaron Schulz <aschulz@wikimedia.org>
Wed, 22 May 2013 23:19:16 +0000 (16:19 -0700)
committerGerrit Code Review <gerrit@wikimedia.org>
Tue, 11 Jun 2013 00:39:58 +0000 (00:39 +0000)
Change-Id: I79e3232e3e87bb298ae1a3fe214fcd2506818884

includes/db/LoadMonitor.php

index 4b9ecce..519e2df 100644 (file)
@@ -142,12 +142,12 @@ class LoadMonitor_MySQL implements LoadMonitor {
                $masterName = $this->parent->getServerName( 0 );
                $memcKey = wfMemcKey( 'lag_times', $masterName );
                $times = $wgMemc->get( $memcKey );
-               if ( $times ) {
+               if ( is_array( $times ) ) {
                        # Randomly recache with probability rising over $expiry
                        $elapsed = time() - $times['timestamp'];
                        $chance = max( 0, ( $expiry - $elapsed ) * $requestRate );
                        if ( mt_rand( 0, $chance ) != 0 ) {
-                               unset( $times['timestamp'] );
+                               unset( $times['timestamp'] ); // hide from caller
                                wfProfileOut( __METHOD__ );
                                return $times;
                        }
@@ -157,6 +157,17 @@ class LoadMonitor_MySQL implements LoadMonitor {
                }
 
                # Cache key missing or expired
+               if ( $wgMemc->add( "$memcKey:lock", 1, 10 ) ) {
+                       # Let this process alone update the cache value
+                       $unlocker = new ScopedCallback( function() use ( $wgMemc, $memcKey ) {
+                               $wgMemc->delete( $memcKey );
+                       } );
+               } elseif ( is_array( $times ) ) {
+                       # Could not acquire lock but an old cache exists, so use it
+                       unset( $times['timestamp'] ); // hide from caller
+                       wfProfileOut( __METHOD__ );
+                       return $times;
+               }
 
                $times = array();
                foreach ( $serverIndexes as $i ) {
@@ -171,14 +182,11 @@ class LoadMonitor_MySQL implements LoadMonitor {
 
                # Add a timestamp key so we know when it was cached
                $times['timestamp'] = time();
-               $wgMemc->set( $memcKey, $times, $expiry );
-
-               # But don't give the timestamp to the caller
-               unset( $times['timestamp'] );
-               $lagTimes = $times;
+               $wgMemc->set( $memcKey, $times, $expiry + 10 );
+               unset( $times['timestamp'] ); // hide from caller
 
                wfProfileOut( __METHOD__ );
-               return $lagTimes;
+               return $times;
        }
 
        /**