core/base/stat.go (95 lines of code) (raw):
// Copyright 1999-2020 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package base
import (
"errors"
)
type TimePredicate func(uint64) bool
type MetricEvent int8
// There are five events to record
// pass + block == Total
const (
// sentinel rules check pass
MetricEventPass MetricEvent = iota
// sentinel rules check block
MetricEventBlock
MetricEventComplete
// Biz error, used for circuit breaker
MetricEventError
// request execute rt, unit is millisecond
MetricEventRt
// hack for the number of event
MetricEventTotal
)
var (
globalNopReadStat = &nopReadStat{}
globalNopWriteStat = &nopWriteStat{}
)
type ReadStat interface {
GetQPS(event MetricEvent) float64
GetPreviousQPS(event MetricEvent) float64
GetSum(event MetricEvent) int64
MinRT() float64
AvgRT() float64
}
func NopReadStat() *nopReadStat {
return globalNopReadStat
}
type nopReadStat struct {
}
func (rs *nopReadStat) GetQPS(_ MetricEvent) float64 {
return 0.0
}
func (rs *nopReadStat) GetPreviousQPS(_ MetricEvent) float64 {
return 0.0
}
func (rs *nopReadStat) GetSum(_ MetricEvent) int64 {
return 0
}
func (rs *nopReadStat) MinRT() float64 {
return 0.0
}
func (rs *nopReadStat) AvgRT() float64 {
return 0.0
}
type WriteStat interface {
// AddCount adds given count to the metric of provided MetricEvent.
AddCount(event MetricEvent, count int64)
}
func NopWriteStat() *nopWriteStat {
return globalNopWriteStat
}
type nopWriteStat struct {
}
func (ws *nopWriteStat) AddCount(_ MetricEvent, _ int64) {
}
// ConcurrencyStat provides read/update operation for concurrency statistics.
type ConcurrencyStat interface {
CurrentConcurrency() int32
IncreaseConcurrency()
DecreaseConcurrency()
}
// StatNode holds real-time statistics for resources.
type StatNode interface {
MetricItemRetriever
ReadStat
WriteStat
ConcurrencyStat
// GenerateReadStat generates the readonly metric statistic based on resource level global statistic
// If parameters, sampleCount and intervalInMs, are not suitable for resource level global statistic, return (nil, error)
GenerateReadStat(sampleCount uint32, intervalInMs uint32) (ReadStat, error)
}
var (
IllegalGlobalStatisticParamsError = errors.New("Invalid parameters, sampleCount or interval, for resource's global statistic")
IllegalStatisticParamsError = errors.New("Invalid parameters, sampleCount or interval, for metric statistic")
GlobalStatisticNonReusableError = errors.New("The parameters, sampleCount and interval, mismatch for reusing between resource's global statistic and readonly metric statistic.")
)
func CheckValidityForStatistic(sampleCount, intervalInMs uint32) error {
if intervalInMs == 0 || sampleCount == 0 || intervalInMs%sampleCount != 0 {
return IllegalStatisticParamsError
}
return nil
}
// CheckValidityForReuseStatistic checks whether the read-only stat-metric with given attributes
// (i.e. sampleCount and intervalInMs) can be built based on underlying global statistics data-structure
// with given attributes (parentSampleCount and parentIntervalInMs). Returns nil if the attributes
// satisfy the validation, or return specific error if not.
//
// The parameters, sampleCount and intervalInMs, are the attributes of the stat-metric view you want to build.
// The parameters, parentSampleCount and parentIntervalInMs, are the attributes of the underlying statistics data-structure.
func CheckValidityForReuseStatistic(sampleCount, intervalInMs uint32, parentSampleCount, parentIntervalInMs uint32) error {
if intervalInMs == 0 || sampleCount == 0 || intervalInMs%sampleCount != 0 {
return IllegalStatisticParamsError
}
bucketLengthInMs := intervalInMs / sampleCount
if parentIntervalInMs == 0 || parentSampleCount == 0 || parentIntervalInMs%parentSampleCount != 0 {
return IllegalGlobalStatisticParamsError
}
parentBucketLengthInMs := parentIntervalInMs / parentSampleCount
// intervalInMs of the SlidingWindowMetric is not divisible by BucketLeapArray's intervalInMs
if parentIntervalInMs%intervalInMs != 0 {
return GlobalStatisticNonReusableError
}
// BucketLeapArray's BucketLengthInMs is not divisible by BucketLengthInMs of SlidingWindowMetric
if bucketLengthInMs%parentBucketLengthInMs != 0 {
return GlobalStatisticNonReusableError
}
return nil
}