github.com/Finschia/finschia-sdk@v0.48.1/store/cachekv/mergeiterator.go (about)

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