github.com/sereiner/library@v0.0.0-20200518095232-1fa3e640cc5f/metrics/rpsc.go (about)

     1  package metrics
     2  
     3  import (
     4  	"sync/atomic"
     5  	"time"
     6  )
     7  
     8  //QPSC 基于HashedWheelTimer算法的计数器,过期自动淘汰
     9  type QPSC struct {
    10  	total      int
    11  	length     int
    12  	slots      []int32
    13  	lastTicker int64
    14  	counter    int32
    15  }
    16  
    17  //NewQPSC 构建计数器
    18  func NewQPSC(length int, total int) (w *QPSC) {
    19  	w = &QPSC{length: length, total: total}
    20  	w.slots = make([]int32, w.total, w.total)
    21  	for i := 0; i < w.total; i++ {
    22  		w.slots[i] = 0
    23  	}
    24  	return w
    25  }
    26  
    27  //Mark 添加新值
    28  func (r *QPSC) Mark(new int32) {
    29  	r.mark(new, time.Now().Unix())
    30  }
    31  
    32  //mark 记录上次执行时间,超过时间间隔则清除counter
    33  //每一跳需清除中间秒数
    34  func (r *QPSC) mark(new int32, currentStep int64) {
    35  	lastStep := r.lastTicker
    36  	current := int(currentStep % int64(r.total))
    37  	atomic.AddInt32(&r.counter, -r.clear(lastStep, currentStep)) //6, 8(clear,1,2,7,8)
    38  	atomic.AddInt32(&r.counter, new)
    39  	atomic.AddInt32(&r.slots[current], new)
    40  	r.lastTicker = currentStep
    41  }
    42  
    43  func (r *QPSC) clear(l int64, n int64) (clearCounter int32) { //1-5:1,10:1,10 //2:1,3:1
    44  	clearCounter = int32(0)
    45  	if l == n {
    46  		return
    47  	}
    48  	//清空时间中间差
    49  	if int(n-l) >= r.length {
    50  		for i := 0; i < r.total; i++ {
    51  			clearCounter += atomic.SwapInt32(&r.slots[i], 0)
    52  		}
    53  		return clearCounter
    54  	}
    55  
    56  	right := int(n % int64(r.total))       //0,3
    57  	l1 := (right - r.length + 1) % r.total //5,4
    58  	left := l1 % r.total
    59  	if l1 < 0 {
    60  		left = (l1 + r.total) % r.total
    61  	}
    62  	if right > left {
    63  		for i := 0; i < left; i++ { //0,1,2,3,4,5
    64  			clearCounter += atomic.SwapInt32(&r.slots[i], 0)
    65  		}
    66  		for i := right; i < r.total; i++ { //1,
    67  			clearCounter += atomic.SwapInt32(&r.slots[i], 0)
    68  		}
    69  		return clearCounter
    70  	}
    71  	for i := right; i < left; i++ { //0,1,2,3,4,5 //3,4
    72  		clearCounter += atomic.SwapInt32(&r.slots[i], 0)
    73  	}
    74  	return clearCounter
    75  
    76  }