Merge "Add statsd metric support to WANObjectCache"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Wed, 1 Nov 2017 01:19:08 +0000 (01:19 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 1 Nov 2017 01:19:08 +0000 (01:19 +0000)
1  2 
includes/DefaultSettings.php
includes/libs/objectcache/WANObjectCache.php

@@@ -6351,7 -6351,9 +6351,9 @@@ $wgStatsdMetricPrefix = 'MediaWiki'
   * Rates are sampling probabilities (e.g. 0.1 means 1 in 10 events are sampled).
   * @since 1.28
   */
- $wgStatsdSamplingRates = [];
+ $wgStatsdSamplingRates = [
+       'wanobjectcache:*' => 0.001
+ ];
  
  /**
   * InfoAction retrieves a list of transclusion links (both to and from).
@@@ -6804,10 -6806,6 +6806,10 @@@ $wgRCWatchCategoryMembership = false
  /**
   * Use RC Patrolling to check for vandalism (from recent changes and watchlists)
   * New pages and new files are included.
 + *
 + * @note If you disable all patrolling features, you probably also want to
 + *  remove 'patrol' from $wgFilterLogTypes so a show/hide link isn't shown on
 + *  Special:Log.
   */
  $wgUseRCPatrol = true;
  
@@@ -6839,20 -6837,12 +6841,20 @@@ $wgStructuredChangeFiltersLiveUpdatePol
  
  /**
   * Use new page patrolling to check new pages on Special:Newpages
 + *
 + * @note If you disable all patrolling features, you probably also want to
 + *  remove 'patrol' from $wgFilterLogTypes so a show/hide link isn't shown on
 + *  Special:Log.
   */
  $wgUseNPPatrol = true;
  
  /**
   * Use file patrolling to check new files on Special:Newfiles
   *
 + * @note If you disable all patrolling features, you probably also want to
 + *  remove 'patrol' from $wgFilterLogTypes so a show/hide link isn't shown on
 + *  Special:Log.
 + *
   * @since 1.27
   */
  $wgUseFilePatrol = true;
@@@ -19,6 -19,7 +19,7 @@@
   * @ingroup Cache
   */
  
+ use Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface;
  use Psr\Log\LoggerAwareInterface;
  use Psr\Log\LoggerInterface;
  use Psr\Log\NullLogger;
@@@ -88,6 -89,8 +89,8 @@@ class WANObjectCache implements IExpiri
        protected $purgeRelayer;
        /** @var LoggerInterface */
        protected $logger;
+       /** @var StatsdDataFactoryInterface */
+       protected $stats;
  
        /** @var int ERR_* constant for the "last error" registry */
        protected $lastRelayError = self::ERR_NONE;
         *   - channels : Map of (action => channel string). Actions include "purge".
         *   - relayers : Map of (action => EventRelayer object). Actions include "purge".
         *   - logger   : LoggerInterface object
+        *   - stats    : LoggerInterface object
         */
        public function __construct( array $params ) {
                $this->cache = $params['cache'];
                        ? $params['relayers']['purge']
                        : new EventRelayerNull( [] );
                $this->setLogger( isset( $params['logger'] ) ? $params['logger'] : new NullLogger() );
+               $this->stats = isset( $params['stats'] ) ? $params['stats'] : new NullStatsdDataFactory();
        }
  
        public function setLogger( LoggerInterface $logger ) {
         * Consider using getWithSetCallback() instead of get() and set() cycles.
         * That method has cache slam avoiding features for hot/expensive keys.
         *
-        * @param string $key Cache key
+        * @param string $key Cache key made from makeKey() or makeGlobalKey()
         * @param mixed &$curTTL Approximate TTL left on the key if present/tombstoned [returned]
         * @param array $checkKeys List of "check" keys
         * @param float &$asOf UNIX timestamp of cached value; null on failure [returned]
         *
         * @see WANObjectCache::get()
         *
-        * @param array $keys List of cache keys
+        * @param array $keys List of cache keys made from makeKey() or makeGlobalKey()
         * @param array &$curTTLs Map of (key => approximate TTL left) for existing keys [returned]
         * @param array $checkKeys List of check keys to apply to all $keys. May also apply "check"
         *  keys to specific cache keys only by using cache keys as keys in the $checkKeys array.
         * @see WANObjectCache::get()
         * @see WANObjectCache::set()
         *
-        * @param string $key Cache key
+        * @param string $key Cache key made from makeKey() or makeGlobalKey()
         * @param int $ttl Seconds to live for key updates. Special values are:
         *   - WANObjectCache::TTL_INDEFINITE: Cache forever
         *   - WANObjectCache::TTL_UNCACHEABLE: Do not cache at all
                $minTime = isset( $opts['minAsOf'] ) ? $opts['minAsOf'] : self::MIN_TIMESTAMP_NONE;
                $versioned = isset( $opts['version'] );
  
+               // Get a collection name to describe this class of key
+               $kClass = $this->determineKeyClass( $key );
                // Get the current key value
                $curTTL = null;
                $cValue = $this->get( $key, $curTTL, $checkKeys, $asOf ); // current value
                        && !$this->worthRefreshExpiring( $curTTL, $lowTTL )
                        && !$this->worthRefreshPopular( $asOf, $ageNew, $popWindow, $preCallbackTime )
                ) {
+                       $this->stats->increment( "wanobjectcache.$kClass.hit.good" );
                        return $value;
                }
  
                                // Lock acquired; this thread should update the key
                                $lockAcquired = true;
                        } elseif ( $value !== false && $this->isValid( $value, $versioned, $asOf, $minTime ) ) {
+                               $this->stats->increment( "wanobjectcache.$kClass.hit.stale" );
                                // If it cannot be acquired; then the stale value can be used
                                return $value;
                        } else {
                                // use the INTERIM value from the last thread that regenerated it.
                                $value = $this->getInterimValue( $key, $versioned, $minTime, $asOf );
                                if ( $value !== false ) {
+                                       $this->stats->increment( "wanobjectcache.$kClass.hit.volatile" );
                                        return $value;
                                }
                                // Use the busy fallback value if nothing else
                                if ( $busyValue !== null ) {
+                                       $this->stats->increment( "wanobjectcache.$kClass.miss.busy" );
                                        return is_callable( $busyValue ) ? $busyValue() : $busyValue;
                                }
                        }
                        $this->cache->changeTTL( self::MUTEX_KEY_PREFIX . $key, (int)$preCallbackTime - 60 );
                }
  
