github.com/TeaOSLab/EdgeNode@v1.3.8/internal/utils/counters/item.go (about) 1 // Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn . 2 3 package counters 4 5 import ( 6 "github.com/TeaOSLab/EdgeNode/internal/utils/fasttime" 7 ) 8 9 const spanMaxValue = 10_000_000 10 const maxSpans = 10 11 12 type Item[T SupportedUIntType] struct { 13 spans [maxSpans + 1]T 14 lastUpdateTime int64 15 lifeSeconds int64 16 spanSeconds int64 17 } 18 19 func NewItem[T SupportedUIntType](lifeSeconds int) Item[T] { 20 if lifeSeconds <= 0 { 21 lifeSeconds = 60 22 } 23 var spanSeconds = lifeSeconds / maxSpans 24 if spanSeconds < 1 { 25 spanSeconds = 1 26 } else if lifeSeconds > maxSpans && lifeSeconds%maxSpans != 0 { 27 spanSeconds++ 28 } 29 30 return Item[T]{ 31 lifeSeconds: int64(lifeSeconds), 32 spanSeconds: int64(spanSeconds), 33 lastUpdateTime: fasttime.Now().Unix(), 34 } 35 } 36 37 func (this *Item[T]) Increase() (result T) { 38 var currentTime = fasttime.Now().Unix() 39 var currentSpanIndex = this.calculateSpanIndex(currentTime) 40 41 // return quickly 42 if this.lastUpdateTime == currentTime { 43 if this.spans[currentSpanIndex] < spanMaxValue { 44 this.spans[currentSpanIndex]++ 45 } 46 for _, count := range this.spans { 47 result += count 48 } 49 return 50 } 51 52 if this.lastUpdateTime > 0 { 53 if currentTime-this.lastUpdateTime > this.lifeSeconds { 54 for index := range this.spans { 55 this.spans[index] = 0 56 } 57 } else { 58 var lastSpanIndex = this.calculateSpanIndex(this.lastUpdateTime) 59 60 if lastSpanIndex != currentSpanIndex { 61 var countSpans = len(this.spans) 62 63 // reset values between LAST and CURRENT 64 for index := lastSpanIndex + 1; ; index++ { 65 var realIndex = index % countSpans 66 this.spans[realIndex] = 0 67 if realIndex == currentSpanIndex { 68 break 69 } 70 } 71 } 72 } 73 } 74 75 if this.spans[currentSpanIndex] < spanMaxValue { 76 this.spans[currentSpanIndex]++ 77 } 78 this.lastUpdateTime = currentTime 79 80 for _, count := range this.spans { 81 result += count 82 } 83 84 return 85 } 86 87 func (this *Item[T]) Sum() (result T) { 88 if this.lastUpdateTime == 0 { 89 return 0 90 } 91 92 var currentTime = fasttime.Now().Unix() 93 var currentSpanIndex = this.calculateSpanIndex(currentTime) 94 95 if currentTime-this.lastUpdateTime > this.lifeSeconds { 96 return 0 97 } else { 98 var lastSpanIndex = this.calculateSpanIndex(this.lastUpdateTime) 99 var countSpans = len(this.spans) 100 for index := currentSpanIndex + 1; ; index++ { 101 var realIndex = index % countSpans 102 result += this.spans[realIndex] 103 if realIndex == lastSpanIndex { 104 break 105 } 106 } 107 } 108 109 return result 110 } 111 112 func (this *Item[T]) Reset() { 113 for index := range this.spans { 114 this.spans[index] = 0 115 } 116 } 117 118 func (this *Item[T]) IsExpired(currentTime int64) bool { 119 return this.lastUpdateTime < currentTime-this.lifeSeconds-this.spanSeconds 120 } 121 122 func (this *Item[T]) calculateSpanIndex(timestamp int64) int { 123 var index = int(timestamp % this.lifeSeconds / this.spanSeconds) 124 if index > maxSpans-1 { 125 return maxSpans - 1 126 } 127 return index 128 } 129 130 func (this *Item[T]) IsOk() bool { 131 return this.lifeSeconds > 0 132 }