github.com/lazyledger/lazyledger-core@v0.35.0-dev.0.20210613111200-4c651f053571/libs/db/memdb/iterator.go (about)

     1  package memdb
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  
     7  	"github.com/google/btree"
     8  
     9  	lldb "github.com/lazyledger/lazyledger-core/libs/db"
    10  )
    11  
    12  const (
    13  	// Size of the channel buffer between traversal goroutine and iterator. Using an unbuffered
    14  	// channel causes two context switches per item sent, while buffering allows more work per
    15  	// context switch. Tuned with benchmarks.
    16  	chBufferSize = 64
    17  )
    18  
    19  // memDBIterator is a memDB iterator.
    20  type memDBIterator struct {
    21  	ch     <-chan *item
    22  	cancel context.CancelFunc
    23  	item   *item
    24  	start  []byte
    25  	end    []byte
    26  }
    27  
    28  var _ lldb.Iterator = (*memDBIterator)(nil)
    29  
    30  // newMemDBIterator creates a new memDBIterator.
    31  func newMemDBIterator(db *MemDB, start []byte, end []byte, reverse bool) *memDBIterator {
    32  	ctx, cancel := context.WithCancel(context.Background())
    33  	ch := make(chan *item, chBufferSize)
    34  	iter := &memDBIterator{
    35  		ch:     ch,
    36  		cancel: cancel,
    37  		start:  start,
    38  		end:    end,
    39  	}
    40  
    41  	db.mtx.RLock()
    42  	go func() {
    43  		defer db.mtx.RUnlock()
    44  		// Because we use [start, end) for reverse ranges, while btree uses (start, end], we need
    45  		// the following variables to handle some reverse iteration conditions ourselves.
    46  		var (
    47  			skipEqual     []byte
    48  			abortLessThan []byte
    49  		)
    50  		visitor := func(i btree.Item) bool {
    51  			item := i.(*item)
    52  			if skipEqual != nil && bytes.Equal(item.key, skipEqual) {
    53  				skipEqual = nil
    54  				return true
    55  			}
    56  			if abortLessThan != nil && bytes.Compare(item.key, abortLessThan) == -1 {
    57  				return false
    58  			}
    59  			select {
    60  			case <-ctx.Done():
    61  				return false
    62  			case ch <- item:
    63  				return true
    64  			}
    65  		}
    66  		switch {
    67  		case start == nil && end == nil && !reverse:
    68  			db.btree.Ascend(visitor)
    69  		case start == nil && end == nil && reverse:
    70  			db.btree.Descend(visitor)
    71  		case end == nil && !reverse:
    72  			// must handle this specially, since nil is considered less than anything else
    73  			db.btree.AscendGreaterOrEqual(newKey(start), visitor)
    74  		case !reverse:
    75  			db.btree.AscendRange(newKey(start), newKey(end), visitor)
    76  		case end == nil:
    77  			// abort after start, since we use [start, end) while btree uses (start, end]
    78  			abortLessThan = start
    79  			db.btree.Descend(visitor)
    80  		default:
    81  			// skip end and abort after start, since we use [start, end) while btree uses (start, end]
    82  			skipEqual = end
    83  			abortLessThan = start
    84  			db.btree.DescendLessOrEqual(newKey(end), visitor)
    85  		}
    86  		close(ch)
    87  	}()
    88  
    89  	// prime the iterator with the first value, if any
    90  	if item, ok := <-ch; ok {
    91  		iter.item = item
    92  	}
    93  
    94  	return iter
    95  }
    96  
    97  // Close implements Iterator.
    98  func (i *memDBIterator) Close() error {
    99  	i.cancel()
   100  	for range i.ch { // drain channel
   101  	}
   102  	i.item = nil
   103  	return nil
   104  }
   105  
   106  // Domain implements Iterator.
   107  func (i *memDBIterator) Domain() ([]byte, []byte) {
   108  	return i.start, i.end
   109  }
   110  
   111  // Valid implements Iterator.
   112  func (i *memDBIterator) Valid() bool {
   113  	return i.item != nil
   114  }
   115  
   116  // Next implements Iterator.
   117  func (i *memDBIterator) Next() {
   118  	i.assertIsValid()
   119  	item, ok := <-i.ch
   120  	switch {
   121  	case ok:
   122  		i.item = item
   123  	default:
   124  		i.item = nil
   125  	}
   126  }
   127  
   128  // Error implements Iterator.
   129  func (i *memDBIterator) Error() error {
   130  	return nil // famous last words
   131  }
   132  
   133  // Key implements Iterator.
   134  func (i *memDBIterator) Key() []byte {
   135  	i.assertIsValid()
   136  	return i.item.key
   137  }
   138  
   139  // Value implements Iterator.
   140  func (i *memDBIterator) Value() []byte {
   141  	i.assertIsValid()
   142  	return i.item.value
   143  }
   144  
   145  func (i *memDBIterator) assertIsValid() {
   146  	if !i.Valid() {
   147  		panic("iterator is invalid")
   148  	}
   149  }