LCOV - code coverage report
Current view: top level - pebble/sstable/colblk - keyspan.go (source / functions) Hit Total Coverage
Test: 2024-09-30 08:16Z d93251cc - tests + meta.lcov Lines: 294 313 93.9 %
Date: 2024-09-30 08:17:48 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 colblk
       6             : 
       7             : import (
       8             :         "bytes"
       9             :         "context"
      10             :         "encoding/binary"
      11             :         "fmt"
      12             :         "os"
      13             :         "sync"
      14             : 
      15             :         "github.com/cockroachdb/errors"
      16             :         "github.com/cockroachdb/pebble/internal/base"
      17             :         "github.com/cockroachdb/pebble/internal/binfmt"
      18             :         "github.com/cockroachdb/pebble/internal/invariants"
      19             :         "github.com/cockroachdb/pebble/internal/keyspan"
      20             :         "github.com/cockroachdb/pebble/internal/treeprinter"
      21             :         "github.com/cockroachdb/pebble/sstable/block"
      22             : )
      23             : 
      24             : // the keyspan header encodes a 32-bit count of the number of unique boundary
      25             : // user keys in the block.
      26             : const keyspanHeaderSize = 4
      27             : 
      28             : // keyspan block column indexes
      29             : const (
      30             :         // Columns with 1 row per unique boundary user key contained within the
      31             :         // block (with the count indicated via the keyspan custom block header).
      32             :         keyspanColBoundaryUserKeys   = 0
      33             :         keyspanColBoundaryKeyIndices = 1
      34             :         // Columns with 1 row per keyspan.Key (with the count indicated via the
      35             :         // columnar header's row count).
      36             :         keyspanColTrailers = 2
      37             :         keyspanColSuffixes = 3
      38             :         keyspanColValues   = 4
      39             :         keyspanColumnCount = 5
      40             : )
      41             : 
      42             : // A KeyspanBlockWriter writes keyspan blocks. See the colblk package
      43             : // documentation for more details on the schema.
      44             : type KeyspanBlockWriter struct {
      45             :         equal base.Equal
      46             : 
      47             :         // boundary columns
      48             :         boundaryUserKeys   RawBytesBuilder
      49             :         boundaryKeyIndexes UintBuilder
      50             : 
      51             :         // keyspan.Key columns
      52             :         trailers UintBuilder
      53             :         suffixes RawBytesBuilder
      54             :         values   RawBytesBuilder
      55             : 
      56             :         enc               blockEncoder
      57             :         keyCount          int
      58             :         unsafeLastUserKey []byte
      59             : }
      60             : 
      61             : // Init initializes a keyspan block writer.
      62           1 : func (w *KeyspanBlockWriter) Init(equal base.Equal) {
      63           1 :         w.equal = equal
      64           1 :         w.boundaryUserKeys.Init()
      65           1 :         w.boundaryKeyIndexes.Init()
      66           1 :         w.trailers.Init()
      67           1 :         w.suffixes.Init()
      68           1 :         w.values.Init()
      69           1 :         w.keyCount = 0
      70           1 :         w.unsafeLastUserKey = nil
      71           1 : }
      72             : 
      73             : // Reset resets the keyspan block writer to an empty state, retaining memory for
      74             : // reuse.
      75           1 : func (w *KeyspanBlockWriter) Reset() {
      76           1 :         w.boundaryUserKeys.Reset()
      77           1 :         w.boundaryKeyIndexes.Reset()
      78           1 :         w.trailers.Reset()
      79           1 :         w.suffixes.Reset()
      80           1 :         w.values.Reset()
      81           1 :         w.enc.reset()
      82           1 :         w.keyCount = 0
      83           1 :         w.unsafeLastUserKey = nil
      84           1 : }
      85             : 
      86             : // AddSpan appends a new Span to the pending block. Spans must already be
      87             : // fragmented (non-overlapping) and added in sorted order.
      88           1 : func (w *KeyspanBlockWriter) AddSpan(s keyspan.Span) {
      89           1 :         // When keyspans are fragmented, abutting spans share a user key. One span's
      90           1 :         // end key is the next span's start key.  Check if the previous user key
      91           1 :         // equals this span's start key, and avoid encoding it again if so.
      92           1 :         if w.unsafeLastUserKey == nil || !w.equal(w.unsafeLastUserKey, s.Start) {
      93           1 :                 w.boundaryKeyIndexes.Set(w.boundaryUserKeys.rows, uint64(w.keyCount))
      94           1 :                 w.boundaryUserKeys.Put(s.Start)
      95           1 :         }
      96             :         // The end key must be strictly greater than the start key and spans are
      97             :         // already sorted, so the end key is guaranteed to not be present in the
      98             :         // column yet. We need to encode it.
      99           1 :         w.boundaryKeyIndexes.Set(w.boundaryUserKeys.rows, uint64(w.keyCount+len(s.Keys)))
     100           1 :         w.boundaryUserKeys.Put(s.End)
     101           1 : 
     102           1 :         // Hold on to a slice of the copy of s.End we just added to the bytes
     103           1 :         // builder so that we can compare it to the next span's start key.
     104           1 :         w.unsafeLastUserKey = w.boundaryUserKeys.data[len(w.boundaryUserKeys.data)-len(s.End):]
     105           1 : 
     106           1 :         // Encode each keyspan.Key in the span.
     107           1 :         for i := range s.Keys {
     108           1 :                 w.trailers.Set(w.keyCount, uint64(s.Keys[i].Trailer))
     109           1 :                 w.suffixes.Put(s.Keys[i].Suffix)
     110           1 :                 w.values.Put(s.Keys[i].Value)
     111           1 :                 w.keyCount++
     112           1 :         }
     113             : }
     114             : 
     115             : // KeyCount returns the count of keyspan.Keys written to the writer.
     116           1 : func (w *KeyspanBlockWriter) KeyCount() int {
     117           1 :         return w.keyCount
     118           1 : }
     119             : 
     120             : // UnsafeBoundaryKeys returns the smallest and largest keys written to the
     121             : // keyspan block so far. The returned internal keys have user keys that point
     122             : // directly into the block writer's memory and must not be mutated.
     123           1 : func (w *KeyspanBlockWriter) UnsafeBoundaryKeys() (smallest, largest base.InternalKey) {
     124           1 :         if w.keyCount == 0 {
     125           0 :                 return smallest, largest
     126           0 :         }
     127           1 :         smallest.UserKey = w.boundaryUserKeys.UnsafeGet(0)
     128           1 :         smallest.Trailer = base.InternalKeyTrailer(w.trailers.Get(0))
     129           1 :         largest.UserKey = w.boundaryUserKeys.UnsafeGet(w.boundaryUserKeys.rows - 1)
     130           1 :         largest.Trailer = base.MakeTrailer(base.SeqNumMax,
     131           1 :                 base.InternalKeyTrailer(w.trailers.Get(w.keyCount-1)).Kind())
     132           1 :         return smallest, largest
     133             : }
     134             : 
     135             : // Size returns the size of the pending block.
     136           1 : func (w *KeyspanBlockWriter) Size() int {
     137           1 :         off := blockHeaderSize(keyspanColumnCount, keyspanHeaderSize)
     138           1 :         // Span boundary columns (with userKeyCount elements).
     139           1 :         off = w.boundaryUserKeys.Size(w.boundaryUserKeys.rows, off)
     140           1 :         off = w.boundaryKeyIndexes.Size(w.boundaryUserKeys.rows, off)
     141           1 : 
     142           1 :         // keyspan.Key columns (with keyCount elements).
     143           1 :         off = w.trailers.Size(w.keyCount, off)
     144           1 :         off = w.suffixes.Size(w.keyCount, off)
     145           1 :         off = w.values.Size(w.keyCount, off)
     146           1 :         off++ // trailing padding
     147           1 :         return int(off)
     148           1 : }
     149             : 
     150             : // Finish finalizes the pending block and returns the encoded block.
     151           1 : func (w *KeyspanBlockWriter) Finish() []byte {
     152           1 :         w.enc.init(w.Size(), Header{
     153           1 :                 Version: Version1,
     154           1 :                 Columns: keyspanColumnCount,
     155           1 :                 Rows:    uint32(w.keyCount),
     156           1 :         }, keyspanHeaderSize)
     157           1 : 
     158           1 :         // The keyspan block has a 4-byte custom header used to encode the number of
     159           1 :         // user keys encoded within the user key and start indices columns. All
     160           1 :         // other columns have the number of rows indicated by the shared columnar
     161           1 :         // block header.
     162           1 :         binary.LittleEndian.PutUint32(w.enc.data()[:keyspanHeaderSize], uint32(w.boundaryUserKeys.rows))
     163           1 : 
     164           1 :         // Columns with userKeyCount elements.
     165           1 :         w.enc.encode(w.boundaryUserKeys.rows, &w.boundaryUserKeys)
     166           1 :         w.enc.encode(w.boundaryUserKeys.rows, &w.boundaryKeyIndexes)
     167           1 :         // Columns with keyCount elements.
     168           1 :         w.enc.encode(w.keyCount, &w.trailers)
     169           1 :         w.enc.encode(w.keyCount, &w.suffixes)
     170           1 :         w.enc.encode(w.keyCount, &w.values)
     171           1 :         return w.enc.finish()
     172           1 : }
     173             : 
     174             : // String returns a string representation of the pending block's state.
     175           1 : func (w *KeyspanBlockWriter) String() string {
     176           1 :         var buf bytes.Buffer
     177           1 :         size := uint32(w.Size())
     178           1 :         fmt.Fprintf(&buf, "size=%d:\n", size)
     179           1 : 
     180           1 :         fmt.Fprint(&buf, "0: user keys:      ")
     181           1 :         w.boundaryUserKeys.WriteDebug(&buf, w.boundaryUserKeys.rows)
     182           1 :         fmt.Fprintln(&buf)
     183           1 :         fmt.Fprint(&buf, "1: start indices:  ")
     184           1 :         w.boundaryKeyIndexes.WriteDebug(&buf, w.boundaryUserKeys.rows)
     185           1 :         fmt.Fprintln(&buf)
     186           1 : 
     187           1 :         fmt.Fprint(&buf, "2: trailers:       ")
     188           1 :         w.trailers.WriteDebug(&buf, w.keyCount)
     189           1 :         fmt.Fprintln(&buf)
     190           1 :         fmt.Fprint(&buf, "3: suffixes:       ")
     191           1 :         w.suffixes.WriteDebug(&buf, w.keyCount)
     192           1 :         fmt.Fprintln(&buf)
     193           1 :         fmt.Fprint(&buf, "4: values:         ")
     194           1 :         w.values.WriteDebug(&buf, w.keyCount)
     195           1 :         fmt.Fprintln(&buf)
     196           1 : 
     197           1 :         return buf.String()
     198           1 : }
     199             : 
     200             : // A KeyspanReader exposes facilities for reading a keyspan block. A
     201             : // KeyspanReader is safe for concurrent use and may be used by multiple
     202             : // KeyspanIters concurrently.
     203             : type KeyspanReader struct {
     204             :         blockReader BlockReader
     205             :         // Span boundary columns with boundaryKeysCount elements.
     206             :         boundaryKeysCount  uint32
     207             :         boundaryKeys       RawBytes
     208             :         boundaryKeyIndices UnsafeUints
     209             : 
     210             :         // keyspan.Key columns with blockReader.header.Rows elements.
     211             :         trailers UnsafeUints
     212             :         suffixes RawBytes
     213             :         values   RawBytes
     214             : }
     215             : 
     216             : // Init initializes the keyspan reader with the given block data.
     217           1 : func (r *KeyspanReader) Init(data []byte) {
     218           1 :         r.boundaryKeysCount = binary.LittleEndian.Uint32(data[:4])
     219           1 :         r.blockReader.Init(data, keyspanHeaderSize)
     220           1 :         // The boundary key columns have a different number of rows than the other
     221           1 :         // columns, so we call DecodeColumn directly, taking care to pass in
     222           1 :         // rows=r.boundaryKeysCount.
     223           1 :         r.boundaryKeys = DecodeColumn(&r.blockReader, keyspanColBoundaryUserKeys,
     224           1 :                 int(r.boundaryKeysCount), DataTypeBytes, DecodeRawBytes)
     225           1 :         r.boundaryKeyIndices = DecodeColumn(&r.blockReader, keyspanColBoundaryKeyIndices,
     226           1 :                 int(r.boundaryKeysCount), DataTypeUint, DecodeUnsafeUints)
     227           1 : 
     228           1 :         r.trailers = r.blockReader.Uints(keyspanColTrailers)
     229           1 :         r.suffixes = r.blockReader.RawBytes(keyspanColSuffixes)
     230           1 :         r.values = r.blockReader.RawBytes(keyspanColValues)
     231           1 : }
     232             : 
     233             : // DebugString prints a human-readable explanation of the keyspan block's binary
     234             : // representation.
     235           1 : func (r *KeyspanReader) DebugString() string {
     236           1 :         f := binfmt.New(r.blockReader.data).LineWidth(20)
     237           1 :         r.Describe(f)
     238           1 :         return f.String()
     239           1 : }
     240             : 
     241             : // Describe describes the binary format of the keyspan block, assuming
     242             : // f.Offset() is positioned at the beginning of the same keyspan block described
     243             : // by r.
     244           1 : func (r *KeyspanReader) Describe(f *binfmt.Formatter) {
     245           1 :         // Set the relative offset. When loaded into memory, the beginning of blocks
     246           1 :         // are aligned. Padding that ensures alignment is done relative to the
     247           1 :         // current offset. Setting the relative offset ensures that if we're
     248           1 :         // describing this block within a larger structure (eg, f.Offset()>0), we
     249           1 :         // compute padding appropriately assuming the current byte f.Offset() is
     250           1 :         // aligned.
     251           1 :         f.SetAnchorOffset()
     252           1 : 
     253           1 :         f.CommentLine("keyspan block header")
     254           1 :         f.HexBytesln(4, "user key count: %d", r.boundaryKeysCount)
     255           1 :         r.blockReader.headerToBinFormatter(f)
     256           1 : 
     257           1 :         for i := 0; i < keyspanColumnCount; i++ {
     258           1 :                 // Not all columns in a keyspan block have the same number of rows; the
     259           1 :                 // boundary columns columns are different (and their lengths are held in
     260           1 :                 // the keyspan block header that precedes the ordinary columnar block
     261           1 :                 // header).
     262           1 :                 rows := int(r.blockReader.header.Rows)
     263           1 :                 if i == keyspanColBoundaryUserKeys || i == keyspanColBoundaryKeyIndices {
     264           1 :                         rows = int(r.boundaryKeysCount)
     265           1 :                 }
     266           1 :                 r.blockReader.columnToBinFormatter(f, i, rows)
     267             :         }
     268           1 :         f.HexBytesln(1, "block padding byte")
     269             : }
     270             : 
     271             : // searchBoundaryKeys returns the index of the first boundary key greater than
     272             : // or equal to key and whether or not the key was found exactly.
     273           1 : func (r *KeyspanReader) searchBoundaryKeys(cmp base.Compare, key []byte) (index int, equal bool) {
     274           1 :         i, j := 0, int(r.boundaryKeysCount)
     275           1 :         for i < j {
     276           1 :                 h := int(uint(i+j) >> 1) // avoid overflow when computing h
     277           1 :                 // i ≤ h < j
     278           1 :                 switch cmp(key, r.boundaryKeys.At(h)) {
     279           1 :                 case +1:
     280           1 :                         i = h + 1
     281           1 :                 case 0:
     282           1 :                         return h, true
     283           1 :                 default:
     284           1 :                         // -1
     285           1 :                         j = h
     286             :                 }
     287             :         }
     288           1 :         return i, false
     289             : }
     290             : 
     291             : // NewKeyspanIter constructs a new iterator over a keyspan columnar block.
     292             : func NewKeyspanIter(
     293             :         cmp base.Compare, h block.BufferHandle, transforms block.FragmentIterTransforms,
     294           1 : ) *KeyspanIter {
     295           1 :         i := keyspanIterPool.Get().(*KeyspanIter)
     296           1 :         i.closeCheck = invariants.CloseChecker{}
     297           1 :         i.handle = h
     298           1 :         // TODO(jackson): We can teach the block cache to stash a *KeyspanReader.
     299           1 :         // Then all iters would use the same reader rather than needing to allocate
     300           1 :         // their own KeyspanReader and parse the high-level block structure
     301           1 :         // themselves.
     302           1 :         i.allocReader.Init(h.Get())
     303           1 :         i.init(cmp, &i.allocReader, transforms)
     304           1 :         return i
     305           1 : }
     306             : 
     307             : var keyspanIterPool = sync.Pool{
     308           1 :         New: func() interface{} {
     309           1 :                 i := &KeyspanIter{}
     310           1 :                 invariants.SetFinalizer(i, checkKeyspanIter)
     311           1 :                 return i
     312           1 :         },
     313             : }
     314             : 
     315             : // A KeyspanIter is an iterator over a columnar keyspan block. It implements the
     316             : // keyspan.FragmentIterator interface.
     317             : type KeyspanIter struct {
     318             :         keyspanIter
     319             :         handle      block.BufferHandle
     320             :         allocReader KeyspanReader
     321             : 
     322             :         closeCheck invariants.CloseChecker
     323             : }
     324             : 
     325             : // Close closes the iterator.
     326           1 : func (i *KeyspanIter) Close() {
     327           1 :         i.handle.Release()
     328           1 :         i.handle = block.BufferHandle{}
     329           1 : 
     330           1 :         if invariants.Sometimes(25) {
     331           1 :                 // In invariants mode, sometimes don't add the object to the pool so
     332           1 :                 // that we can check for double closes that take longer than the object
     333           1 :                 // stays in the pool.
     334           1 :                 return
     335           1 :         }
     336             : 
     337           1 :         i.keyspanIter.Close()
     338           1 :         i.allocReader = KeyspanReader{}
     339           1 :         i.closeCheck.Close()
     340           1 :         keyspanIterPool.Put(i)
     341             : }
     342             : 
     343             : // A keyspanIter is an iterator over a keyspan block. It implements the
     344             : // keyspan.FragmentIterator interface.
     345             : type keyspanIter struct {
     346             :         r          *KeyspanReader
     347             :         cmp        base.Compare
     348             :         transforms block.FragmentIterTransforms
     349             :         span       keyspan.Span
     350             :         // When positioned, the current span's start key is the user key at
     351             :         //   i.r.userKeys.At(i.startBoundIndex)
     352             :         // and the current span's end key is the user key at
     353             :         //   i.r.userKeys.At(i.startBoundIndex+1)
     354             :         startBoundIndex int
     355             :         keyBuf          [2]keyspan.Key
     356             : }
     357             : 
     358             : // Assert that KeyspanIter implements the FragmentIterator interface.
     359             : var _ keyspan.FragmentIterator = (*keyspanIter)(nil)
     360             : 
     361             : // init initializes the iterator with the given comparison function and keyspan
     362             : // reader.
     363             : func (i *keyspanIter) init(
     364             :         cmp base.Compare, r *KeyspanReader, transforms block.FragmentIterTransforms,
     365           1 : ) {
     366           1 :         i.r = r
     367           1 :         i.cmp = cmp
     368           1 :         i.transforms = transforms
     369           1 :         i.span.Start, i.span.End = nil, nil
     370           1 :         i.startBoundIndex = -1
     371           1 :         if i.span.Keys == nil {
     372           1 :                 i.span.Keys = i.keyBuf[:0]
     373           1 :         }
     374             : }
     375             : 
     376             : // SeekGE moves the iterator to the first span covering a key greater than
     377             : // or equal to the given key. This is equivalent to seeking to the first
     378             : // span with an end key greater than the given key.
     379           1 : func (i *keyspanIter) SeekGE(key []byte) (*keyspan.Span, error) {
     380           1 :         // Seek among the boundary keys.
     381           1 :         j, eq := i.r.searchBoundaryKeys(i.cmp, key)
     382           1 :         // If the found boundary key does not exactly equal the given key, it's
     383           1 :         // strictly greater than key. We need to back up one to consider the span
     384           1 :         // that ends at the this boundary key.
     385           1 :         if !eq {
     386           1 :                 j = max(j-1, 0)
     387           1 :         }
     388           1 :         return i.gatherKeysForward(j), nil
     389             : }
     390             : 
     391             : // SeekLT moves the iterator to the last span covering a key less than the
     392             : // given key. This is equivalent to seeking to the last span with a start
     393             : // key less than the given key.
     394           1 : func (i *keyspanIter) SeekLT(key []byte) (*keyspan.Span, error) {
     395           1 :         // Seek among the boundary keys.
     396           1 :         j, eq := i.r.searchBoundaryKeys(i.cmp, key)
     397           1 :         // If eq is true, the found boundary key exactly equals the given key. A
     398           1 :         // span that starts at exactly [key] does not contain any keys strictly less
     399           1 :         // than [key], so back up one index.
     400           1 :         if eq {
     401           1 :                 j--
     402           1 :         }
     403             :         // If all boundaries are less than [key], or only the last boundary is
     404             :         // greater than the key, then we want the last span so we clamp the index to
     405             :         // the second to last boundary.
     406           1 :         return i.gatherKeysBackward(min(j, int(i.r.boundaryKeysCount)-2)), nil
     407             : }
     408             : 
     409             : // First moves the iterator to the first span.
     410           1 : func (i *keyspanIter) First() (*keyspan.Span, error) {
     411           1 :         return i.gatherKeysForward(0), nil
     412           1 : }
     413             : 
     414             : // Last moves the iterator to the last span.
     415           1 : func (i *keyspanIter) Last() (*keyspan.Span, error) {
     416           1 :         return i.gatherKeysBackward(int(i.r.boundaryKeysCount) - 2), nil
     417           1 : }
     418             : 
     419             : // Next moves the iterator to the next span.
     420           1 : func (i *keyspanIter) Next() (*keyspan.Span, error) {
     421           1 :         return i.gatherKeysForward(i.startBoundIndex + 1), nil
     422           1 : }
     423             : 
     424             : // Prev moves the iterator to the previous span.
     425           1 : func (i *keyspanIter) Prev() (*keyspan.Span, error) {
     426           1 :         return i.gatherKeysBackward(max(i.startBoundIndex-1, -1)), nil
     427           1 : }
     428             : 
     429             : // gatherKeysForward returns the first non-empty Span in the forward direction,
     430             : // starting with the span formed by using the boundary key at index
     431             : // [startBoundIndex] as the span's start boundary.
     432           1 : func (i *keyspanIter) gatherKeysForward(startBoundIndex int) *keyspan.Span {
     433           1 :         if invariants.Enabled && startBoundIndex < 0 {
     434           0 :                 panic(errors.AssertionFailedf("out of bounds: i.startBoundIndex=%d", startBoundIndex))
     435             :         }
     436           1 :         i.startBoundIndex = startBoundIndex
     437           1 :         if i.startBoundIndex >= int(i.r.boundaryKeysCount)-1 {
     438           1 :                 return nil
     439           1 :         }
     440           1 :         if !i.isNonemptySpan(i.startBoundIndex) {
     441           1 :                 if i.startBoundIndex == int(i.r.boundaryKeysCount)-2 {
     442           0 :                         // Corruption error
     443           0 :                         panic(base.CorruptionErrorf("keyspan block has empty span at end"))
     444             :                 }
     445           1 :                 i.startBoundIndex++
     446           1 :                 if !i.isNonemptySpan(i.startBoundIndex) {
     447           0 :                         panic(base.CorruptionErrorf("keyspan block has consecutive empty spans"))
     448             :                 }
     449             :         }
     450           1 :         return i.materializeSpan()
     451             : }
     452             : 
     453             : // gatherKeysBackward returns the first non-empty Span in the backward direction,
     454             : // starting with the span formed by using the boundary key at index
     455             : // [startBoundIndex] as the span's start boundary.
     456           1 : func (i *keyspanIter) gatherKeysBackward(startBoundIndex int) *keyspan.Span {
     457           1 :         i.startBoundIndex = startBoundIndex
     458           1 :         if i.startBoundIndex < 0 {
     459           1 :                 return nil
     460           1 :         }
     461           1 :         if invariants.Enabled && i.startBoundIndex >= int(i.r.boundaryKeysCount)-1 {
     462           0 :                 panic(errors.AssertionFailedf("out of bounds: i.startBoundIndex=%d, i.r.boundaryKeysCount=%d",
     463           0 :                         i.startBoundIndex, i.r.boundaryKeysCount))
     464             :         }
     465           1 :         if !i.isNonemptySpan(i.startBoundIndex) {
     466           1 :                 if i.startBoundIndex == 0 {
     467           0 :                         // Corruption error
     468           0 :                         panic(base.CorruptionErrorf("keyspan block has empty span at beginning"))
     469             :                 }
     470           1 :                 i.startBoundIndex--
     471           1 :                 if !i.isNonemptySpan(i.startBoundIndex) {
     472           0 :                         panic(base.CorruptionErrorf("keyspan block has consecutive empty spans"))
     473             :                 }
     474             :         }
     475           1 :         return i.materializeSpan()
     476             : }
     477             : 
     478             : // isNonemptySpan returns true if the span starting at i.startBoundIndex
     479             : // contains keys.
     480           1 : func (i *keyspanIter) isNonemptySpan(startBoundIndex int) bool {
     481           1 :         return i.r.boundaryKeyIndices.At(startBoundIndex) < i.r.boundaryKeyIndices.At(startBoundIndex+1)
     482           1 : }
     483             : 
     484             : // materializeSpan constructs the current span from i.startBoundIndex and
     485             : // i.{start,end}KeyIndex.
     486           1 : func (i *keyspanIter) materializeSpan() *keyspan.Span {
     487           1 :         // TODO(jackson): Apply i.transforms.
     488           1 : 
     489           1 :         i.span = keyspan.Span{
     490           1 :                 Start: i.r.boundaryKeys.At(i.startBoundIndex),
     491           1 :                 End:   i.r.boundaryKeys.At(i.startBoundIndex + 1),
     492           1 :                 Keys:  i.span.Keys[:0],
     493           1 :         }
     494           1 :         startIndex := i.r.boundaryKeyIndices.At(i.startBoundIndex)
     495           1 :         endIndex := i.r.boundaryKeyIndices.At(i.startBoundIndex + 1)
     496           1 :         if cap(i.span.Keys) < int(endIndex-startIndex) {
     497           1 :                 i.span.Keys = make([]keyspan.Key, 0, int(endIndex-startIndex))
     498           1 :         }
     499           1 :         for j := startIndex; j < endIndex; j++ {
     500           1 :                 i.span.Keys = append(i.span.Keys, keyspan.Key{
     501           1 :                         Trailer: base.InternalKeyTrailer(i.r.trailers.At(int(j))),
     502           1 :                         Suffix:  i.r.suffixes.At(int(j)),
     503           1 :                         Value:   i.r.values.At(int(j)),
     504           1 :                 })
     505           1 :         }
     506           1 :         return &i.span
     507             : }
     508             : 
     509             : // Close closes the iterator.
     510           1 : func (i *keyspanIter) Close() {
     511           1 :         *i = keyspanIter{}
     512           1 : }
     513             : 
     514             : // SetContext implements keyspan.FragmentIterator.
     515           0 : func (i *keyspanIter) SetContext(context.Context) {}
     516             : 
     517             : // WrapChildren implements keyspan.FragmentIterator.
     518           0 : func (i *keyspanIter) WrapChildren(keyspan.WrapFn) {}
     519             : 
     520             : // DebugTree is part of the FragmentIterator interface.
     521           0 : func (i *keyspanIter) DebugTree(tp treeprinter.Node) {
     522           0 :         tp.Childf("%T(%p)", i, i)
     523           0 : }
     524             : 
     525           1 : func checkKeyspanIter(obj interface{}) {
     526           1 :         i := obj.(*KeyspanIter)
     527           1 :         if p := i.handle.Get(); p != nil {
     528           0 :                 fmt.Fprintf(os.Stderr, "KeyspanIter.handle is not nil: %p\n", p)
     529           0 :                 os.Exit(1)
     530           0 :         }
     531             : }

Generated by: LCOV version 1.14