github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/forensics/storage/multi_iterator.go (about) 1 package storage 2 3 import ( 4 "bytes" 5 "container/heap" 6 7 "github.com/hyperledger/burrow/storage" 8 ) 9 10 type MultiIterator struct { 11 start []byte 12 end []byte 13 // Acts as priority queue based on sort order of current key in each iterator 14 iterators []storage.KVIterator 15 iteratorOrder map[storage.KVIterator]int 16 lessComp int 17 } 18 19 // MultiIterator iterates in order over a series o 20 func NewMultiIterator(reverse bool, iterators ...storage.KVIterator) *MultiIterator { 21 // reuse backing array 22 lessComp := -1 23 if reverse { 24 lessComp = 1 25 } 26 mi := &MultiIterator{ 27 iterators: iterators, 28 iteratorOrder: make(map[storage.KVIterator]int), 29 lessComp: lessComp, 30 } 31 mi.init() 32 return mi 33 } 34 35 func (mi *MultiIterator) init() { 36 validIterators := mi.iterators[:0] 37 for i, it := range mi.iterators { 38 mi.iteratorOrder[it] = i 39 if it.Valid() { 40 validIterators = append(validIterators, it) 41 start, end := it.Domain() 42 if i == 0 || storage.CompareKeys(start, mi.start) == mi.lessComp { 43 mi.start = start 44 } 45 if i == 0 || storage.CompareKeys(mi.end, end) == mi.lessComp { 46 mi.end = end 47 } 48 } else { 49 // Not clear if this is necessary - fairly sure it is permitted so can't hurt 50 it.Close() 51 } 52 } 53 mi.iterators = validIterators 54 heap.Init(mi) 55 } 56 57 // sort.Interface implementation 58 func (mi *MultiIterator) Len() int { 59 return len(mi.iterators) 60 } 61 62 func (mi *MultiIterator) Less(i, j int) bool { 63 comp := bytes.Compare(mi.iterators[i].Key(), mi.iterators[j].Key()) 64 // Use order iterators passed to NewMultiIterator if keys are equal1 65 return comp == mi.lessComp || (comp == 0 && mi.iteratorOrder[mi.iterators[i]] < mi.iteratorOrder[mi.iterators[j]]) 66 } 67 68 func (mi *MultiIterator) Swap(i, j int) { 69 mi.iterators[i], mi.iterators[j] = mi.iterators[j], mi.iterators[i] 70 } 71 72 func (mi *MultiIterator) Push(x interface{}) { 73 mi.iterators = append(mi.iterators, x.(storage.KVIterator)) 74 } 75 76 func (mi *MultiIterator) Pop() interface{} { 77 n := len(mi.iterators) - 1 78 it := mi.iterators[n] 79 mi.iterators = mi.iterators[:n] 80 return it 81 } 82 83 func (mi *MultiIterator) Domain() ([]byte, []byte) { 84 return mi.start, mi.end 85 } 86 87 func (mi *MultiIterator) Valid() bool { 88 return len(mi.iterators) > 0 89 } 90 91 func (mi *MultiIterator) Next() { 92 // Always advance the lowest iterator - the same one we serve the KV pair from 93 it := heap.Pop(mi).(storage.KVIterator) 94 it.Next() 95 if it.Valid() { 96 heap.Push(mi, it) 97 } 98 } 99 100 func (mi *MultiIterator) Key() []byte { 101 return mi.Peek().Key() 102 } 103 104 func (mi *MultiIterator) Value() []byte { 105 return mi.Peek().Value() 106 } 107 108 func (mi *MultiIterator) Peek() storage.KVIterator { 109 return mi.iterators[0] 110 } 111 112 func (mi *MultiIterator) Close() error { 113 // Close any remaining valid iterators 114 for _, it := range mi.iterators { 115 err := it.Close() 116 if err != nil { 117 return err 118 } 119 } 120 return nil 121 } 122 123 func (mi *MultiIterator) Error() error { 124 for _, it := range mi.iterators { 125 if err := it.Error(); err != nil { 126 return err 127 } 128 } 129 return nil 130 }