Skip to content

Commit 683c229

Browse files
committed
Improve go docs for core statistic structures and interfaces
Signed-off-by: Eric Zhao <[email protected]>
1 parent ea8c74f commit 683c229

File tree

4 files changed

+78
-54
lines changed

4 files changed

+78
-54
lines changed

core/base/stat.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ func (rs *nopReadStat) AvgRT() float64 {
8181
}
8282

8383
type WriteStat interface {
84+
// AddCount adds given count to the metric of provided MetricEvent.
8485
AddCount(event MetricEvent, count int64)
8586
}
8687

@@ -94,6 +95,7 @@ type nopWriteStat struct {
9495
func (ws *nopWriteStat) AddCount(_ MetricEvent, _ int64) {
9596
}
9697

98+
// ConcurrencyStat provides read/update operation for concurrency statistics.
9799
type ConcurrencyStat interface {
98100
CurrentConcurrency() int32
99101
IncreaseConcurrency()
@@ -126,10 +128,13 @@ func CheckValidityForStatistic(sampleCount, intervalInMs uint32) error {
126128
return nil
127129
}
128130

129-
// CheckValidityForReuseStatistic check the compliance whether readonly metric statistic can be built based on resource's global statistic
130-
// The parameters, sampleCount and intervalInMs, are the parameters of the metric statistic you want to build
131-
// The parameters, parentSampleCount and parentIntervalInMs, are the parameters of the resource's global statistic
132-
// If compliance passes, return nil, if not returns specific error
131+
// CheckValidityForReuseStatistic checks whether the read-only stat-metric with given attributes
132+
// (i.e. sampleCount and intervalInMs) can be built based on underlying global statistics data-structure
133+
// with given attributes (parentSampleCount and parentIntervalInMs). Returns nil if the attributes
134+
// satisfy the validation, or return specific error if not.
135+
//
136+
// The parameters, sampleCount and intervalInMs, are the attributes of the stat-metric view you want to build.
137+
// The parameters, parentSampleCount and parentIntervalInMs, are the attributes of the underlying statistics data-structure.
133138
func CheckValidityForReuseStatistic(sampleCount, intervalInMs uint32, parentSampleCount, parentIntervalInMs uint32) error {
134139
if intervalInMs == 0 || sampleCount == 0 || intervalInMs%sampleCount != 0 {
135140
return IllegalStatisticParamsError
@@ -141,11 +146,11 @@ func CheckValidityForReuseStatistic(sampleCount, intervalInMs uint32, parentSamp
141146
}
142147
parentBucketLengthInMs := parentIntervalInMs / parentSampleCount
143148

144-
//SlidingWindowMetric's intervalInMs is not divisible by BucketLeapArray's intervalInMs
149+
// intervalInMs of the SlidingWindowMetric is not divisible by BucketLeapArray's intervalInMs
145150
if parentIntervalInMs%intervalInMs != 0 {
146151
return GlobalStatisticNonReusableError
147152
}
148-
// BucketLeapArray's BucketLengthInMs is not divisible by SlidingWindowMetric's BucketLengthInMs
153+
// BucketLeapArray's BucketLengthInMs is not divisible by BucketLengthInMs of SlidingWindowMetric
149154
if bucketLengthInMs%parentBucketLengthInMs != 0 {
150155
return GlobalStatisticNonReusableError
151156
}

core/stat/base/bucket_leap_array.go

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import (
2424
"github.com/pkg/errors"
2525
)
2626

27-
// The implementation of sliding window based on LeapArray (as the sliding window infrastructure)
27+
// BucketLeapArray is the sliding window implementation based on LeapArray (as the sliding window infrastructure)
2828
// and MetricBucket (as the data type). The MetricBucket is used to record statistic
2929
// metrics per minimum time unit (i.e. the bucket time span).
3030
type BucketLeapArray struct {
@@ -42,11 +42,14 @@ func (bla *BucketLeapArray) ResetBucketTo(bw *BucketWrap, startTime uint64) *Buc
4242
return bw
4343
}
4444

45-
// sampleCount is the number of slots
46-
// intervalInMs is the time length of sliding window
47-
// sampleCount and intervalInMs must be positive and intervalInMs%sampleCount == 0,
48-
// the validation must be done before call NewBucketLeapArray
45+
// NewBucketLeapArray creates a BucketLeapArray with given attributes.
46+
//
47+
// The sampleCount represents the number of buckets, while intervalInMs represents
48+
// the total time span of sliding window. Note that the sampleCount and intervalInMs must be positive
49+
// and satisfies the condition that intervalInMs%sampleCount == 0.
50+
// The validation must be done before call NewBucketLeapArray.
4951
func NewBucketLeapArray(sampleCount uint32, intervalInMs uint32) *BucketLeapArray {
52+
// TODO: also check params here.
5053
bucketLengthInMs := intervalInMs / sampleCount
5154
ret := &BucketLeapArray{
5255
data: LeapArray{
@@ -82,9 +85,8 @@ func (bla *BucketLeapArray) GetIntervalInSecond() float64 {
8285
return float64(bla.IntervalInMs()) / 1000.0
8386
}
8487

85-
// Write method
86-
// It might panic
8788
func (bla *BucketLeapArray) AddCount(event base.MetricEvent, count int64) {
89+
// It might panic?
8890
bla.addCountWithTime(util.CurrentTimeMillis(), event, count)
8991
}
9092

@@ -131,9 +133,9 @@ func (bla *BucketLeapArray) currentBucketWithTime(now uint64) *MetricBucket {
131133
return b
132134
}
133135

134-
// Read method, need to adapt upper application
135-
// it might panic
136+
// Count returns the sum count for the given MetricEvent within all valid (non-expired) buckets.
136137
func (bla *BucketLeapArray) Count(event base.MetricEvent) int64 {
138+
// it might panic?
137139
return bla.CountWithTime(util.CurrentTimeMillis(), event)
138140
}
139141

@@ -159,12 +161,14 @@ func (bla *BucketLeapArray) CountWithTime(now uint64, event base.MetricEvent) in
159161
return count
160162
}
161163

162-
// Read method, get all BucketWrap.
164+
// Values returns all valid (non-expired) buckets.
163165
func (bla *BucketLeapArray) Values(now uint64) []*BucketWrap {
166+
// Refresh current bucket if necessary.
164167
_, err := bla.data.currentBucketOfTime(now, bla)
165168
if err != nil {
166-
logging.Error(err, "Failed to get current bucket in BucketLeapArray.Values()", "now", now)
169+
logging.Error(err, "Failed to refresh current bucket in BucketLeapArray.Values()", "now", now)
167170
}
171+
168172
return bla.data.valuesWithTime(now)
169173
}
170174

core/stat/base/leap_array.go

Lines changed: 44 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,16 @@ import (
2626
"github.com/pkg/errors"
2727
)
2828

29-
// BucketWrap represent a slot to record metrics
30-
// In order to reduce the usage of memory, BucketWrap don't hold length of BucketWrap
29+
// BucketWrap represents a slot to record metrics.
30+
//
31+
// In order to reduce memory footprint, BucketWrap does not hold the length of the bucket.
3132
// The length of BucketWrap could be seen in LeapArray.
32-
// The scope of time is [startTime, startTime+bucketLength)
33-
// The size of BucketWrap is 24(8+16) bytes
33+
// The scope of time is [startTime, startTime+bucketLength).
34+
// The size of BucketWrap is 24(8+16) bytes.
3435
type BucketWrap struct {
35-
// The start timestamp of this statistic bucket wrapper.
36+
// BucketStart represents start timestamp of this statistic bucket wrapper.
3637
BucketStart uint64
37-
// The actual data structure to record the metrics (e.g. MetricBucket).
38+
// Value represents the actual data structure of the metrics (e.g. MetricBucket).
3839
Value atomic.Value
3940
}
4041

@@ -50,8 +51,9 @@ func calculateStartTime(now uint64, bucketLengthInMs uint32) uint64 {
5051
return now - (now % uint64(bucketLengthInMs))
5152
}
5253

53-
// atomic BucketWrap array to resolve race condition
54-
// AtomicBucketWrapArray can not append or delete element after initializing
54+
// AtomicBucketWrapArray represents a thread-safe circular array.
55+
//
56+
// The length of the array should be provided on-create and cannot be modified.
5557
type AtomicBucketWrapArray struct {
5658
// The base address for real data array
5759
base unsafe.Pointer
@@ -94,11 +96,11 @@ func NewAtomicBucketWrapArrayWithTime(len int, bucketLengthInMs uint32, now uint
9496
return ret
9597
}
9698

97-
// New AtomicBucketWrapArray with initializing field data
98-
// Default, automatically initialize each BucketWrap
99-
// len: length of array
100-
// bucketLengthInMs: bucket length of BucketWrap
101-
// generator: generator to generate bucket
99+
// NewAtomicBucketWrapArray creates an AtomicBucketWrapArray and initializes data of each BucketWrap.
100+
//
101+
// The len represents the length of the circular array.
102+
// The bucketLengthInMs represents bucket length of each bucket (in milliseconds).
103+
// The generator accepts a BucketGenerator to generate and refresh buckets.
102104
func NewAtomicBucketWrapArray(len int, bucketLengthInMs uint32, generator BucketGenerator) *AtomicBucketWrapArray {
103105
return NewAtomicBucketWrapArrayWithTime(len, bucketLengthInMs, util.CurrentTimeMillis(), generator)
104106
}
@@ -133,23 +135,30 @@ func (aa *AtomicBucketWrapArray) compareAndSet(idx int, except, update *BucketWr
133135
return false
134136
}
135137

136-
// The BucketWrap leap array,
137-
// sampleCount represent the number of BucketWrap
138-
// intervalInMs represent the interval of LeapArray.
139-
// For example, bucketLengthInMs is 200ms, intervalInMs is 1000ms, so sampleCount is 5.
140-
// Give a diagram to illustrate
141-
// Suppose current time is 888, bucketLengthInMs is 200ms, intervalInMs is 1000ms, LeapArray will build the below windows
138+
// LeapArray represents the fundamental implementation of a sliding window data-structure.
139+
//
140+
// Some important attributes: the sampleCount represents the number of buckets,
141+
// while intervalInMs represents the total time span of the sliding window.
142+
//
143+
// For example, assuming sampleCount=5, intervalInMs is 1000ms, so the bucketLength is 200ms.
144+
// Let's give a diagram to illustrate.
145+
// Suppose current timestamp is 1188, bucketLength is 200ms, intervalInMs is 1000ms, then
146+
// time span of current bucket is [1000, 1200). The representation of the underlying structure:
147+
//
142148
// B0 B1 B2 B3 B4
143149
// |_______|_______|_______|_______|_______|
144-
// 1000 1200 1400 1600 800 (1000)
145-
// ^
146-
// time=888
150+
// 1000 1200 400 600 800 (1000) ms
151+
// ^
152+
// time=1188
147153
type LeapArray struct {
148154
bucketLengthInMs uint32
149-
sampleCount uint32
150-
intervalInMs uint32
151-
array *AtomicBucketWrapArray
152-
// update lock
155+
// sampleCount represents the number of BucketWrap.
156+
sampleCount uint32
157+
// intervalInMs represents the total time span of the sliding window (in milliseconds).
158+
intervalInMs uint32
159+
// array represents the internal circular array.
160+
array *AtomicBucketWrapArray
161+
// updateLock is the internal lock for update operations.
153162
updateLock mutex
154163
}
155164

@@ -224,7 +233,8 @@ func (la *LeapArray) calculateTimeIdx(now uint64) int {
224233
return int(timeId) % la.array.length
225234
}
226235

227-
// Get all BucketWrap between [current time - leap array interval, current time]
236+
// Values returns all valid (non-expired) buckets between [curBucketEnd-windowInterval, curBucketEnd],
237+
// where curBucketEnd=curBucketStart+bucketLength.
228238
func (la *LeapArray) Values() []*BucketWrap {
229239
return la.valuesWithTime(util.CurrentTimeMillis())
230240
}
@@ -244,6 +254,8 @@ func (la *LeapArray) valuesWithTime(now uint64) []*BucketWrap {
244254
return ret
245255
}
246256

257+
// ValuesConditional returns all buckets of which the startTimestamp satisfies the given timestamp condition (predicate).
258+
// The function uses the parameter "now" as the target timestamp.
247259
func (la *LeapArray) ValuesConditional(now uint64, predicate base.TimePredicate) []*BucketWrap {
248260
if now <= 0 {
249261
return make([]*BucketWrap, 0)
@@ -259,17 +271,17 @@ func (la *LeapArray) ValuesConditional(now uint64, predicate base.TimePredicate)
259271
return ret
260272
}
261273

262-
// Judge whether the BucketWrap is expired
274+
// isBucketDeprecated checks whether the BucketWrap is expired, according to given timestamp.
263275
func (la *LeapArray) isBucketDeprecated(now uint64, ww *BucketWrap) bool {
264276
ws := atomic.LoadUint64(&ww.BucketStart)
265277
return (now - ws) > uint64(la.intervalInMs)
266278
}
267279

268-
// Generic interface to generate bucket
280+
// BucketGenerator represents the "generic" interface for generating and refreshing buckets.
269281
type BucketGenerator interface {
270-
// called when timestamp entry a new slot interval
282+
// NewEmptyBucket creates new raw data inside the bucket.
271283
NewEmptyBucket() interface{}
272284

273-
// reset the BucketWrap, clear all data of BucketWrap
274-
ResetBucketTo(bw *BucketWrap, startTime uint64) *BucketWrap
285+
// ResetBucketTo refreshes the BucketWrap to provided startTime and resets all data inside the given bucket.
286+
ResetBucketTo(bucket *BucketWrap, startTime uint64) *BucketWrap
275287
}

core/stat/base/sliding_window_metric.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,18 @@ import (
2525
)
2626

2727
// SlidingWindowMetric represents the sliding window metric wrapper.
28-
// It does not store any data and is the wrapper of BucketLeapArray to adapt to different internal bucket
29-
// SlidingWindowMetric is used for SentinelRules and BucketLeapArray is used for monitor
30-
// BucketLeapArray is per resource, and SlidingWindowMetric support only read operation.
28+
// It does not store any data and is the wrapper of BucketLeapArray to adapt to different internal bucket.
29+
//
30+
// SlidingWindowMetric is designed as a high-level, read-only statistic structure for functionalities of Sentinel
3131
type SlidingWindowMetric struct {
3232
bucketLengthInMs uint32
3333
sampleCount uint32
3434
intervalInMs uint32
3535
real *BucketLeapArray
3636
}
3737

38-
// It must pass the parameter point to the real storage entity
38+
// NewSlidingWindowMetric creates a SlidingWindowMetric with given attributes.
39+
// The pointer to the internal statistic BucketLeapArray should be valid.
3940
func NewSlidingWindowMetric(sampleCount, intervalInMs uint32, real *BucketLeapArray) (*SlidingWindowMetric, error) {
4041
if real == nil {
4142
return nil, errors.New("nil BucketLeapArray")
@@ -53,7 +54,7 @@ func NewSlidingWindowMetric(sampleCount, intervalInMs uint32, real *BucketLeapAr
5354
}, nil
5455
}
5556

56-
// Get the start time range of the bucket for the provided time.
57+
// getBucketStartRange returns start time range of the bucket for the provided time.
5758
// The actual time span is: [start, end + in.bucketTimeLength)
5859
func (m *SlidingWindowMetric) getBucketStartRange(timeMs uint64) (start, end uint64) {
5960
curBucketStartTime := calculateStartTime(timeMs, m.real.BucketLengthInMs())
@@ -107,6 +108,8 @@ func (m *SlidingWindowMetric) getQPSWithTime(now uint64, event base.MetricEvent)
107108

108109
func (m *SlidingWindowMetric) getSatisfiedBuckets(now uint64) []*BucketWrap {
109110
start, end := m.getBucketStartRange(now)
111+
// Extracts the buckets of which the startTime is between [start, end]
112+
// which means the time view of the buckets is [firstStart, endStart+bucketLength)
110113
satisfiedBuckets := m.real.ValuesConditional(now, func(ws uint64) bool {
111114
return ws >= start && ws <= end
112115
})

0 commit comments

Comments
 (0)