+               $this->stats->increment( "wanobjectcache.$kClass.miss.compute" );
                return $value;
        }
  
         *             $setOpts += Database::getCacheSetOptions( $dbr );
         *
         *             // Load the row for this file
 -       *             $row = $dbr->selectRow( 'file', File::selectFields(), [ 'id' => $id ], __METHOD__ );
 +       *             $queryInfo = File::getQueryInfo();
 +       *             $row = $dbr->selectRow(
 +       *                 $queryInfo['tables'],
 +       *                 $queryInfo['fields'],
 +       *                 [ 'id' => $id ],
 +       *                 __METHOD__,
 +       *                 [],
 +       *                 $queryInfo['joins']
 +       *             );
         *
         *             return $row ? (array)$row : false;
         *         },
         *
         *             // Load the rows for these files
         *             $rows = [];
 -       *             $res = $dbr->select( 'file', File::selectFields(), [ 'id' => $ids ], __METHOD__ );
 +       *             $queryInfo = File::getQueryInfo();
 +       *             $res = $dbr->select(
 +       *                 $queryInfo['tables'],
 +       *                 $queryInfo['fields'],
 +       *                 [ 'id' => $ids ],
 +       *                 __METHOD__,
 +       *                 [],
 +       *                 $queryInfo['joins']
 +       *             );
         *             foreach ( $res as $row ) {
         *                 $rows[$row->id] = $row;
         *                 $mtime = wfTimestamp( TS_UNIX, $row->timestamp );
                return $res;
        }
  
+       /**
+        * @param string $key String of the format <scope>:<class>[:<class or variable>]...
+        * @return string
+        */
+       protected function determineKeyClass( $key ) {
+               $parts = explode( ':', $key );
+               return isset( $parts[1] ) ? $parts[1] : $parts[0]; // sanity
+       }
        /**
         * @param string $value Wrapped value like "PURGED:<timestamp>:<holdoff>"
         * @return array|bool Array containing a UNIX timestamp (float) and holdoff period (integer),