LCOV - code coverage report
Current view: top level - pebble/internal/keyspan - span.go (source / functions) Hit Total Coverage
Test: 2025-01-08 08:16Z 80ce1d7f - tests only.lcov Lines: 259 280 92.5 %
Date: 2025-01-08 08:17:34 Functions: 0 0 -

          Line data    Source code
       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 keyspan // import "github.com/cockroachdb/pebble/internal/keyspan"
       6             : 
       7             : import (
       8             :         "bytes"
       9             :         "cmp"
      10             :         "fmt"
      11             :         "slices"
      12             :         "strings"
      13             :         "unicode"
      14             : 
      15             :         "github.com/cockroachdb/pebble/internal/base"
      16             : )
      17             : 
      18             : // Span represents a set of keys over a span of user key space. All of the keys
      19             : // within a Span are applied across the span's key span indicated by Start and
      20             : // End. Each internal key applied over the user key span appears as a separate
      21             : // Key, with its own kind and sequence number. Optionally, each Key may also
      22             : // have a Suffix and/or Value.
      23             : //
      24             : // Note that the start user key is inclusive and the end user key is exclusive.
      25             : //
      26             : // Currently the only supported key kinds are:
      27             : //
      28             : //      RANGEDEL, RANGEKEYSET, RANGEKEYUNSET, RANGEKEYDEL.
      29             : //
      30             : // Spans either have only RANGEDEL keys (range del spans), or a mix of
      31             : // RANGEKESET/RANGEKEYUNSET/RANGEKEYDEL keys (range key spans).
      32             : //
      33             : // Note that at the user level, range key span start and end keys never have
      34             : // suffixes. Internally, range key spans get fragmented along sstable
      35             : // boundaries; however, this is transparent to the user.
      36             : type Span struct {
      37             :         // Start and End encode the user key range of all the contained items, with
      38             :         // an inclusive start key and exclusive end key. Both Start and End must be
      39             :         // non-nil, or both nil if representing an invalid Span.
      40             :         Start, End []byte
      41             :         // Keys holds the set of keys applied over the [Start, End) user key range.
      42             :         // Keys is sorted by (SeqNum, Kind) descending, unless otherwise specified
      43             :         // by the context. If SeqNum and Kind are equal, the order of Keys is
      44             :         // undefined. Keys may be empty, even if Start and End are non-nil.
      45             :         //
      46             :         // Keys are a decoded representation of the internal keys stored in batches
      47             :         // or sstable blocks. A single internal key in a range key block may produce
      48             :         // several decoded Keys.
      49             :         Keys      []Key
      50             :         KeysOrder KeysOrder
      51             : }
      52             : 
      53             : // KeysOrder describes the ordering of Keys within a Span.
      54             : type KeysOrder int8
      55             : 
      56             : const (
      57             :         // ByTrailerDesc indicates a Span's keys are sorted by InternalKeyTrailer descending.
      58             :         // This is the default ordering, and the ordering used during physical
      59             :         // storage.
      60             :         ByTrailerDesc KeysOrder = iota
      61             :         // BySuffixAsc indicates a Span's keys are sorted by Suffix ascending. This
      62             :         // ordering is used during user iteration of range keys.
      63             :         BySuffixAsc
      64             : )
      65             : 
      66             : // Key represents a single key applied over a span of user keys. A Key is
      67             : // contained by a Span which specifies the span of user keys over which the Key
      68             : // is applied.
      69             : type Key struct {
      70             :         // Trailer contains the key kind and sequence number.
      71             :         Trailer base.InternalKeyTrailer
      72             :         // Suffix holds an optional suffix associated with the key. This is only
      73             :         // non-nil for RANGEKEYSET and RANGEKEYUNSET keys.
      74             :         Suffix []byte
      75             :         // Value holds a logical value associated with the Key. It is NOT the
      76             :         // internal value stored in a range key or range deletion block.  This is
      77             :         // only non-nil for RANGEKEYSET keys.
      78             :         Value []byte
      79             : }
      80             : 
      81             : // SeqNum returns the sequence number component of the key.
      82           1 : func (k Key) SeqNum() base.SeqNum {
      83           1 :         return k.Trailer.SeqNum()
      84           1 : }
      85             : 
      86             : // VisibleAt returns true if the provided key is visible at the provided
      87             : // snapshot sequence number. It interprets batch sequence numbers as always
      88             : // visible, because non-visible batch span keys are filtered when they're
      89             : // fragmented.
      90           1 : func (k Key) VisibleAt(snapshot base.SeqNum) bool {
      91           1 :         seq := k.SeqNum()
      92           1 :         return seq < snapshot || seq&base.SeqNumBatchBit != 0
      93           1 : }
      94             : 
      95             : // Kind returns the kind component of the key.
      96           1 : func (k Key) Kind() base.InternalKeyKind {
      97           1 :         return base.InternalKeyKind(k.Trailer & 0xff)
      98           1 : }
      99             : 
     100             : // Equal returns true if this Key is equal to the given key. Two keys are said
     101             : // to be equal if the two Keys have equal trailers, suffix and value. Suffix
     102             : // comparison uses the provided base.Compare func. Value comparison is bytewise.
     103           1 : func (k Key) Equal(suffixCmp base.CompareRangeSuffixes, b Key) bool {
     104           1 :         return k.Trailer == b.Trailer &&
     105           1 :                 suffixCmp(k.Suffix, b.Suffix) == 0 &&
     106           1 :                 bytes.Equal(k.Value, b.Value)
     107           1 : }
     108             : 
     109             : // CopyFrom copies the contents of another key, retaining the Suffix and Value slices.
     110           1 : func (k *Key) CopyFrom(other Key) {
     111           1 :         k.Trailer = other.Trailer
     112           1 :         k.Suffix = append(k.Suffix[:0], other.Suffix...)
     113           1 :         k.Value = append(k.Value[:0], other.Value...)
     114           1 : }
     115             : 
     116             : // Clone creates a deep clone of the key, copying the Suffix and Value
     117             : // slices.
     118           1 : func (k Key) Clone() Key {
     119           1 :         res := Key{
     120           1 :                 Trailer: k.Trailer,
     121           1 :         }
     122           1 :         if len(k.Suffix) > 0 {
     123           1 :                 res.Suffix = slices.Clone(k.Suffix)
     124           1 :         }
     125           1 :         if len(k.Value) > 0 {
     126           1 :                 res.Value = slices.Clone(k.Value)
     127           1 :         }
     128           1 :         return res
     129             : }
     130             : 
     131           1 : func (k Key) String() string {
     132           1 :         var b strings.Builder
     133           1 :         fmt.Fprintf(&b, "(#%d,%s", k.SeqNum(), k.Kind())
     134           1 :         if len(k.Suffix) > 0 || len(k.Value) > 0 {
     135           1 :                 fmt.Fprintf(&b, ",%s", k.Suffix)
     136           1 :         }
     137           1 :         if len(k.Value) > 0 {
     138           1 :                 fmt.Fprintf(&b, ",%s", k.Value)
     139           1 :         }
     140           1 :         b.WriteString(")")
     141           1 :         return b.String()
     142             : }
     143             : 
     144             : // Valid returns true if the span is defined.
     145           1 : func (s *Span) Valid() bool {
     146           1 :         return s.Start != nil && s.End != nil
     147           1 : }
     148             : 
     149             : // Empty returns true if the span does not contain any keys. An empty span may
     150             : // still be Valid. A non-empty span must be Valid.
     151             : //
     152             : // An Empty span may be produced by Visible, or be produced by iterators in
     153             : // order to surface the gaps between keys.
     154           1 : func (s *Span) Empty() bool {
     155           1 :         return s == nil || len(s.Keys) == 0
     156           1 : }
     157             : 
     158             : // Bounds returns Start and End as UserKeyBounds.
     159           0 : func (s *Span) Bounds() base.UserKeyBounds {
     160           0 :         return base.UserKeyBoundsEndExclusive(s.Start, s.End)
     161           0 : }
     162             : 
     163             : // SmallestKey returns the smallest internal key defined by the span's keys.
     164             : // It requires the Span's keys be in ByTrailerDesc order. It panics if the span
     165             : // contains no keys or its keys are sorted in a different order.
     166           1 : func (s *Span) SmallestKey() base.InternalKey {
     167           1 :         if len(s.Keys) == 0 {
     168           0 :                 panic("pebble: Span contains no keys")
     169           1 :         } else if s.KeysOrder != ByTrailerDesc {
     170           0 :                 panic("pebble: span's keys unexpectedly not in trailer order")
     171             :         }
     172             :         // The first key has the highest (sequence number,kind) tuple.
     173           1 :         return base.InternalKey{
     174           1 :                 UserKey: s.Start,
     175           1 :                 Trailer: s.Keys[0].Trailer,
     176           1 :         }
     177             : }
     178             : 
     179             : // LargestKey returns the largest internal key defined by the span's keys. The
     180             : // returned key will always be a "sentinel key" at the end boundary. The
     181             : // "sentinel key" models the exclusive end boundary by returning an InternalKey
     182             : // with the maximal sequence number, ensuring all InternalKeys with the same
     183             : // user key sort after the sentinel key.
     184             : //
     185             : // It requires the Span's keys be in ByTrailerDesc order. It panics if the span
     186             : // contains no keys or its keys are sorted in a different order.
     187           1 : func (s *Span) LargestKey() base.InternalKey {
     188           1 :         if len(s.Keys) == 0 {
     189           0 :                 panic("pebble: Span contains no keys")
     190           1 :         } else if s.KeysOrder != ByTrailerDesc {
     191           0 :                 panic("pebble: span's keys unexpectedly not in trailer order")
     192             :         }
     193             :         // The last key has the lowest (sequence number,kind) tuple.
     194           1 :         kind := s.Keys[len(s.Keys)-1].Kind()
     195           1 :         return base.MakeExclusiveSentinelKey(kind, s.End)
     196             : }
     197             : 
     198             : // SmallestSeqNum returns the smallest sequence number of a key contained within
     199             : // the span. It requires the Span's keys be in ByTrailerDesc order. It panics if
     200             : // the span contains no keys or its keys are sorted in a different order.
     201           1 : func (s *Span) SmallestSeqNum() base.SeqNum {
     202           1 :         if len(s.Keys) == 0 {
     203           0 :                 panic("pebble: Span contains no keys")
     204           1 :         } else if s.KeysOrder != ByTrailerDesc {
     205           0 :                 panic("pebble: span's keys unexpectedly not in trailer order")
     206             :         }
     207             : 
     208           1 :         return s.Keys[len(s.Keys)-1].SeqNum()
     209             : }
     210             : 
     211             : // LargestSeqNum returns the largest sequence number of a key contained within
     212             : // the span. It requires the Span's keys be in ByTrailerDesc order. It panics if
     213             : // the span contains no keys or its keys are sorted in a different order.
     214           1 : func (s *Span) LargestSeqNum() base.SeqNum {
     215           1 :         if len(s.Keys) == 0 {
     216           0 :                 panic("pebble: Span contains no keys")
     217           1 :         } else if s.KeysOrder != ByTrailerDesc {
     218           0 :                 panic("pebble: span's keys unexpectedly not in trailer order")
     219             :         }
     220           1 :         return s.Keys[0].SeqNum()
     221             : }
     222             : 
     223             : // LargestVisibleSeqNum returns the largest sequence number of a key contained
     224             : // within the span that's also visible at the provided snapshot sequence number.
     225             : // It requires the Span's keys be in ByTrailerDesc order. It panics if the span
     226             : // contains no keys or its keys are sorted in a different order.
     227           1 : func (s *Span) LargestVisibleSeqNum(snapshot base.SeqNum) (largest base.SeqNum, ok bool) {
     228           1 :         if s == nil {
     229           1 :                 return 0, false
     230           1 :         } else if len(s.Keys) == 0 {
     231           0 :                 panic("pebble: Span contains no keys")
     232           1 :         } else if s.KeysOrder != ByTrailerDesc {
     233           0 :                 panic("pebble: span's keys unexpectedly not in trailer order")
     234             :         }
     235           1 :         for i := range s.Keys {
     236           1 :                 if s.Keys[i].VisibleAt(snapshot) {
     237           1 :                         return s.Keys[i].SeqNum(), true
     238           1 :                 }
     239             :         }
     240           1 :         return 0, false
     241             : }
     242             : 
     243             : // TODO(jackson): Replace most of the calls to Visible with more targeted calls
     244             : // that avoid the need to construct a new Span.
     245             : 
     246             : // Visible returns a span with the subset of keys visible at the provided
     247             : // sequence number. It requires the Span's keys be in ByTrailerDesc order. It
     248             : // panics if the span's keys are sorted in a different order.
     249             : //
     250             : // Visible may incur an allocation, so callers should prefer targeted,
     251             : // non-allocating methods when possible.
     252           1 : func (s Span) Visible(snapshot base.SeqNum) Span {
     253           1 :         if s.KeysOrder != ByTrailerDesc {
     254           0 :                 panic("pebble: span's keys unexpectedly not in trailer order")
     255             :         }
     256             : 
     257           1 :         ret := Span{Start: s.Start, End: s.End}
     258           1 :         if len(s.Keys) == 0 {
     259           0 :                 return ret
     260           0 :         }
     261             : 
     262             :         // Keys from indexed batches may force an allocation. The Keys slice is
     263             :         // ordered by sequence number, so ordinarily we can return the trailing
     264             :         // subslice containing keys with sequence numbers less than `seqNum`.
     265             :         //
     266             :         // However, batch keys are special. Only visible batch keys are included
     267             :         // when an Iterator's batch spans are fragmented. They must always be
     268             :         // visible.
     269             :         //
     270             :         // Batch keys can create a sandwich of visible batch keys at the beginning
     271             :         // of the slice and visible committed keys at the end of the slice, forcing
     272             :         // us to allocate a new slice and copy the contents.
     273             :         //
     274             :         // Care is taking to only incur an allocation only when batch keys and
     275             :         // visible keys actually sandwich non-visible keys.
     276             : 
     277             :         // lastBatchIdx and lastNonVisibleIdx are set to the last index of a batch
     278             :         // key and a non-visible key respectively.
     279           1 :         lastBatchIdx := -1
     280           1 :         lastNonVisibleIdx := -1
     281           1 :         for i := range s.Keys {
     282           1 :                 if seqNum := s.Keys[i].SeqNum(); seqNum&base.SeqNumBatchBit != 0 {
     283           1 :                         // Batch key. Always visible.
     284           1 :                         lastBatchIdx = i
     285           1 :                 } else if seqNum >= snapshot {
     286           1 :                         // This key is not visible.
     287           1 :                         lastNonVisibleIdx = i
     288           1 :                 }
     289             :         }
     290             : 
     291             :         // In the following comments: b = batch, h = hidden, v = visible (committed).
     292           1 :         switch {
     293           1 :         case lastNonVisibleIdx == -1:
     294           1 :                 // All keys are visible.
     295           1 :                 //
     296           1 :                 // [b b b], [v v v] and [b b b v v v]
     297           1 :                 ret.Keys = s.Keys
     298           1 :         case lastBatchIdx == -1:
     299           1 :                 // There are no batch keys, so we can return the continuous subslice
     300           1 :                 // starting after the last non-visible Key.
     301           1 :                 //
     302           1 :                 // h h h [v v v]
     303           1 :                 ret.Keys = s.Keys[lastNonVisibleIdx+1:]
     304           1 :         case lastNonVisibleIdx == len(s.Keys)-1:
     305           1 :                 // While we have a batch key and non-visible keys, there are no
     306           1 :                 // committed visible keys. The 'sandwich' is missing the bottom layer,
     307           1 :                 // so we can return the continuous sublice at the beginning.
     308           1 :                 //
     309           1 :                 // [b b b] h h h
     310           1 :                 ret.Keys = s.Keys[0 : lastBatchIdx+1]
     311           1 :         default:
     312           1 :                 // This is the problematic sandwich case. Allocate a new slice, copying
     313           1 :                 // the batch keys and the visible keys into it.
     314           1 :                 //
     315           1 :                 // [b b b] h h h [v v v]
     316           1 :                 ret.Keys = make([]Key, (lastBatchIdx+1)+(len(s.Keys)-lastNonVisibleIdx-1))
     317           1 :                 copy(ret.Keys, s.Keys[:lastBatchIdx+1])
     318           1 :                 copy(ret.Keys[lastBatchIdx+1:], s.Keys[lastNonVisibleIdx+1:])
     319             :         }
     320           1 :         return ret
     321             : }
     322             : 
     323             : // VisibleAt returns true if the span contains a key visible at the provided
     324             : // snapshot. Keys with sequence numbers with the batch bit set are treated as
     325             : // always visible.
     326             : //
     327             : // VisibleAt requires the Span's keys be in ByTrailerDesc order. It panics if
     328             : // the span's keys are sorted in a different order.
     329           1 : func (s *Span) VisibleAt(snapshot base.SeqNum) bool {
     330           1 :         if s.KeysOrder != ByTrailerDesc {
     331           0 :                 panic("pebble: span's keys unexpectedly not in trailer order")
     332             :         }
     333           1 :         if len(s.Keys) == 0 {
     334           0 :                 return false
     335           1 :         } else if first := s.Keys[0].SeqNum(); first&base.SeqNumBatchBit != 0 {
     336           1 :                 // Only visible batch keys are included when an Iterator's batch spans
     337           1 :                 // are fragmented. They must always be visible.
     338           1 :                 return true
     339           1 :         } else {
     340           1 :                 // Otherwise we check the last key. Since keys are ordered decreasing in
     341           1 :                 // sequence number, the last key has the lowest sequence number of any
     342           1 :                 // of the span's keys. If any of the keys are visible, the last key must
     343           1 :                 // be visible. Or put differently: if the last key is not visible, then
     344           1 :                 // no key is visible.
     345           1 :                 return s.Keys[len(s.Keys)-1].SeqNum() < snapshot
     346           1 :         }
     347             : }
     348             : 
     349             : // Clone clones the span, creating copies of all contained slices. Clone is
     350             : // allocation heavy and should not be used in hot paths.
     351           1 : func (s *Span) Clone() Span {
     352           1 :         c := Span{
     353           1 :                 Start:     slices.Clone(s.Start),
     354           1 :                 End:       slices.Clone(s.End),
     355           1 :                 KeysOrder: s.KeysOrder,
     356           1 :         }
     357           1 :         c.Keys = make([]Key, len(s.Keys))
     358           1 :         for i := range c.Keys {
     359           1 :                 c.Keys[i] = s.Keys[i].Clone()
     360           1 :         }
     361           1 :         return c
     362             : }
     363             : 
     364             : // Contains returns true if the specified key resides within the span's bounds.
     365           1 : func (s *Span) Contains(cmp base.Compare, key []byte) bool {
     366           1 :         return cmp(s.Start, key) <= 0 && cmp(key, s.End) < 0
     367           1 : }
     368             : 
     369             : // Covers returns true if the span covers keys at seqNum.
     370             : //
     371             : // Covers requires the Span's keys be in ByTrailerDesc order. It panics if the
     372             : // span's keys are sorted in a different order.
     373           1 : func (s Span) Covers(seqNum base.SeqNum) bool {
     374           1 :         if s.KeysOrder != ByTrailerDesc {
     375           0 :                 panic("pebble: span's keys unexpectedly not in trailer order")
     376             :         }
     377           1 :         return !s.Empty() && s.Keys[0].SeqNum() > seqNum
     378             : }
     379             : 
     380             : // CoversAt returns true if the span contains a key that is visible at the
     381             : // provided snapshot sequence number, and that key's sequence number is higher
     382             : // than seqNum.
     383             : //
     384             : // Keys with sequence numbers with the batch bit set are treated as always
     385             : // visible.
     386             : //
     387             : // CoversAt requires the Span's keys be in ByTrailerDesc order. It panics if the
     388             : // span's keys are sorted in a different order.
     389           1 : func (s *Span) CoversAt(snapshot, seqNum base.SeqNum) bool {
     390           1 :         if s.KeysOrder != ByTrailerDesc {
     391           0 :                 panic("pebble: span's keys unexpectedly not in trailer order")
     392             :         }
     393             :         // NB: A key is visible at `snapshot` if its sequence number is strictly
     394             :         // less than `snapshot`. See base.Visible.
     395           1 :         for i := range s.Keys {
     396           1 :                 if kseq := s.Keys[i].SeqNum(); kseq&base.SeqNumBatchBit != 0 {
     397           1 :                         // Only visible batch keys are included when an Iterator's batch spans
     398           1 :                         // are fragmented. They must always be visible.
     399           1 :                         return kseq > seqNum
     400           1 :                 } else if kseq < snapshot {
     401           1 :                         return kseq > seqNum
     402           1 :                 }
     403             :         }
     404           1 :         return false
     405             : }
     406             : 
     407             : // Reset clears the span's Start, End, and Keys fields, retaining the slices for
     408             : // reuse.
     409           1 : func (s *Span) Reset() {
     410           1 :         s.Start = s.Start[:0]
     411           1 :         s.End = s.End[:0]
     412           1 :         s.Keys = s.Keys[:0]
     413           1 : }
     414             : 
     415             : // CopyFrom deep-copies the contents of the other span, retaining the slices
     416             : // allocated in this span.
     417           1 : func (s *Span) CopyFrom(other *Span) {
     418           1 :         s.Start = append(s.Start[:0], other.Start...)
     419           1 :         s.End = append(s.End[:0], other.End...)
     420           1 : 
     421           1 :         // We want to preserve any existing Suffix/Value buffers.
     422           1 :         if cap(s.Keys) >= len(other.Keys) {
     423           1 :                 s.Keys = s.Keys[:len(other.Keys)]
     424           1 :         } else {
     425           1 :                 s.Keys = append(s.Keys[:cap(s.Keys)], make([]Key, len(other.Keys)-cap(s.Keys))...)
     426           1 :         }
     427           1 :         for i := range other.Keys {
     428           1 :                 s.Keys[i].CopyFrom(other.Keys[i])
     429           1 :         }
     430             : 
     431           1 :         s.KeysOrder = other.KeysOrder
     432             : }
     433             : 
     434             : // String returns a string representation of the span.
     435           1 : func (s Span) String() string {
     436           1 :         return fmt.Sprint(prettySpan{Span: s, formatKey: base.DefaultFormatter})
     437           1 : }
     438             : 
     439             : // Pretty returns a formatter for the span.
     440           1 : func (s Span) Pretty(f base.FormatKey) fmt.Formatter {
     441           1 :         // TODO(jackson): Take a base.FormatValue to format Key.Value too.
     442           1 :         return prettySpan{s, f}
     443           1 : }
     444             : 
     445             : type prettySpan struct {
     446             :         Span
     447             :         formatKey base.FormatKey
     448             : }
     449             : 
     450           1 : func (s prettySpan) Format(fs fmt.State, c rune) {
     451           1 :         if !s.Valid() {
     452           1 :                 fmt.Fprintf(fs, "<invalid>")
     453           1 :                 return
     454           1 :         }
     455           1 :         fmt.Fprintf(fs, "%s-%s:{", s.formatKey(s.Start), s.formatKey(s.End))
     456           1 :         for i, k := range s.Keys {
     457           1 :                 if i > 0 {
     458           1 :                         fmt.Fprint(fs, " ")
     459           1 :                 }
     460           1 :                 fmt.Fprint(fs, k.String())
     461             :         }
     462           1 :         fmt.Fprintf(fs, "}")
     463             : }
     464             : 
     465             : // SortKeysByTrailer sorts a Keys slice by trailer.
     466           1 : func SortKeysByTrailer(keys []Key) {
     467           1 :         slices.SortFunc(keys, func(a, b Key) int {
     468           1 :                 // Trailer are ordered in decreasing number order.
     469           1 :                 return -cmp.Compare(a.Trailer, b.Trailer)
     470           1 :         })
     471             : }
     472             : 
     473             : // SortKeysByTrailerAndSuffix sorts a Keys slice by trailer, and among keys with
     474             : // equal trailers, by suffix.
     475           1 : func SortKeysByTrailerAndSuffix(suffixCmp base.CompareRangeSuffixes, keys []Key) {
     476           1 :         slices.SortFunc(keys, func(a, b Key) int {
     477           1 :                 // Trailer are ordered in decreasing number order.
     478           1 :                 if v := cmp.Compare(b.Trailer, a.Trailer); v != 0 {
     479           1 :                         return v
     480           1 :                 }
     481           1 :                 return suffixCmp(a.Suffix, b.Suffix)
     482             :         })
     483             : }
     484             : 
     485             : // SortSpansByStartKey sorts the spans by start key.
     486             : //
     487             : // This is the ordering required by the Fragmenter. Usually spans are naturally
     488             : // sorted by their start key, but that isn't true for range deletion tombstones
     489             : // in the legacy range-del-v1 block format.
     490           1 : func SortSpansByStartKey(cmp base.Compare, spans []Span) {
     491           1 :         slices.SortFunc(spans, func(a, b Span) int {
     492           1 :                 return cmp(a.Start, b.Start)
     493           1 :         })
     494             : }
     495             : 
     496             : // SortSpansByEndKey sorts the spans by the end key.
     497           1 : func SortSpansByEndKey(cmp base.Compare, spans []Span) {
     498           1 :         slices.SortFunc(spans, func(a, b Span) int {
     499           1 :                 return cmp(a.End, b.End)
     500           1 :         })
     501             : }
     502             : 
     503             : // ParseSpan parses the string representation of a Span. It's intended for
     504             : // tests. ParseSpan panics if passed a malformed span representation.
     505           1 : func ParseSpan(input string) Span {
     506           1 :         var s Span
     507           1 :         parts := strings.FieldsFunc(input, func(r rune) bool {
     508           1 :                 switch r {
     509           1 :                 case '-', ':', '{', '}':
     510           1 :                         return true
     511           1 :                 default:
     512           1 :                         return unicode.IsSpace(r)
     513             :                 }
     514             :         })
     515           1 :         s.Start, s.End = []byte(parts[0]), []byte(parts[1])
     516           1 : 
     517           1 :         // Each of the remaining parts represents a single Key.
     518           1 :         s.Keys = make([]Key, 0, len(parts)-2)
     519           1 :         for _, p := range parts[2:] {
     520           1 :                 if len(p) >= 2 && p[0] == '(' && p[len(p)-1] == ')' {
     521           1 :                         p = p[1 : len(p)-1]
     522           1 :                 }
     523           1 :                 keyFields := strings.FieldsFunc(p, func(r rune) bool {
     524           1 :                         switch r {
     525           1 :                         case '#', ',':
     526           1 :                                 return true
     527           1 :                         default:
     528           1 :                                 return unicode.IsSpace(r)
     529             :                         }
     530             :                 })
     531             : 
     532           1 :                 var k Key
     533           1 :                 seqNum := base.ParseSeqNum(keyFields[0])
     534           1 :                 kind := base.ParseKind(keyFields[1])
     535           1 :                 k.Trailer = base.MakeTrailer(seqNum, kind)
     536           1 :                 // Parse the optional suffix.
     537           1 :                 if len(keyFields) >= 3 {
     538           1 :                         k.Suffix = []byte(keyFields[2])
     539           1 :                 }
     540             :                 // Parse the optional value.
     541           1 :                 if len(keyFields) >= 4 {
     542           1 :                         k.Value = []byte(keyFields[3])
     543           1 :                 }
     544           1 :                 s.Keys = append(s.Keys, k)
     545             :         }
     546           1 :         for i := 1; i < len(s.Keys); i++ {
     547           1 :                 if s.Keys[i-1].Trailer < s.Keys[i].Trailer {
     548           0 :                         panic(fmt.Sprintf("span keys not sorted: %s %s", s.Keys[i-1], s.Keys[i]))
     549             :                 }
     550             :         }
     551           1 :         s.KeysOrder = ByTrailerDesc
     552           1 :         return s
     553             : }

Generated by: LCOV version 1.14