33 $this->store = $store;
34 $this->metricSpecs = [];
35 foreach ( $specs as $name => $spec ) {
36 $this->metricSpecs[$name] =
new MetricSpec( $spec );
38 $this->prefixComponents = is_array( $prefix ) ? $prefix : [ $prefix ];
39 if ( !count( $this->prefixComponents ) ) {
41 ': there must be at least one prefix component' );
78 $metricSpec = $this->metricSpecs[$metricName] ??
null;
79 if ( $metricSpec ===
null ) {
80 throw new WRStatsError( __METHOD__ .
": Unrecognised metric \"$metricName\"" );
85 foreach ( $metricSpec->sequences as $seqSpec ) {
86 $seqStart = $now - $seqSpec->softExpiry;
87 if ( $seqStart <= $range->start ) {
91 $timeStep = $seqSpec->timeStep;
92 $firstBucket = (int)( $range->start / $timeStep );
93 $lastBucket = (int)ceil( $range->end / $timeStep );
94 for ( $bucket = $firstBucket; $bucket <= $lastBucket; $bucket++ ) {
95 $key = $this->store->makeKey(
96 $this->prefixComponents,
97 [ $metricName, $seqSpec->name, $bucket ],
100 if ( !isset( $this->cachedValues[$key] ) ) {
101 $this->queuedKeys[$key] =
true;
104 return new RatePromise( $this, $metricName, $entity, $metricSpec, $seqSpec, $range );
178 $timeStep = $seqSpec->timeStep;
179 $firstBucket = (int)( $range->start / $timeStep );
180 $lastBucket = (int)( $range->end / $timeStep );
183 for ( $bucket = $firstBucket; $bucket <= $lastBucket; $bucket++ ) {
184 $key = $this->store->makeKey(
185 $this->prefixComponents,
186 [ $metricName, $seqSpec->name, $bucket ],
189 $value = $this->cachedValues[$key] ?? 0;
192 } elseif ( $bucket === $firstBucket ) {
193 if ( $bucket === $lastBucket ) {
195 $bucketStartTime = $bucket * $timeStep;
196 $rateInterpolationEndTime = min( $bucketStartTime + $timeStep, $now );
197 $interpolationDuration = $rateInterpolationEndTime - $bucketStartTime;
198 if ( $interpolationDuration > 0 ) {
199 $total += $value * $range->
getDuration() / $interpolationDuration;
202 $overlapDuration = max( ( $bucket + 1 ) * $timeStep - $range->start, 0 );
203 $total += $value * $overlapDuration / $timeStep;
205 } elseif ( $bucket === $lastBucket ) {
207 $bucketStartTime = $bucket * $timeStep;
208 $rateInterpolationEndTime = min( $bucketStartTime + $timeStep, $now );
209 $overlapDuration = max( $range->end - $bucketStartTime, 0 );
210 $interpolationDuration = $rateInterpolationEndTime - $bucketStartTime;
211 if ( $overlapDuration === $interpolationDuration ) {
214 } elseif ( $interpolationDuration > 0 ) {
215 $total += $value * $overlapDuration / $interpolationDuration;
222 $rounded = round( $total ) * $metricSpec->resolution;
224 if ( is_int( $metricSpec->resolution ) ) {
225 $rounded = (int)$rounded;