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  }