github.com/zuoyebang/bitalostable@v1.0.1-0.20240229032404-e3b99a834294/internal/keyspan/bounded.go (about)

     1  // Copyright 2022 The LevelDB-Go and Pebble Authors. All rights reserved. Use
     2  // of this source code is governed by a BSD-style license that can be found in
     3  // the LICENSE file.
     4  
     5  package keyspan
     6  
     7  import "github.com/zuoyebang/bitalostable/internal/base"
     8  
     9  // TODO(jackson): Consider removing this type and adding bounds enforcement
    10  // directly to the MergingIter. This type is probably too lightweight to warrant
    11  // its own type, but for now we implement it separately for expediency.
    12  
    13  // boundedIterPos records the position of the BoundedIter relative to the
    14  // underlying iterator's position. It's used to avoid Next/Prev-ing the iterator
    15  // if there can't possibly be another span within bounds, because the current
    16  // span overlaps the bound.
    17  //
    18  // Imagine bounds [a,c) and an iterator that seeks to a span [b,d). The span
    19  // [b,d) overlaps some portion of the iterator bounds, so the iterator must
    20  // return it. If the iterator is subsequently Nexted, Next can tell that the
    21  // iterator is exhausted without advancing the underlying iterator because the
    22  // current span's end bound of d is ≥ the upper bound of c. In this case, the
    23  // bounded iterator returns nil and records i.pos as posAtUpperLimit to remember
    24  // that the underlying iterator position does not match the current BoundedIter
    25  // position.
    26  type boundedIterPos int8
    27  
    28  const (
    29  	posAtLowerLimit boundedIterPos = -1
    30  	posAtIterSpan   boundedIterPos = 0
    31  	posAtUpperLimit boundedIterPos = +1
    32  )
    33  
    34  // BoundedIter implements FragmentIterator and enforces bounds.
    35  //
    36  // Like the point InternalIterator interface, the bounded iterator's forward
    37  // positioning routines (SeekGE, First, and Next) only check the upper bound.
    38  // The reverse positioning routines (SeekLT, Last, and Prev) only check the
    39  // lower bound. It is up to the caller to ensure that the forward positioning
    40  // routines respect the lower bound and the reverse positioning routines respect
    41  // the upper bound (i.e. calling SeekGE instead of First if there is a lower
    42  // bound, and SeekLT instead of Last if there is an upper bound).
    43  //
    44  // When the hasPrefix parameter indicates that the iterator is in prefix
    45  // iteration mode, BoundedIter elides any spans that do not overlap with the
    46  // prefix's keyspace. In prefix iteration mode, reverse iteration is disallowed,
    47  // except for an initial SeekLT with a seek key greater than or equal to the
    48  // prefix. In prefix iteration mode, the first seek must position the iterator
    49  // at or immediately before the first fragment covering a key greater than or
    50  // equal to the prefix.
    51  type BoundedIter struct {
    52  	iter      FragmentIterator
    53  	iterSpan  *Span
    54  	cmp       base.Compare
    55  	split     base.Split
    56  	lower     []byte
    57  	upper     []byte
    58  	hasPrefix *bool
    59  	prefix    *[]byte
    60  	pos       boundedIterPos
    61  }
    62  
    63  // Init initializes the bounded iterator.
    64  //
    65  // In addition to the iterator bounds, Init takes pointers to a boolean
    66  // indicating whether the iterator is in prefix iteration mode and the prefix
    67  // key if it is. This is used to exclude spans that are outside the iteration
    68  // prefix.
    69  func (i *BoundedIter) Init(
    70  	cmp base.Compare,
    71  	split base.Split,
    72  	iter FragmentIterator,
    73  	lower, upper []byte,
    74  	hasPrefix *bool,
    75  	prefix *[]byte,
    76  ) {
    77  	*i = BoundedIter{
    78  		iter:      iter,
    79  		cmp:       cmp,
    80  		split:     split,
    81  		lower:     lower,
    82  		upper:     upper,
    83  		hasPrefix: hasPrefix,
    84  		prefix:    prefix,
    85  	}
    86  }
    87  
    88  var _ FragmentIterator = (*BoundedIter)(nil)
    89  
    90  // Seek calls.
    91  //
    92  // Seek calls check iterator bounds in the direction of the seek. Additionally,
    93  // if the iterator is in prefix iteration mode, seek calls check both start and
    94  // end bounds against the prefix's bounds. We check both bounds for defense in
    95  // depth. This optimization has been a source of various bugs due to various
    96  // other prefix iteration optimizations that can result in seek keys that don't
    97  // respect the prefix bounds.
    98  
    99  // SeekGE implements FragmentIterator.
   100  func (i *BoundedIter) SeekGE(key []byte) *Span {
   101  	s := i.iter.SeekGE(key)
   102  	s = i.checkPrefixSpanStart(s)
   103  	s = i.checkPrefixSpanEnd(s)
   104  	return i.checkForwardBound(s)
   105  }
   106  
   107  // SeekLT implements FragmentIterator.
   108  func (i *BoundedIter) SeekLT(key []byte) *Span {
   109  	s := i.iter.SeekLT(key)
   110  	s = i.checkPrefixSpanStart(s)
   111  	s = i.checkPrefixSpanEnd(s)
   112  	return i.checkBackwardBound(s)
   113  }
   114  
   115  // First implements FragmentIterator.
   116  func (i *BoundedIter) First() *Span {
   117  	s := i.iter.First()
   118  	s = i.checkPrefixSpanStart(s)
   119  	return i.checkForwardBound(s)
   120  }
   121  
   122  // Last implements FragmentIterator.
   123  func (i *BoundedIter) Last() *Span {
   124  	s := i.iter.Last()
   125  	s = i.checkPrefixSpanEnd(s)
   126  	return i.checkBackwardBound(s)
   127  }
   128  
   129  // Next implements FragmentIterator.
   130  func (i *BoundedIter) Next() *Span {
   131  	switch i.pos {
   132  	case posAtLowerLimit:
   133  		// The BoundedIter had previously returned nil, because it knew from
   134  		// i.iterSpan's bounds that there was no previous span. To Next, we only
   135  		// need to return the current iter span and reset i.pos to reflect that
   136  		// we're no longer positioned at the limit.
   137  		i.pos = posAtIterSpan
   138  		return i.iterSpan
   139  	case posAtIterSpan:
   140  		// If the span at the underlying iterator position extends to or beyond the
   141  		// upper bound, we can avoid advancing because the next span is necessarily
   142  		// out of bounds.
   143  		if i.iterSpan != nil && i.upper != nil && i.cmp(i.iterSpan.End, i.upper) >= 0 {
   144  			i.pos = posAtUpperLimit
   145  			return nil
   146  		}
   147  		// Similarly, if the span extends to the next prefix and we're in prefix
   148  		// iteration mode, we can avoid advancing.
   149  		if i.iterSpan != nil && *i.hasPrefix {
   150  			ei := i.split(i.iterSpan.End)
   151  			if i.cmp(i.iterSpan.End[:ei], *i.prefix) > 0 {
   152  				i.pos = posAtUpperLimit
   153  				return nil
   154  			}
   155  		}
   156  		return i.checkForwardBound(i.checkPrefixSpanStart(i.iter.Next()))
   157  	case posAtUpperLimit:
   158  		// Already exhausted.
   159  		return nil
   160  	default:
   161  		panic("unreachable")
   162  	}
   163  }
   164  
   165  // Prev implements FragmentIterator.
   166  func (i *BoundedIter) Prev() *Span {
   167  	switch i.pos {
   168  	case posAtLowerLimit:
   169  		// Already exhausted.
   170  		return nil
   171  	case posAtIterSpan:
   172  		// If the span at the underlying iterator position extends to or beyond
   173  		// the lower bound, we can avoid advancing because the previous span is
   174  		// necessarily out of bounds.
   175  		if i.iterSpan != nil && i.lower != nil && i.cmp(i.iterSpan.Start, i.lower) <= 0 {
   176  			i.pos = posAtLowerLimit
   177  			return nil
   178  		}
   179  		// Similarly, if the span extends to or beyond the current prefix and
   180  		// we're in prefix iteration mode, we can avoid advancing.
   181  		if i.iterSpan != nil && *i.hasPrefix {
   182  			si := i.split(i.iterSpan.Start)
   183  			if i.cmp(i.iterSpan.Start[:si], *i.prefix) < 0 {
   184  				i.pos = posAtLowerLimit
   185  				return nil
   186  			}
   187  		}
   188  		return i.checkBackwardBound(i.checkPrefixSpanEnd(i.iter.Prev()))
   189  	case posAtUpperLimit:
   190  		// The BoundedIter had previously returned nil, because it knew from
   191  		// i.iterSpan's bounds that there was no next span. To Prev, we only
   192  		// need to return the current iter span and reset i.pos to reflect that
   193  		// we're no longer positioned at the limit.
   194  		i.pos = posAtIterSpan
   195  		return i.iterSpan
   196  	default:
   197  		panic("unreachable")
   198  	}
   199  }
   200  
   201  // Error implements FragmentIterator.
   202  func (i *BoundedIter) Error() error {
   203  	return i.iter.Error()
   204  }
   205  
   206  // Close implements FragmentIterator.
   207  func (i *BoundedIter) Close() error {
   208  	return i.iter.Close()
   209  }
   210  
   211  // SetBounds modifies the FragmentIterator's bounds.
   212  func (i *BoundedIter) SetBounds(lower, upper []byte) {
   213  	i.lower, i.upper = lower, upper
   214  }
   215  
   216  func (i *BoundedIter) checkPrefixSpanStart(span *Span) *Span {
   217  	// Compare to the prefix's bounds, if in prefix iteration mode.
   218  	if span != nil && *i.hasPrefix {
   219  		si := i.split(span.Start)
   220  		if i.cmp(span.Start[:si], *i.prefix) > 0 {
   221  			// This span starts at a prefix that sorts after our current prefix.
   222  			span = nil
   223  		}
   224  	}
   225  	return span
   226  }
   227  
   228  // checkForwardBound enforces the upper bound, returning nil if the provided
   229  // span is wholly outside the upper bound. It also updates i.pos and i.iterSpan
   230  // to reflect the new iterator position.
   231  func (i *BoundedIter) checkForwardBound(span *Span) *Span {
   232  	// Compare to the upper bound.
   233  	if span != nil && i.upper != nil && i.cmp(span.Start, i.upper) >= 0 {
   234  		span = nil
   235  	}
   236  	i.iterSpan = span
   237  	if i.pos != posAtIterSpan {
   238  		i.pos = posAtIterSpan
   239  	}
   240  	return span
   241  }
   242  
   243  func (i *BoundedIter) checkPrefixSpanEnd(span *Span) *Span {
   244  	// Compare to the prefix's bounds, if in prefix iteration mode.
   245  	if span != nil && *i.hasPrefix && i.cmp(span.End, *i.prefix) <= 0 {
   246  		// This span ends before the current prefix.
   247  		span = nil
   248  	}
   249  	return span
   250  }
   251  
   252  // checkBackward enforces the lower bound, returning nil if the provided span is
   253  // wholly outside the lower bound.  It also updates i.pos and i.iterSpan to
   254  // reflect the new iterator position.
   255  func (i *BoundedIter) checkBackwardBound(span *Span) *Span {
   256  	// Compare to the lower bound.
   257  	if span != nil && i.lower != nil && i.cmp(span.End, i.lower) <= 0 {
   258  		span = nil
   259  	}
   260  	i.iterSpan = span
   261  	if i.pos != posAtIterSpan {
   262  		i.pos = posAtIterSpan
   263  	}
   264  	return span
   265  }