17 private $queuedValues = [];
21 private $prefixComponents;
30 $this->store = $store;
31 $this->metricSpecs = [];
32 foreach ( $specs as $name => $spec ) {
33 $this->metricSpecs[$name] =
new MetricSpec( $spec );
35 $this->prefixComponents = is_array( $prefix ) ? $prefix : [ $prefix ];
36 if ( !count( $this->prefixComponents ) ) {
38 ': there must be at least one prefix component' );
50 $metricSpec = $this->metricSpecs[$name] ??
null;
52 if ( $metricSpec ===
null ) {
53 throw new WRStatsError(
"Unrecognised metric \"$name\"" );
55 $res = $metricSpec->resolution;
56 $scaledValue = $value / $res;
58 foreach ( $metricSpec->sequences as $seqSpec ) {
59 $timeStep = $seqSpec->timeStep;
60 $timeBucket = (int)( $this->now() / $timeStep );
61 $key = $this->store->makeKey(
62 $this->prefixComponents,
63 [ $name, $seqSpec->name, $timeBucket ],
67 $ttl = $seqSpec->hardExpiry;
69 if ( !isset( $this->queuedValues[$ttl][$key] ) ) {
70 $this->queuedValues[$ttl][$key] = 0;
72 $this->queuedValues[$ttl][$key] += (int)round( $scaledValue );
98 private function now() {
99 $this->now ??= microtime(
true );
107 foreach ( $this->queuedValues as $ttl => $values ) {
108 $this->store->incr( $values, $ttl );
110 $this->queuedValues = [];
127 public function resetAll( ?array $entities =
null ) {
129 $this->queuedValues = [];
131 foreach ( $this->metricSpecs as $name => $metricSpec ) {
132 foreach ( $metricSpec->sequences as $seqSpec ) {
133 $timeStep = $seqSpec->timeStep;
134 $ttl = $seqSpec->hardExpiry;
135 $lastBucket = (int)( $this->now() / $timeStep ) + 1;
136 $firstBucket = (int)( ( $this->now() - $ttl ) / $timeStep ) - 1;
137 for ( $bucket = $firstBucket; $bucket <= $lastBucket; $bucket++ ) {
138 foreach ( $entities as $entity ) {
139 $keys[] = $this->store->makeKey(
140 $this->prefixComponents,
141 [ $name, $seqSpec->name, $bucket ],
148 $this->store->delete( $keys );