From 1b89cd274a0d2c546736607c7fc4dea0fe219866 Mon Sep 17 00:00:00 2001 From: Roan Kattouw Date: Fri, 6 Nov 2009 14:38:55 +0000 Subject: [PATCH] API: (bug 20554) Expose average slave lag (avglag) as well as maxlag. Patch by Sam Reed. --- RELEASE-NOTES | 1 + includes/GlobalFunctions.php | 15 +++++++++++++++ includes/Wiki.php | 18 ++++++++++++++++++ includes/api/ApiBase.php | 8 ++++++++ includes/api/ApiHelp.php | 4 ++++ includes/api/ApiMain.php | 18 ++++++++++++++++++ includes/api/ApiQuery.php | 4 ++++ includes/api/ApiQuerySiteinfo.php | 1 + includes/db/LoadBalancer.php | 21 +++++++++++++++++++++ index.php | 5 +++++ 10 files changed, 95 insertions(+) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index a0cadd510a..bf4aebcd27 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -684,6 +684,7 @@ Hopefully we will remove this configuration var soon) * (bug 19004) Added support for tags * (bug 21083) list=allusers no longer returns current timestamp for users without registration date +* (bug 20554) Expose average slave lag (avglag) as well as maxlag === Languages updated in 1.16 === diff --git a/includes/GlobalFunctions.php b/includes/GlobalFunctions.php index b92e48f70a..60197eea9f 100644 --- a/includes/GlobalFunctions.php +++ b/includes/GlobalFunctions.php @@ -3113,6 +3113,21 @@ function wfMaxlagError( $host, $lag, $maxLag ) { } } +/** + * Displays a avglag error + * + * @param $lag Integer: avglag (actual) + * @param $avgLag Integer: avglag (requested) + */ +function wfAvglagError( $lag, $avgLag ) { + header( 'HTTP/1.1 503 Service Unavailable' ); + header( 'Retry-After: ' . max( intval( $avgLag ), 5 ) ); + header( 'X-Database-Lag: ' . intval( $lag ) ); + header( 'Content-Type: text/plain' ); + + echo "Lagged: $lag seconds average\n"; +} + /** * Throws a warning that $function is deprecated * @param $function String diff --git a/includes/Wiki.php b/includes/Wiki.php index 286bc8e747..c7d80c27c6 100644 --- a/includes/Wiki.php +++ b/includes/Wiki.php @@ -95,6 +95,24 @@ class MediaWiki { return true; } } + + /** + * Check if the average lag of database slaves is higher that $avgLag, and + * if it's the case, output an error message + * + * @param $avgLag int: maximum lag allowed for the request, as supplied by + * the client + * @return bool true if the request can continue + */ + function checkAvgLag( $avgLag ) { + list( $host, $lag ) = wfGetLB()->getAvgLag(); + if( $lag > $avgLag ) { + wfAvglagError( $lag, $avgLag ); + return false; + } else { + return true; + } + } /** * Checks some initial queries diff --git a/includes/api/ApiBase.php b/includes/api/ApiBase.php index dd496b85b5..0d1db32b7c 100644 --- a/includes/api/ApiBase.php +++ b/includes/api/ApiBase.php @@ -935,6 +935,14 @@ abstract class ApiBase { public function shouldCheckMaxlag() { return true; } + + /** + * Indicates if this module needs avglag to be checked + * @return bool + */ + public function shouldCheckAvglag() { + return true; + } /** * Indicates whether this module requires read rights diff --git a/includes/api/ApiHelp.php b/includes/api/ApiHelp.php index 982bf4d5ea..02000626e7 100644 --- a/includes/api/ApiHelp.php +++ b/includes/api/ApiHelp.php @@ -49,6 +49,10 @@ class ApiHelp extends ApiBase { public function shouldCheckMaxlag() { return false; } + + public function shouldCheckAvglag() { + return false; + } public function isReadMode() { return false; diff --git a/includes/api/ApiMain.php b/includes/api/ApiMain.php index 6867193d25..e930e7fb1f 100644 --- a/includes/api/ApiMain.php +++ b/includes/api/ApiMain.php @@ -394,6 +394,20 @@ class ApiMain extends ApiBase { return; } } + + if( $module->shouldCheckAvglag() && isset( $params['avglag'] ) ) { + // Check for avglag + global $wgShowHostnames; + $avgLag = $params['avglag']; + $lag = wfGetLB()->getAvgLag(); + if ( $lag > $avgLag ) { + header( 'Retry-After: ' . max( intval( $avgLag ), 5 ) ); + header( 'X-Database-Lag: ' . intval( $lag ) ); + + $this->dieUsage( "Lag: $lag seconds average", 'avglag' ); + return; + } + } global $wgUser; if ($module->isReadMode() && !$wgUser->isAllowed('read')) @@ -477,6 +491,9 @@ class ApiMain extends ApiBase { 'maxlag' => array ( ApiBase :: PARAM_TYPE => 'integer' ), + 'avglag' => array ( + ApiBase :: PARAM_TYPE => 'integer' + ), 'smaxage' => array ( ApiBase :: PARAM_TYPE => 'integer', ApiBase :: PARAM_DFLT => 0 @@ -498,6 +515,7 @@ class ApiMain extends ApiBase { 'action' => 'What action you would like to perform', 'version' => 'When showing help, include version for each module', 'maxlag' => 'Maximum lag', + 'avglag' => 'Average lag', 'smaxage' => 'Set the s-maxage header to this many seconds. Errors are never cached', 'maxage' => 'Set the max-age header to this many seconds. Errors are never cached', 'requestid' => 'Request ID to distinguish requests. This will just be output back to you', diff --git a/includes/api/ApiQuery.php b/includes/api/ApiQuery.php index e15edb68a1..f2e90b18bc 100644 --- a/includes/api/ApiQuery.php +++ b/includes/api/ApiQuery.php @@ -548,6 +548,10 @@ class ApiQuery extends ApiBase { public function shouldCheckMaxlag() { return true; } + + public function shouldCheckAvglag() { + return true; + } public function getParamDescription() { return array ( diff --git a/includes/api/ApiQuerySiteinfo.php b/includes/api/ApiQuerySiteinfo.php index 8439e471a2..287887bced 100644 --- a/includes/api/ApiQuerySiteinfo.php +++ b/includes/api/ApiQuerySiteinfo.php @@ -295,6 +295,7 @@ class ApiQuerySiteinfo extends ApiQueryBase { ); } + $data['avglag'] = wfGetLB()->getAvgLag(); $result = $this->getResult(); $result->setIndexedTagName( $data, 'db' ); return $this->getResult()->addValue( 'query', $property, $data ); diff --git a/includes/db/LoadBalancer.php b/includes/db/LoadBalancer.php index 0b8ef05a08..5e91f1ee40 100644 --- a/includes/db/LoadBalancer.php +++ b/includes/db/LoadBalancer.php @@ -898,6 +898,27 @@ class LoadBalancer { } return array( $host, $maxLag ); } + + /** + * Gets the average lag of slaves. + * May attempt to open connections to slaves on the default DB. + */ + function getAvgLag() { + $lag = 0; + $count = 0; + foreach ( $this->mServers as $i => $conn ) { + $conn = $this->getAnyOpenConnection( $i ); + if ( !$conn ) { + $conn = $this->openConnection( $i ); + } + if ( !$conn ) { + continue; + } + $lag += $conn->getLag(); + $count++; + } + return ($count > 1) ? $lag / $count : $lag; + } /** * Get lag time for each server diff --git a/index.php b/index.php index 1cbba1e89f..bbc77e58ed 100644 --- a/index.php +++ b/index.php @@ -53,6 +53,11 @@ if( !is_null( $maxLag ) && !$mediaWiki->checkMaxLag( $maxLag ) ) { exit; } +$avgLag = $wgRequest->getVal( 'avglag' ); +if( !is_null( $avgLag ) && !$mediaWiki->checkAvgLag( $avgLag ) ) { + exit; +} + # Query string fields $action = $wgRequest->getVal( 'action', 'view' ); $title = $wgRequest->getVal( 'title' ); -- 2.20.1