LCOV - code coverage report
Current view: top level - pebble/internal/base - key_bounds.go (source / functions) Hit Total Coverage
Test: 2024-10-23 08:16Z 6cca117f - meta test only.lcov Lines: 76 92 82.6 %
Date: 2024-10-23 08:17:41 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             : // CompareUpperBounds compares two UserKeyBoundaries as upper bounds (e.g. when
      77             : // they are used for UserKeyBounds.End).
      78           1 : func (eb UserKeyBoundary) CompareUpperBounds(cmp Compare, other UserKeyBoundary) int {
      79           1 :         switch c := cmp(eb.Key, other.Key); {
      80           1 :         case c != 0:
      81           1 :                 return c
      82           1 :         case eb.Kind == other.Kind:
      83           1 :                 return 0
      84           1 :         case eb.Kind == Inclusive:
      85           1 :                 // eb is inclusive, other is exclusive.
      86           1 :                 return 1
      87           1 :         default:
      88           1 :                 // eb is exclusive, other is inclusive.
      89           1 :                 return -1
      90             :         }
      91             : }
      92             : 
      93             : // UserKeyBounds is a user key interval with an inclusive start boundary and
      94             : // with an end boundary that can be either inclusive or exclusive.
      95             : type UserKeyBounds struct {
      96             :         Start []byte
      97             :         End   UserKeyBoundary
      98             : }
      99             : 
     100             : // UserKeyBoundsInclusive creates the bounds [start, end].
     101           1 : func UserKeyBoundsInclusive(start []byte, end []byte) UserKeyBounds {
     102           1 :         return UserKeyBounds{
     103           1 :                 Start: start,
     104           1 :                 End:   UserKeyInclusive(end),
     105           1 :         }
     106           1 : }
     107             : 
     108             : // UserKeyBoundsEndExclusive creates the bounds [start, end).
     109           1 : func UserKeyBoundsEndExclusive(start []byte, end []byte) UserKeyBounds {
     110           1 :         return UserKeyBounds{
     111           1 :                 Start: start,
     112           1 :                 End:   UserKeyExclusive(end),
     113           1 :         }
     114           1 : }
     115             : 
     116             : // UserKeyBoundsEndExclusiveIf creates either [start, end] or [start, end) bounds.
     117           1 : func UserKeyBoundsEndExclusiveIf(start []byte, end []byte, exclusive bool) UserKeyBounds {
     118           1 :         return UserKeyBounds{
     119           1 :                 Start: start,
     120           1 :                 End:   UserKeyExclusiveIf(end, exclusive),
     121           1 :         }
     122           1 : }
     123             : 
     124             : // UserKeyBoundsFromInternal creates the bounds
     125             : // [smallest.UserKey, largest.UserKey] or [smallest.UserKey, largest.UserKey) if
     126             : // largest is an exclusive sentinel.
     127             : //
     128             : // smallest must not be an exclusive sentinel.
     129           1 : func UserKeyBoundsFromInternal(smallest, largest InternalKey) UserKeyBounds {
     130           1 :         if invariants.Enabled && smallest.IsExclusiveSentinel() {
     131           0 :                 panic("smallest key is exclusive sentinel")
     132             :         }
     133           1 :         return UserKeyBoundsEndExclusiveIf(smallest.UserKey, largest.UserKey, largest.IsExclusiveSentinel())
     134             : }
     135             : 
     136             : // Valid returns true if the bounds contain at least a user key.
     137           0 : func (b *UserKeyBounds) Valid(cmp Compare) bool {
     138           0 :         return b.End.IsUpperBoundFor(cmp, b.Start)
     139           0 : }
     140             : 
     141             : // Overlaps returns true if the bounds overlap.
     142           1 : func (b *UserKeyBounds) Overlaps(cmp Compare, other *UserKeyBounds) bool {
     143           1 :         // There is no overlap iff one interval starts after the other ends.
     144           1 :         return other.End.IsUpperBoundFor(cmp, b.Start) && b.End.IsUpperBoundFor(cmp, other.Start)
     145           1 : }
     146             : 
     147             : // ContainsBounds returns true if b completely overlaps other.
     148           1 : func (b *UserKeyBounds) ContainsBounds(cmp Compare, other *UserKeyBounds) bool {
     149           1 :         if cmp(b.Start, other.Start) > 0 {
     150           1 :                 return false
     151           1 :         }
     152           1 :         return other.End.CompareUpperBounds(cmp, b.End) <= 0
     153             : }
     154             : 
     155             : // ContainsUserKey returns true if the user key is within the bounds.
     156           0 : func (b *UserKeyBounds) ContainsUserKey(cmp Compare, userKey []byte) bool {
     157           0 :         return cmp(b.Start, userKey) <= 0 && b.End.IsUpperBoundFor(cmp, userKey)
     158           0 : }
     159             : 
     160             : // ContainsInternalKey returns true if the internal key is within the bounds.
     161           1 : func (b *UserKeyBounds) ContainsInternalKey(cmp Compare, key InternalKey) bool {
     162           1 :         c := cmp(b.Start, key.UserKey)
     163           1 :         return (c < 0 || (c == 0 && !key.IsExclusiveSentinel())) &&
     164           1 :                 b.End.IsUpperBoundForInternalKey(cmp, key)
     165           1 : }
     166             : 
     167           0 : func (b UserKeyBounds) String() string {
     168           0 :         return b.Format(DefaultFormatter)
     169           0 : }
     170             : 
     171             : // Format converts the bounds to a string of the form "[foo, bar]" or
     172             : // "[foo, bar)", using the given key formatter.
     173           0 : func (b UserKeyBounds) Format(fmtKey FormatKey) string {
     174           0 :         endC := ']'
     175           0 :         if b.End.Kind == Exclusive {
     176           0 :                 endC = ')'
     177           0 :         }
     178           0 :         return fmt.Sprintf("[%s, %s%c", fmtKey(b.Start), fmtKey(b.End.Key), endC)
     179             : }

Generated by: LCOV version 1.14