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  }