From 5f1e95436eac69fb7d02a538ac20b4215391e2b6 Mon Sep 17 00:00:00 2001 From: Aaron Schulz Date: Thu, 28 Mar 2013 13:18:30 -0700 Subject: [PATCH] Avoid sending multiple UDP packets for the same key in wfIncrStats(). * This should help reduce collector data loss. Change-Id: Ibe55648422d1b8aac86dd6fa83973d3c8715b0aa --- includes/AutoLoader.php | 1 + includes/GlobalFunctions.php | 48 +----------- includes/StatCounter.php | 141 +++++++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+), 45 deletions(-) create mode 100644 includes/StatCounter.php diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php index 0b3c788d61..9ef3165258 100644 --- a/includes/AutoLoader.php +++ b/includes/AutoLoader.php @@ -243,6 +243,7 @@ $wgAutoloadLocalClasses = array( 'SpecialRedirectToSpecial' => 'includes/SpecialPage.php', 'SquidPurgeClient' => 'includes/SquidPurgeClient.php', 'SquidPurgeClientPool' => 'includes/SquidPurgeClient.php', + 'StatCounter' => 'includes/StatCounter.php', 'Status' => 'includes/Status.php', 'StreamFile' => 'includes/StreamFile.php', 'StringUtils' => 'includes/StringUtils.php', diff --git a/includes/GlobalFunctions.php b/includes/GlobalFunctions.php index 90429268e9..1a4b985c41 100644 --- a/includes/GlobalFunctions.php +++ b/includes/GlobalFunctions.php @@ -1177,6 +1177,8 @@ function wfLogProfilingData() { global $wgRequestTime, $wgDebugLogFile, $wgDebugRawPage, $wgRequest; global $wgProfileLimit, $wgUser; + StatCounter::singleton()->flush(); + $profiler = Profiler::instance(); # Profiling must actually be enabled... @@ -1240,51 +1242,7 @@ function wfLogProfilingData() { * @return void */ function wfIncrStats( $key, $count = 1 ) { - global $wgStatsMethod; - - $count = intval( $count ); - if ( $count == 0 ) { - return; - } - - if( $wgStatsMethod == 'udp' ) { - global $wgUDPProfilerHost, $wgUDPProfilerPort, $wgAggregateStatsID; - static $socket; - - $id = $wgAggregateStatsID !== false ? $wgAggregateStatsID : wfWikiID(); - - if ( !$socket ) { - $socket = socket_create( AF_INET, SOCK_DGRAM, SOL_UDP ); - $statline = "stats/{$id} - 1 1 1 1 1 -total\n"; - socket_sendto( - $socket, - $statline, - strlen( $statline ), - 0, - $wgUDPProfilerHost, - $wgUDPProfilerPort - ); - } - $statline = "stats/{$id} - {$count} 1 1 1 1 {$key}\n"; - wfSuppressWarnings(); - socket_sendto( - $socket, - $statline, - strlen( $statline ), - 0, - $wgUDPProfilerHost, - $wgUDPProfilerPort - ); - wfRestoreWarnings(); - } elseif( $wgStatsMethod == 'cache' ) { - global $wgMemc; - $key = wfMemcKey( 'stats', $key ); - if ( is_null( $wgMemc->incr( $key, $count ) ) ) { - $wgMemc->add( $key, $count ); - } - } else { - // Disabled - } + StatCounter::singleton()->incr( $key, $count ); } /** diff --git a/includes/StatCounter.php b/includes/StatCounter.php new file mode 100644 index 0000000000..30e504219b --- /dev/null +++ b/includes/StatCounter.php @@ -0,0 +1,141 @@ + count) + + protected function __construct() {} + + public static function singleton() { + static $instance = null; + if ( !$instance ) { + $instance = new self(); + } + return $instance; + } + + /** + * Increment a key by delta $count + * + * @param string $key + * @param integer $count + * @return void + */ + public function incr( $key, $count = 1 ) { + if ( PHP_SAPI === 'cli' ) { + $this->sendDelta( $key, $count ); + } else { + if ( !isset( $this->deltas[$key] ) ) { + $this->deltas[$key] = 0; + } + $this->deltas[$key] += $count; + } + } + + /** + * Flush all pending deltas to persistent storage + * + * @return void + */ + public function flush() { + try { + foreach ( $this->deltas as $key => $count ) { + $this->sendDelta( $key, $count ); + } + } catch ( MWException $e ) { + trigger_error( "Caught exception: {$e->getMessage()}"); + } + $this->deltas = array(); + } + + /** + * @param string $key + * @param string $count + * @return void + */ + protected function sendDelta( $key, $count ) { + global $wgStatsMethod; + + $count = intval( $count ); + if ( $count == 0 ) { + return; + } + + if ( $wgStatsMethod == 'udp' ) { + global $wgUDPProfilerHost, $wgUDPProfilerPort, $wgAggregateStatsID; + static $socket; + + $id = $wgAggregateStatsID !== false ? $wgAggregateStatsID : wfWikiID(); + + if ( !$socket ) { + $socket = socket_create( AF_INET, SOCK_DGRAM, SOL_UDP ); + $statline = "stats/{$id} - 1 1 1 1 1 -total\n"; + socket_sendto( + $socket, + $statline, + strlen( $statline ), + 0, + $wgUDPProfilerHost, + $wgUDPProfilerPort + ); + } + $statline = "stats/{$id} - {$count} 1 1 1 1 {$key}\n"; + wfSuppressWarnings(); + socket_sendto( + $socket, + $statline, + strlen( $statline ), + 0, + $wgUDPProfilerHost, + $wgUDPProfilerPort + ); + wfRestoreWarnings(); + } elseif ( $wgStatsMethod == 'cache' ) { + global $wgMemc; + $key = wfMemcKey( 'stats', $key ); + if ( is_null( $wgMemc->incr( $key, $count ) ) ) { + $wgMemc->add( $key, $count ); + } + } else { + // Disabled + } + } + + function __destruct() { + $this->flush(); + } +} -- 2.20.1