32 $this->store = $store;
33 $this->metricSpecs = [];
34 foreach ( $specs as $name => $spec ) {
35 $this->metricSpecs[$name] =
new MetricSpec( $spec );
37 $this->prefixComponents = is_array( $prefix ) ? $prefix : [ $prefix ];
38 if ( !count( $this->prefixComponents ) ) {
40 ': there must be at least one prefix component' );
77 $metricSpec = $this->metricSpecs[$metricName] ??
null;
78 if ( $metricSpec ===
null ) {
79 throw new WRStatsError(
"Unrecognised metric \"$metricName\"" );
84 foreach ( $metricSpec->sequences as $seqSpec ) {
85 $seqStart = $now - $seqSpec->softExpiry;
86 if ( $seqStart <= $range->start ) {
90 $timeStep = $seqSpec->timeStep;
91 $firstBucket = (int)( $range->start / $timeStep );
92 $lastBucket = (int)ceil( $range->end / $timeStep );
93 for ( $bucket = $firstBucket; $bucket <= $lastBucket; $bucket++ ) {
94 $key = $this->store->makeKey(
95 $this->prefixComponents,
96 [ $metricName, $seqSpec->name, $bucket ],
99 if ( !isset( $this->cachedValues[$key] ) ) {
100 $this->queuedKeys[$key] =
true;
103 return new RatePromise( $this, $metricName, $entity, $metricSpec, $seqSpec, $range );
176 $timeStep = $seqSpec->timeStep;
177 $firstBucket = (int)( $range->start / $timeStep );
178 $lastBucket = (int)( $range->end / $timeStep );
181 for ( $bucket = $firstBucket; $bucket <= $lastBucket; $bucket++ ) {
182 $key = $this->store->makeKey(
183 $this->prefixComponents,
184 [ $metricName, $seqSpec->name, $bucket ],
187 $value = $this->cachedValues[$key] ?? 0;
190 } elseif ( $bucket === $firstBucket ) {
191 if ( $bucket === $lastBucket ) {
193 $bucketStartTime = $bucket * $timeStep;
194 $rateInterpolationEndTime = min( $bucketStartTime + $timeStep, $now );
195 $interpolationDuration = $rateInterpolationEndTime - $bucketStartTime;
196 if ( $interpolationDuration > 0 ) {
197 $total += $value * $range->
getDuration() / $interpolationDuration;
200 $overlapDuration = max( ( $bucket + 1 ) * $timeStep - $range->start, 0 );
201 $total += $value * $overlapDuration / $timeStep;
203 } elseif ( $bucket === $lastBucket ) {
205 $bucketStartTime = $bucket * $timeStep;
206 $rateInterpolationEndTime = min( $bucketStartTime + $timeStep, $now );
207 $overlapDuration = max( $range->end - $bucketStartTime, 0 );
208 $interpolationDuration = $rateInterpolationEndTime - $bucketStartTime;
209 if ( $overlapDuration === $interpolationDuration ) {
212 } elseif ( $interpolationDuration > 0 ) {
213 $total += $value * $overlapDuration / $interpolationDuration;
220 $rounded = round( $total ) * $metricSpec->resolution;
222 if ( is_int( $metricSpec->resolution ) ) {
223 $rounded = (int)$rounded;