LCOV - code coverage report
Current view: top level - pebble/internal/base - key_bounds.go (source / functions) Hit Total Coverage
Test: 2024-04-29 08:15Z 5d4c2850 - tests only.lcov Lines: 80 81 98.8 %
Date: 2024-04-29 08:16:17 Functions: 0 0 -

          Line data    Source code
       1             : // Copyright 2024 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 base
       6             : 
       7             : import (
       8             :         "fmt"
       9             : 
      10             :         "github.com/cockroachdb/pebble/internal/invariants"
      11             : )
      12             : 
      13             : // BoundaryKind indicates if a boundary is exclusive or inclusive.
      14             : type BoundaryKind uint8
      15             : 
      16             : // The two possible values of BoundaryKind.
      17             : //
      18             : // Note that we prefer Exclusive to be the zero value, so that zero
      19             : // UserKeyBounds are not valid.
      20             : const (
      21             :         Exclusive BoundaryKind = iota
      22             :         Inclusive
      23             : )
      24             : 
      25             : // UserKeyBoundary represents the endpoint of a bound which can be exclusive or
      26             : // inclusive.
      27             : type UserKeyBoundary struct {
      28             :         Key  []byte
      29             :         Kind BoundaryKind
      30             : }
      31             : 
      32             : // UserKeyInclusive creates an inclusive user key boundary.
      33           1 : func UserKeyInclusive(userKey []byte) UserKeyBoundary {
      34           1 :         return UserKeyBoundary{
      35           1 :                 Key:  userKey,
      36           1 :                 Kind: Inclusive,
      37           1 :         }
      38           1 : }
      39             : 
      40             : // UserKeyExclusive creates an exclusive user key boundary.
      41           1 : func UserKeyExclusive(userKey []byte) UserKeyBoundary {
      42           1 :         return UserKeyBoundary{
      43           1 :                 Key:  userKey,
      44           1 :                 Kind: Exclusive,
      45           1 :         }
      46           1 : }
      47             : 
      48             : // UserKeyExclusiveIf creates a user key boundary which can be either inclusive
      49             : // or exclusive.
      50           1 : func UserKeyExclusiveIf(userKey []byte, exclusive bool) UserKeyBoundary {
      51           1 :         kind := Inclusive
      52           1 :         if exclusive {
      53           1 :                 kind = Exclusive
      54           1 :         }
      55           1 :         return UserKeyBoundary{
      56           1 :                 Key:  userKey,
      57           1 :                 Kind: kind,
      58           1 :         }
      59             : }
      60             : 
      61             : // IsUpperBoundFor returns true if the boundary is an upper bound for the key;
      62             : // i.e. the key is less than the boundary key OR they are equal and the boundary
      63             : // is inclusive.
      64           1 : func (eb UserKeyBoundary) IsUpperBoundFor(cmp Compare, userKey []byte) bool {
      65           1 :         c := cmp(userKey, eb.Key)
      66           1 :         return c < 0 || (c == 0 && eb.Kind == Inclusive)
      67           1 : }
      68             : 
      69             : // IsUpperBoundForInternalKey returns true if boundary is an upper bound for the
      70             : // given internal key.
      71           1 : func (eb UserKeyBoundary) IsUpperBoundForInternalKey(cmp Compare, key InternalKey) bool {
      72           1 :         c := cmp(key.UserKey, eb.Key)
      73           1 :         return c < 0 || (c == 0 && (eb.Kind == Inclusive || key.IsExclusiveSentinel()))
      74           1 : }
      75             : 
      76             : // UserKeyBounds is a user key interval with an inclusive start boundary and
      77             : // with an end boundary that can be either inclusive or exclusive.
      78             : type UserKeyBounds struct {
      79             :         Start []byte
      80             :         End   UserKeyBoundary
      81             : }
      82             : 
      83             : // UserKeyBoundsInclusive creates the bounds [start, end].
      84           1 : func UserKeyBoundsInclusive(start []byte, end []byte) UserKeyBounds {
      85           1 :         return UserKeyBounds{
      86           1 :                 Start: start,
      87           1 :                 End:   UserKeyInclusive(end),
      88           1 :         }
      89           1 : }
      90             : 
      91             : // UserKeyBoundsEndExclusive creates the bounds [start, end).
      92           1 : func UserKeyBoundsEndExclusive(start []byte, end []byte) UserKeyBounds {
      93           1 :         return UserKeyBounds{
      94           1 :                 Start: start,
      95           1 :                 End:   UserKeyExclusive(end),
      96           1 :         }
      97           1 : }
      98             : 
      99             : // UserKeyBoundsEndExclusiveIf creates either [start, end] or [start, end) bounds.
     100           1 : func UserKeyBoundsEndExclusiveIf(start []byte, end []byte, exclusive bool) UserKeyBounds {
     101           1 :         return UserKeyBounds{
     102           1 :                 Start: start,
     103           1 :                 End:   UserKeyExclusiveIf(end, exclusive),
     104           1 :         }
     105           1 : }
     106             : 
     107             : // UserKeyBoundsFromInternal creates the bounds
     108             : // [smallest.UserKey, largest.UserKey] or [smallest.UserKey, largest.UserKey) if
     109             : // largest is an exclusive sentinel.
     110             : //
     111             : // smallest must not be an exclusive sentinel.
     112           1 : func UserKeyBoundsFromInternal(smallest, largest InternalKey) UserKeyBounds {
     113           1 :         if invariants.Enabled && smallest.IsExclusiveSentinel() {
     114           0 :                 panic("smallest key is exclusive sentinel")
     115             :         }
     116           1 :         return UserKeyBoundsEndExclusiveIf(smallest.UserKey, largest.UserKey, largest.IsExclusiveSentinel())
     117             : }
     118             : 
     119             : // Valid returns true if the bounds contain at least a user key.
     120           1 : func (b *UserKeyBounds) Valid(cmp Compare) bool {
     121           1 :         return b.End.IsUpperBoundFor(cmp, b.Start)
     122           1 : }
     123             : 
     124             : // Overlaps returns true if the bounds overlap.
     125           1 : func (b *UserKeyBounds) Overlaps(cmp Compare, other *UserKeyBounds) bool {
     126           1 :         // There is no overlap iff one interval starts after the other ends.
     127           1 :         return other.End.IsUpperBoundFor(cmp, b.Start) && b.End.IsUpperBoundFor(cmp, other.Start)
     128           1 : }
     129             : 
     130             : // ContainsBounds returns true if b completely overlaps other.
     131           1 : func (b *UserKeyBounds) ContainsBounds(cmp Compare, other *UserKeyBounds) bool {
     132           1 :         if cmp(b.Start, other.Start) > 0 {
     133           1 :                 return false
     134           1 :         }
     135           1 :         c := cmp(other.End.Key, b.End.Key)
     136           1 :         return c < 0 || (c == 0 && (b.End.Kind == Inclusive || other.End.Kind == Exclusive))
     137             : }
     138             : 
     139             : // ContainsUserKey returns true if the user key is within the bounds.
     140           1 : func (b *UserKeyBounds) ContainsUserKey(cmp Compare, userKey []byte) bool {
     141           1 :         return cmp(b.Start, userKey) <= 0 && b.End.IsUpperBoundFor(cmp, userKey)
     142           1 : }
     143             : 
     144             : // ContainsInternalKey returns true if the internal key is within the bounds.
     145           1 : func (b *UserKeyBounds) ContainsInternalKey(cmp Compare, key InternalKey) bool {
     146           1 :         c := cmp(b.Start, key.UserKey)
     147           1 :         return (c < 0 || (c == 0 && !key.IsExclusiveSentinel())) &&
     148           1 :                 b.End.IsUpperBoundForInternalKey(cmp, key)
     149           1 : }
     150             : 
     151           1 : func (b UserKeyBounds) String() string {
     152           1 :         return b.Format(DefaultFormatter)
     153           1 : }
     154             : 
     155             : // Format converts the bounds to a string of the form "[foo, bar]" or
     156             : // "[foo, bar)", using the given key formatter.
     157           1 : func (b UserKeyBounds) Format(fmtKey FormatKey) string {
     158           1 :         endC := ']'
     159           1 :         if b.End.Kind == Exclusive {
     160           1 :                 endC = ')'
     161           1 :         }
     162           1 :         return fmt.Sprintf("[%s, %s%c", fmtKey(b.Start), fmtKey(b.End.Key), endC)
     163             : }

Generated by: LCOV version 1.14