MediaWiki  master
WRStatsWriter.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Wikimedia\WRStats;
4 
13  private $store;
15  private $metricSpecs;
17  private $queuedValues = [];
19  private $now;
21  private $prefixComponents;
22 
30  public function __construct( StatsStore $store, $specs, $prefix ) {
31  $this->store = $store;
32  $this->metricSpecs = [];
33  foreach ( $specs as $name => $spec ) {
34  $this->metricSpecs[$name] = new MetricSpec( $spec );
35  }
36  $this->prefixComponents = is_array( $prefix ) ? $prefix : [ $prefix ];
37  if ( !count( $this->prefixComponents ) ) {
38  throw new WRStatsError( __METHOD__ .
39  ': there must be at least one prefix component' );
40  }
41  }
42 
50  public function incr( $name, ?EntityKey $entity = null, $value = 1 ) {
51  $metricSpec = $this->metricSpecs[$name] ?? null;
52  $entity ??= new LocalEntityKey;
53  if ( $metricSpec === null ) {
54  throw new WRStatsError( __METHOD__ . ": Unrecognised metric \"$name\"" );
55  }
56  $res = $metricSpec->resolution;
57  $scaledValue = $value / $res;
58 
59  foreach ( $metricSpec->sequences as $seqSpec ) {
60  $timeStep = $seqSpec->timeStep;
61  $timeBucket = (int)( $this->now() / $timeStep );
62  $key = $this->store->makeKey(
63  $this->prefixComponents,
64  [ $name, $seqSpec->name, $timeBucket ],
65  $entity
66  );
67 
68  $ttl = $seqSpec->hardExpiry;
69 
70  if ( !isset( $this->queuedValues[$ttl][$key] ) ) {
71  $this->queuedValues[$ttl][$key] = 0;
72  }
73  $this->queuedValues[$ttl][$key] += (int)round( $scaledValue );
74  }
75  }
76 
82  public function setCurrentTime( $now ) {
83  $this->now = $now;
84  }
85 
92  public function resetCurrentTime() {
93  $this->now = null;
94  }
95 
99  private function now() {
100  $this->now ??= microtime( true );
101  return $this->now;
102  }
103 
107  public function flush() {
108  foreach ( $this->queuedValues as $ttl => $values ) {
109  $this->store->incr( $values, $ttl );
110  }
111  $this->queuedValues = [];
112  }
113 
117  public function __destruct() {
118  $this->flush();
119  }
120 
128  public function resetAll( ?array $entities = null ) {
129  $entities ??= [ new LocalEntityKey ];
130  $this->queuedValues = [];
131  $keys = [];
132  foreach ( $this->metricSpecs as $name => $metricSpec ) {
133  foreach ( $metricSpec->sequences as $seqSpec ) {
134  $timeStep = $seqSpec->timeStep;
135  $ttl = $seqSpec->hardExpiry;
136  $lastBucket = (int)( $this->now() / $timeStep ) + 1;
137  $firstBucket = (int)( ( $this->now() - $ttl ) / $timeStep ) - 1;
138  for ( $bucket = $firstBucket; $bucket <= $lastBucket; $bucket++ ) {
139  foreach ( $entities as $entity ) {
140  $keys[] = $this->store->makeKey(
141  $this->prefixComponents,
142  [ $name, $seqSpec->name, $bucket ],
143  $entity
144  );
145  }
146  }
147  }
148  }
149  $this->store->delete( $keys );
150  }
151 }
Base class for entity keys.
Definition: EntityKey.php:13
Entity key with global=false.
Class representation of normalized metric specifications.
Definition: MetricSpec.php:10
Exception class for errors thrown by the WRStats library.
Writers gather a batch of increment operations and then commit them when flush() is called,...
resetCurrentTime()
Reset the stored current time.
incr( $name, ?EntityKey $entity=null, $value=1)
Queue an increment operation.
__construct(StatsStore $store, $specs, $prefix)
resetAll(?array $entities=null)
Delete all stored metrics corresponding to the specs supplied to the constructor, resetting the count...
__destruct()
Commit the batch of increment operations.
setCurrentTime( $now)
Set the time to be used as the current time.
flush()
Commit the batch of increment operations.
The narrow interface WRStats needs into a memcached-like key-value store.
Definition: StatsStore.php:10