github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/store/cache/mergeiterator.go (about)

     1  package cache
     2  
     3  import (
     4  	"bytes"
     5  
     6  	"github.com/gnolang/gno/tm2/pkg/store/types"
     7  )
     8  
     9  // cacheMergeIterator merges a parent Iterator and a cache Iterator.
    10  // The cache iterator may return nil keys to signal that an item
    11  // had been deleted (but not deleted in the parent).
    12  // If the cache iterator has the same key as the parent, the
    13  // cache shadows (overrides) the parent.
    14  //
    15  // TODO: Optimize by memoizing.
    16  type cacheMergeIterator struct {
    17  	parent    types.Iterator
    18  	cache     types.Iterator
    19  	ascending bool
    20  }
    21  
    22  var _ types.Iterator = (*cacheMergeIterator)(nil)
    23  
    24  func newCacheMergeIterator(parent, cache types.Iterator, ascending bool) *cacheMergeIterator {
    25  	iter := &cacheMergeIterator{
    26  		parent:    parent,
    27  		cache:     cache,
    28  		ascending: ascending,
    29  	}
    30  	return iter
    31  }
    32  
    33  // Domain implements Iterator.
    34  // If the domains are different, returns the union.
    35  func (iter *cacheMergeIterator) Domain() (start, end []byte) {
    36  	startP, endP := iter.parent.Domain()
    37  	startC, endC := iter.cache.Domain()
    38  	if iter.compare(startP, startC) < 0 {
    39  		start = startP
    40  	} else {
    41  		start = startC
    42  	}
    43  	if iter.compare(endP, endC) < 0 {
    44  		end = endC
    45  	} else {
    46  		end = endP
    47  	}
    48  	return start, end
    49  }
    50  
    51  // Valid implements Iterator.
    52  func (iter *cacheMergeIterator) Valid() bool {
    53  	return iter.skipUntilExistsOrInvalid()
    54  }
    55  
    56  // Next implements Iterator
    57  func (iter *cacheMergeIterator) Next() {
    58  	iter.skipUntilExistsOrInvalid()
    59  	iter.assertValid()
    60  
    61  	// If parent is invalid, get the next cache item.
    62  	if !iter.parent.Valid() {
    63  		iter.cache.Next()
    64  		return
    65  	}
    66  
    67  	// If cache is invalid, get the next parent item.
    68  	if !iter.cache.Valid() {
    69  		iter.parent.Next()
    70  		return
    71  	}
    72  
    73  	// Both are valid.  Compare keys.
    74  	keyP, keyC := iter.parent.Key(), iter.cache.Key()
    75  	switch iter.compare(keyP, keyC) {
    76  	case -1: // parent < cache
    77  		iter.parent.Next()
    78  	case 0: // parent == cache
    79  		iter.parent.Next()
    80  		iter.cache.Next()
    81  	case 1: // parent > cache
    82  		iter.cache.Next()
    83  	}
    84  }
    85  
    86  // Key implements Iterator
    87  func (iter *cacheMergeIterator) Key() []byte {
    88  	iter.skipUntilExistsOrInvalid()
    89  	iter.assertValid()
    90  
    91  	// If parent is invalid, get the cache key.
    92  	if !iter.parent.Valid() {
    93  		return iter.cache.Key()
    94  	}
    95  
    96  	// If cache is invalid, get the parent key.
    97  	if !iter.cache.Valid() {
    98  		return iter.parent.Key()
    99  	}
   100  
   101  	// Both are valid.  Compare keys.
   102  	keyP, keyC := iter.parent.Key(), iter.cache.Key()
   103  	cmp := iter.compare(keyP, keyC)
   104  	switch cmp {
   105  	case -1: // parent < cache
   106  		return keyP
   107  	case 0: // parent == cache
   108  		return keyP
   109  	case 1: // parent > cache
   110  		return keyC
   111  	default:
   112  		panic("invalid compare result")
   113  	}
   114  }
   115  
   116  // Value implements Iterator
   117  func (iter *cacheMergeIterator) Value() []byte {
   118  	iter.skipUntilExistsOrInvalid()
   119  	iter.assertValid()
   120  
   121  	// If parent is invalid, get the cache value.
   122  	if !iter.parent.Valid() {
   123  		return iter.cache.Value()
   124  	}
   125  
   126  	// If cache is invalid, get the parent value.
   127  	if !iter.cache.Valid() {
   128  		return iter.parent.Value()
   129  	}
   130  
   131  	// Both are valid.  Compare keys.
   132  	keyP, keyC := iter.parent.Key(), iter.cache.Key()
   133  	cmp := iter.compare(keyP, keyC)
   134  	switch cmp {
   135  	case -1: // parent < cache
   136  		return iter.parent.Value()
   137  	case 0: // parent == cache
   138  		return iter.cache.Value()
   139  	case 1: // parent > cache
   140  		return iter.cache.Value()
   141  	default:
   142  		panic("invalid comparison result")
   143  	}
   144  }
   145  
   146  // Close implements Iterator
   147  func (iter *cacheMergeIterator) Close() {
   148  	iter.parent.Close()
   149  	iter.cache.Close()
   150  }
   151  
   152  // Like bytes.Compare but opposite if not ascending.
   153  func (iter *cacheMergeIterator) compare(a, b []byte) int {
   154  	if iter.ascending {
   155  		return bytes.Compare(a, b)
   156  	}
   157  	return bytes.Compare(a, b) * -1
   158  }
   159  
   160  // Skip all delete-items from the cache w/ `key < until`.  After this function,
   161  // current cache item is a non-delete-item, or `until <= key`.
   162  // If the current cache item is not a delete item, does nothing.
   163  // If `until` is nil, there is no limit, and cache may end up invalid.
   164  // CONTRACT: cache is valid.
   165  func (iter *cacheMergeIterator) skipCacheDeletes(until []byte) {
   166  	for iter.cache.Valid() &&
   167  		iter.cache.Value() == nil &&
   168  		(until == nil || iter.compare(iter.cache.Key(), until) < 0) {
   169  		iter.cache.Next()
   170  	}
   171  }
   172  
   173  // Fast forwards cache (or parent+cache in case of deleted items) until current
   174  // item exists, or until iterator becomes invalid.
   175  // Returns whether the iterator is valid.
   176  func (iter *cacheMergeIterator) skipUntilExistsOrInvalid() bool {
   177  	for {
   178  		// If parent is invalid, fast-forward cache.
   179  		if !iter.parent.Valid() {
   180  			iter.skipCacheDeletes(nil)
   181  			return iter.cache.Valid()
   182  		}
   183  		// Parent is valid.
   184  
   185  		if !iter.cache.Valid() {
   186  			return true
   187  		}
   188  		// Parent is valid, cache is valid.
   189  
   190  		// Compare parent and cache.
   191  		keyP := iter.parent.Key()
   192  		keyC := iter.cache.Key()
   193  		switch iter.compare(keyP, keyC) {
   194  		case -1: // parent < cache.
   195  			return true
   196  
   197  		case 0: // parent == cache.
   198  
   199  			// Skip over if cache item is a delete.
   200  			valueC := iter.cache.Value()
   201  			if valueC == nil {
   202  				iter.parent.Next()
   203  				iter.cache.Next()
   204  				continue
   205  			}
   206  			// Cache is not a delete.
   207  
   208  			return true // cache exists.
   209  
   210  		case 1: // cache < parent
   211  
   212  			// Skip over if cache item is a delete.
   213  			valueC := iter.cache.Value()
   214  			if valueC == nil {
   215  				iter.skipCacheDeletes(keyP)
   216  				continue
   217  			}
   218  			// Cache is not a delete.
   219  
   220  			return true // cache exists.
   221  		}
   222  	}
   223  }
   224  
   225  // If not valid, panics.
   226  // NOTE: May have side-effect of iterating over cache.
   227  func (iter *cacheMergeIterator) assertValid() {
   228  	if !iter.Valid() {
   229  		panic("iterator is invalid")
   230  	}
   231  }