github.com/songzhibin97/gkit@v1.2.13/internal/stat/rolling_policy.go (about)

     1  package stat
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  )
     7  
     8  // RollingPolicy 基于持续时间的环形窗口的策略,随时间段移动存储桶偏移量。
     9  type RollingPolicy struct {
    10  	mu     sync.RWMutex
    11  	size   int
    12  	window *Window
    13  	offset int
    14  
    15  	bucketDuration time.Duration
    16  	lastAppendTime time.Time
    17  }
    18  
    19  // timespan 时间跨度
    20  func (r *RollingPolicy) timespan() int {
    21  	v := int(time.Since(r.lastAppendTime) / r.bucketDuration)
    22  	if v > -1 {
    23  		// 时钟回滚?
    24  		return v
    25  	}
    26  	return r.size
    27  }
    28  
    29  // add
    30  func (r *RollingPolicy) add(f func(offset int, val float64), val float64) {
    31  	r.mu.Lock()
    32  	timespan := r.timespan()
    33  	if timespan > 0 {
    34  		r.lastAppendTime = r.lastAppendTime.Add(time.Duration(timespan * int(r.bucketDuration)))
    35  		offset := r.offset
    36  		// 重置过期的 bucket
    37  		s := offset + 1
    38  		if timespan > r.size {
    39  			timespan = r.size
    40  		}
    41  		// e: reset offset must start from offset+1
    42  		e, e1 := s+timespan, 0
    43  		if e > r.size {
    44  			e1 = e - r.size
    45  			e = r.size
    46  		}
    47  		for i := s; i < e; i++ {
    48  			r.window.ResetBucket(i)
    49  			offset = i
    50  		}
    51  		for i := 0; i < e1; i++ {
    52  			r.window.ResetBucket(i)
    53  			offset = i
    54  		}
    55  		r.offset = offset
    56  	}
    57  	f(r.offset, val)
    58  	r.mu.Unlock()
    59  }
    60  
    61  // Append 将给定的点附加到窗口
    62  func (r *RollingPolicy) Append(val float64) {
    63  	r.add(r.window.Append, val)
    64  }
    65  
    66  // Add 将给定值添加到存储桶中的最新点
    67  func (r *RollingPolicy) Add(val float64) {
    68  	r.add(r.window.Add, val)
    69  }
    70  
    71  // Reduce 缩减应用窗口
    72  func (r *RollingPolicy) Reduce(f func(Iterator) float64) (val float64) {
    73  	r.mu.RLock()
    74  	timespan := r.timespan()
    75  	if count := r.size - timespan; count > 0 {
    76  		offset := r.offset + timespan + 1
    77  		if offset >= r.size {
    78  			offset = offset - r.size
    79  		}
    80  		val = f(r.window.Iterator(offset, count))
    81  	}
    82  	r.mu.RUnlock()
    83  	return val
    84  }
    85  
    86  // NewRollingPolicy 实例化 RollingPolicy 对象
    87  func NewRollingPolicy(window *Window, bucketDuration time.Duration) *RollingPolicy {
    88  	return &RollingPolicy{
    89  		window: window,
    90  		size:   window.Size(),
    91  		offset: 0,
    92  
    93  		bucketDuration: bucketDuration,
    94  		lastAppendTime: time.Now(),
    95  	}
    96  }