Files
EdgeNode/internal/utils/counters/item.go
GoEdgeLab c19be78e0d v1.4.1
2024-07-27 15:42:50 +08:00

133 lines
2.9 KiB
Go

// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cloud .
package counters
import (
"github.com/TeaOSLab/EdgeNode/internal/utils/fasttime"
)
const spanMaxValue = 10_000_000
const maxSpans = 10
type Item[T SupportedUIntType] struct {
spans [maxSpans + 1]T
lastUpdateTime int64
lifeSeconds int64
spanSeconds int64
}
func NewItem[T SupportedUIntType](lifeSeconds int) Item[T] {
if lifeSeconds <= 0 {
lifeSeconds = 60
}
var spanSeconds = lifeSeconds / maxSpans
if spanSeconds < 1 {
spanSeconds = 1
} else if lifeSeconds > maxSpans && lifeSeconds%maxSpans != 0 {
spanSeconds++
}
return Item[T]{
lifeSeconds: int64(lifeSeconds),
spanSeconds: int64(spanSeconds),
lastUpdateTime: fasttime.Now().Unix(),
}
}
func (this *Item[T]) Increase() (result T) {
var currentTime = fasttime.Now().Unix()
var currentSpanIndex = this.calculateSpanIndex(currentTime)
// return quickly
if this.lastUpdateTime == currentTime {
if this.spans[currentSpanIndex] < spanMaxValue {
this.spans[currentSpanIndex]++
}
for _, count := range this.spans {
result += count
}
return
}
if this.lastUpdateTime > 0 {
if currentTime-this.lastUpdateTime > this.lifeSeconds {
for index := range this.spans {
this.spans[index] = 0
}
} else {
var lastSpanIndex = this.calculateSpanIndex(this.lastUpdateTime)
if lastSpanIndex != currentSpanIndex {
var countSpans = len(this.spans)
// reset values between LAST and CURRENT
for index := lastSpanIndex + 1; ; index++ {
var realIndex = index % countSpans
this.spans[realIndex] = 0
if realIndex == currentSpanIndex {
break
}
}
}
}
}
if this.spans[currentSpanIndex] < spanMaxValue {
this.spans[currentSpanIndex]++
}
this.lastUpdateTime = currentTime
for _, count := range this.spans {
result += count
}
return
}
func (this *Item[T]) Sum() (result T) {
if this.lastUpdateTime == 0 {
return 0
}
var currentTime = fasttime.Now().Unix()
var currentSpanIndex = this.calculateSpanIndex(currentTime)
if currentTime-this.lastUpdateTime > this.lifeSeconds {
return 0
} else {
var lastSpanIndex = this.calculateSpanIndex(this.lastUpdateTime)
var countSpans = len(this.spans)
for index := currentSpanIndex + 1; ; index++ {
var realIndex = index % countSpans
result += this.spans[realIndex]
if realIndex == lastSpanIndex {
break
}
}
}
return result
}
func (this *Item[T]) Reset() {
for index := range this.spans {
this.spans[index] = 0
}
}
func (this *Item[T]) IsExpired(currentTime int64) bool {
return this.lastUpdateTime < currentTime-this.lifeSeconds-this.spanSeconds
}
func (this *Item[T]) calculateSpanIndex(timestamp int64) int {
var index = int(timestamp % this.lifeSeconds / this.spanSeconds)
if index > maxSpans-1 {
return maxSpans - 1
}
return index
}
func (this *Item[T]) IsOk() bool {
return this.lifeSeconds > 0
}