github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/ledger/complete/wal/triequeue.go (about) 1 package wal 2 3 import ( 4 "github.com/onflow/flow-go/ledger/complete/mtrie/trie" 5 ) 6 7 // IMPORTANT: TrieQueue is in the wal package to prevent it 8 // from being used for other purposes and getting modified 9 // (to prevent introducing side-effects to checkpointing). 10 11 // TrieQueue is a fix-sized FIFO queue of MTrie. 12 // It is only used by Compactor for checkpointing, and 13 // it is intentionally not threadsafe given its limited use case. 14 // It is not a general purpose queue to avoid incurring overhead 15 // for features not needed for its limited use case. 16 type TrieQueue struct { 17 ts []*trie.MTrie 18 capacity int 19 tail int // element index to write to 20 count int // number of elements (count <= capacity) 21 } 22 23 // NewTrieQueue returns a new TrieQueue with given capacity. 24 func NewTrieQueue(capacity uint) *TrieQueue { 25 return &TrieQueue{ 26 ts: make([]*trie.MTrie, capacity), 27 capacity: int(capacity), 28 } 29 } 30 31 // NewTrieQueueWithValues returns a new TrieQueue with given capacity and initial values. 32 func NewTrieQueueWithValues(capacity uint, tries []*trie.MTrie) *TrieQueue { 33 q := NewTrieQueue(capacity) 34 35 start := 0 36 if len(tries) > q.capacity { 37 start = len(tries) - q.capacity 38 } 39 n := copy(q.ts, tries[start:]) 40 q.count = n 41 q.tail = q.count % q.capacity 42 43 return q 44 } 45 46 // Push pushes trie to queue. If queue is full, it overwrites the oldest element. 47 func (q *TrieQueue) Push(t *trie.MTrie) { 48 q.ts[q.tail] = t 49 q.tail = (q.tail + 1) % q.capacity 50 if !q.isFull() { 51 q.count++ 52 } 53 } 54 55 // Tries returns elements in queue, starting from the oldest element 56 // to the newest element. 57 func (q *TrieQueue) Tries() []*trie.MTrie { 58 if q.count == 0 { 59 return nil 60 } 61 62 tries := make([]*trie.MTrie, q.count) 63 64 if q.tail >= q.count { // Data isn't wrapped around the slice. 65 head := q.tail - q.count 66 copy(tries, q.ts[head:q.tail]) 67 } else { // q.tail < q.count, data is wrapped around the slice. 68 head := q.capacity - q.count + q.tail 69 n := copy(tries, q.ts[head:]) 70 copy(tries[n:], q.ts[:q.tail]) 71 } 72 73 return tries 74 } 75 76 // Count returns element count. 77 func (q *TrieQueue) Count() int { 78 return q.count 79 } 80 81 func (q *TrieQueue) isFull() bool { 82 return q.count == q.capacity 83 }