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 );
180 $timeStep = $seqSpec->timeStep;
181 $firstBucket = (int)( $range->start / $timeStep );
182 $lastBucket = (int)( $range->end / $timeStep );
185 for ( $bucket = $firstBucket; $bucket <= $lastBucket; $bucket++ ) {
186 $key = $this->store->makeKey(
187 $this->prefixComponents,
188 [ $metricName, $seqSpec->name, $bucket ],
191 $value = $this->cachedValues[$key] ?? 0;
194 } elseif ( $bucket === $firstBucket ) {
195 if ( $bucket === $lastBucket ) {
197 $bucketStartTime = $bucket * $timeStep;
198 $rateInterpolationEndTime = min( $bucketStartTime + $timeStep, $now );
199 $interpolationDuration = $rateInterpolationEndTime - $bucketStartTime;
200 if ( $interpolationDuration > 0 ) {
201 $total += $value * $range->
getDuration() / $interpolationDuration;
204 $overlapDuration = max( ( $bucket + 1 ) * $timeStep - $range->start, 0 );
205 $total += $value * $overlapDuration / $timeStep;
207 } elseif ( $bucket === $lastBucket ) {
209 $bucketStartTime = $bucket * $timeStep;
210 $rateInterpolationEndTime = min( $bucketStartTime + $timeStep, $now );
211 $overlapDuration = max( $range->end - $bucketStartTime, 0 );
212 $interpolationDuration = $rateInterpolationEndTime - $bucketStartTime;
213 if ( $overlapDuration === $interpolationDuration ) {
216 } elseif ( $interpolationDuration > 0 ) {
217 $total += $value * $overlapDuration / $interpolationDuration;
224 $rounded = round( $total ) * $metricSpec->resolution;
226 if ( is_int( $metricSpec->resolution ) ) {
227 $rounded = (int)$rounded;