github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/util/evicting_queue.go (about) 1 package util 2 3 import ( 4 "errors" 5 "sync" 6 ) 7 8 type EvictingQueue struct { 9 sync.RWMutex 10 11 capacity int 12 entries []interface{} 13 onEvict func() 14 } 15 16 func NewEvictingQueue(capacity int, onEvict func()) (*EvictingQueue, error) { 17 if err := validateCapacity(capacity); err != nil { 18 return nil, err 19 } 20 21 queue := &EvictingQueue{ 22 onEvict: onEvict, 23 entries: make([]interface{}, 0, capacity), 24 } 25 26 err := queue.SetCapacity(capacity) 27 if err != nil { 28 return nil, err 29 } 30 31 return queue, nil 32 } 33 34 func (q *EvictingQueue) Append(entry interface{}) { 35 q.Lock() 36 defer q.Unlock() 37 38 if len(q.entries) >= q.capacity { 39 q.evictOldest() 40 } 41 42 q.entries = append(q.entries, entry) 43 } 44 45 func (q *EvictingQueue) evictOldest() { 46 q.onEvict() 47 48 start := (len(q.entries) - q.Capacity()) + 1 49 q.entries = append(q.entries[:0], q.entries[start:]...) 50 } 51 52 func (q *EvictingQueue) Entries() []interface{} { 53 q.RLock() 54 defer q.RUnlock() 55 56 return q.entries 57 } 58 59 func (q *EvictingQueue) Length() int { 60 q.RLock() 61 defer q.RUnlock() 62 63 return len(q.entries) 64 } 65 66 func (q *EvictingQueue) Capacity() int { 67 return q.capacity 68 } 69 70 func (q *EvictingQueue) SetCapacity(capacity int) error { 71 if err := validateCapacity(capacity); err != nil { 72 return err 73 } 74 75 q.capacity = capacity 76 return nil 77 } 78 79 func (q *EvictingQueue) Clear() { 80 q.Lock() 81 defer q.Unlock() 82 83 q.entries = q.entries[:0] 84 } 85 86 func validateCapacity(capacity int) error { 87 if capacity <= 0 { 88 // a queue of 0 (or smaller) capacity is invalid 89 return errors.New("queue cannot have a zero or negative capacity") 90 } 91 92 return nil 93 }