github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/internal/rangedel/seek.go (about)

     1  // Copyright 2018 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 rangedel
     6  
     7  import "github.com/petermattis/pebble/internal/base"
     8  
     9  // invalidate the specified iterator by moving it past the last entry.
    10  func invalidate(iter iterator) {
    11  	iter.Last()
    12  	iter.Next()
    13  }
    14  
    15  // SeekGE seeks to the newest tombstone that contains or is past the target
    16  // key. The snapshot parameter controls the visibility of tombstones (only
    17  // tombstones older than the snapshot sequence number are visible). The
    18  // iterator must contain fragmented tombstones: any overlapping tombstones must
    19  // have the same start and end key.
    20  func SeekGE(cmp base.Compare, iter iterator, key []byte, snapshot uint64) Tombstone {
    21  	// NB: We use SeekLT in order to land on the proper tombstone for a search
    22  	// key that resides in the middle of a tombstone. Consider the scenario:
    23  	//
    24  	//     a---e
    25  	//         e---i
    26  	//
    27  	// The tombstones are indexed by their start keys `a` and `e`. If the
    28  	// search key is `c` we want to land on the tombstone [a,e). If we were to
    29  	// use SeekGE then the search key `c` would land on the tombstone [e,i) and
    30  	// we'd have to backtrack. The one complexity here is what happens for the
    31  	// search key `e`. In that case SeekLT will land us on the tombstone [a,e)
    32  	// and we'll have to move forward.
    33  	iterKey, iterValue := iter.SeekLT(key)
    34  
    35  	// Invariant: key < iter.Key().UserKey
    36  
    37  	if iterKey != nil && cmp(key, iterValue) < 0 {
    38  		// The current tombstones contains or is past the search key, but SeekLT
    39  		// returns the oldest entry for a key, so backup until we hit the previous
    40  		// tombstone or an entry which is not visible.
    41  		for savedKey := iterKey.UserKey; ; {
    42  			iterKey, iterValue = iter.Prev()
    43  			if iterKey == nil || cmp(savedKey, iterValue) >= 0 || !iterKey.Visible(snapshot) {
    44  				iterKey, iterValue = iter.Next()
    45  				break
    46  			}
    47  		}
    48  	} else {
    49  		// The current tombstone lies before the search key. Advance the iterator
    50  		// as long as the search key lies past the end of the tombstone. See the
    51  		// comment at the start of this function about why this is necessary.
    52  		for {
    53  			iterKey, iterValue = iter.Next()
    54  			if iterKey == nil {
    55  				// We've run out of tombstones.
    56  				return Tombstone{}
    57  			}
    58  			if cmp(key, iterValue) < 0 {
    59  				break
    60  			}
    61  		}
    62  	}
    63  
    64  	// Walk through the tombstones to find one the newest one that is visible
    65  	// (i.e. has a sequence number less than the snapshot sequence number).
    66  	for {
    67  		if start := iterKey; start.Visible(snapshot) {
    68  			// The tombstone is visible at our read sequence number.
    69  			return Tombstone{
    70  				Start: *start,
    71  				End:   iterValue,
    72  			}
    73  		}
    74  		iterKey, iterValue = iter.Next()
    75  		if iterKey == nil {
    76  			// We've run out of tombstones.
    77  			return Tombstone{}
    78  		}
    79  	}
    80  }
    81  
    82  // SeekLE seeks to the newest tombstone that contains or is before the target
    83  // key. The snapshot parameter controls the visibility of tombstones (only
    84  // tombstones older than the snapshot sequence number are visible). The
    85  // iterator must contain fragmented tombstones: any overlapping tombstones must
    86  // have the same start and end key.
    87  func SeekLE(cmp base.Compare, iter iterator, key []byte, snapshot uint64) Tombstone {
    88  	// NB: We use SeekLT in order to land on the proper tombstone for a search
    89  	// key that resides in the middle of a tombstone. Consider the scenario:
    90  	//
    91  	//     a---e
    92  	//         e---i
    93  	//
    94  	// The tombstones are indexed by their start keys `a` and `e`. If the
    95  	// search key is `c` we want to land on the tombstone [a,e). If we were to
    96  	// use SeekGE then the search key `c` would land on the tombstone [e,i) and
    97  	// we'd have to backtrack. The one complexity here is what happens for the
    98  	// search key `e`. In that case SeekLT will land us on the tombstone [a,e)
    99  	// and we'll have to move forward.
   100  	iterKey, iterValue := iter.SeekLT(key)
   101  	if iterKey == nil {
   102  		iterKey, iterValue = iter.Next()
   103  		if iterKey == nil {
   104  			// The iterator is empty.
   105  			return Tombstone{}
   106  		}
   107  		if cmp(key, iterKey.UserKey) < 0 {
   108  			// The search key lies before the first tombstone.
   109  			//
   110  			// TODO(peter): why is this call to iter.Prev() here?
   111  			iterKey, iterValue = iter.Prev()
   112  			return Tombstone{}
   113  		}
   114  		// Advance the iterator until we find a visible version or we hit the next
   115  		// tombstone.
   116  		for {
   117  			if start := iterKey; start.Visible(snapshot) {
   118  				return Tombstone{
   119  					Start: *start,
   120  					End:   iterValue,
   121  				}
   122  			}
   123  			iterKey, iterValue = iter.Next()
   124  			if iterKey == nil {
   125  				// We've run out of tombstones.
   126  				return Tombstone{}
   127  			}
   128  			if cmp(key, iterKey.UserKey) < 0 {
   129  				// We've hit the next tombstone.
   130  				invalidate(iter)
   131  				return Tombstone{}
   132  			}
   133  		}
   134  	}
   135  
   136  	// Invariant: key >= iter.Key().UserKey
   137  
   138  	if cmp(key, iterValue) >= 0 {
   139  		// The current tombstone lies before the search key. Check to see if the
   140  		// next tombstone contains the search key. If it doesn't, we'll backup and
   141  		// use the current tombstone.
   142  		iterKey, iterValue = iter.Next()
   143  		if iterKey == nil || cmp(key, iterKey.UserKey) < 0 {
   144  			iterKey, iterValue = iter.Prev()
   145  		} else {
   146  			// Advance the iterator until we find a visible version or we hit the
   147  			// next tombstone.
   148  			for {
   149  				if start := iterKey; start.Visible(snapshot) {
   150  					return Tombstone{
   151  						Start: *start,
   152  						End:   iterValue,
   153  					}
   154  				}
   155  				iterKey, iterValue = iter.Next()
   156  				if iterKey == nil || cmp(key, iterKey.UserKey) < 0 {
   157  					iterKey, iterValue = iter.Prev()
   158  					break
   159  				}
   160  			}
   161  		}
   162  	}
   163  
   164  	// We're now positioned at a tombstone that contains or is before the search
   165  	// key and we're positioned at either the oldest of the versions or a visible
   166  	// version. Walk backwards through the tombstones to find the newest one that
   167  	// is visible (i.e. has a sequence number less than the snapshot sequence
   168  	// number).
   169  	for savedKey := iterKey.UserKey; ; {
   170  		valid := iterKey.Visible(snapshot)
   171  		iterKey, iterValue = iter.Prev()
   172  		if iterKey == nil {
   173  			break
   174  		}
   175  		if valid {
   176  			if !iterKey.Visible(snapshot) {
   177  				break
   178  			}
   179  			if cmp(savedKey, iterKey.UserKey) != 0 {
   180  				break
   181  			}
   182  		}
   183  	}
   184  
   185  	iterKey, iterValue = iter.Next()
   186  	start := iterKey
   187  	if cmp(key, start.UserKey) < 0 {
   188  		// The current tombstone is after our search key.
   189  		invalidate(iter)
   190  		return Tombstone{}
   191  	}
   192  	if !start.Visible(snapshot) {
   193  		// The current tombstone is not visible at our read sequence number.
   194  		invalidate(iter)
   195  		return Tombstone{}
   196  	}
   197  	// The tombstone is visible at our read sequence number.
   198  	return Tombstone{
   199  		Start: *start,
   200  		End:   iterValue,
   201  	}
   202  }