LCOV - code coverage report
Current view: top level - pebble/sstable/sstable - block_property_test_utils.go (source / functions) Coverage Total Hit
Test: 2025-10-12 08:18Z a5edd166 - meta test only.lcov Lines: 64.4 % 73 47
Test Date: 2025-10-12 08:21:34 Functions: - 0 0

            Line data    Source code
       1              : // Copyright 2022 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 sstable
       6              : 
       7              : import (
       8              :         "fmt"
       9              :         "math"
      10              :         "strconv"
      11              : 
      12              :         "github.com/cockroachdb/pebble/internal/testkeys"
      13              : )
      14              : 
      15              : // Code in this file contains utils for testing. It implements interval block
      16              : // property collectors and filters on the suffixes of keys in the format used
      17              : // by the testkeys package (eg, 'key@5').
      18              : 
      19              : const testKeysBlockPropertyName = `pebble.internal.testkeys.suffixes`
      20              : 
      21              : // NewTestKeysBlockPropertyCollector constructs a sstable property collector
      22              : // over testkey suffixes.
      23            1 : func NewTestKeysBlockPropertyCollector() BlockPropertyCollector {
      24            1 :         return NewBlockIntervalCollector(
      25            1 :                 testKeysBlockPropertyName,
      26            1 :                 &testKeysSuffixIntervalMapper{},
      27            1 :                 nil)
      28            1 : }
      29              : 
      30              : // NewTestKeysBlockPropertyFilter constructs a new block-property filter that excludes
      31              : // blocks containing exclusively suffixed keys where all the suffixes fall
      32              : // outside of the range [filterMin, filterMax).
      33              : //
      34              : // The filter only filters based on data derived from the key. The iteration
      35              : // results of this block property filter are deterministic for unsuffixed keys
      36              : // and keys with suffixes within the range [filterMin, filterMax). For keys with
      37              : // suffixes outside the range, iteration is nondeterministic.
      38            1 : func NewTestKeysBlockPropertyFilter(filterMin, filterMax uint64) *BlockIntervalFilter {
      39            1 :         return NewBlockIntervalFilter(testKeysBlockPropertyName, filterMin, filterMax, testKeysBlockIntervalSyntheticReplacer{})
      40            1 : }
      41              : 
      42              : var _ BlockIntervalSuffixReplacer = testKeysBlockIntervalSyntheticReplacer{}
      43              : 
      44              : type testKeysBlockIntervalSyntheticReplacer struct{}
      45              : 
      46              : // ApplySuffixReplacement implements BlockIntervalSyntheticReplacer.
      47              : func (sr testKeysBlockIntervalSyntheticReplacer) ApplySuffixReplacement(
      48              :         interval BlockInterval, newSuffix []byte,
      49            1 : ) (BlockInterval, error) {
      50            1 :         decoded, err := testkeys.ParseSuffix(newSuffix)
      51            1 :         if err != nil {
      52            0 :                 return BlockInterval{}, err
      53            0 :         }
      54              :         // The testKeysSuffixIntervalMapper below maps keys with no suffix to
      55              :         // [0, MaxUint64); ignore that.
      56            1 :         if interval.Upper != math.MaxUint64 && uint64(decoded) < interval.Upper {
      57            0 :                 panic(fmt.Sprintf("the synthetic suffix %d is less than the property upper bound %d", decoded, interval.Upper))
      58              :         }
      59            1 :         return BlockInterval{uint64(decoded), uint64(decoded) + 1}, nil
      60              : }
      61              : 
      62              : // NewTestKeysMaskingFilter constructs a TestKeysMaskingFilter that implements
      63              : // pebble.BlockPropertyFilterMask for efficient range-key masking using the
      64              : // testkeys block property filter. The masking filter wraps a block interval
      65              : // filter, and modifies the configured interval when Pebble requests it.
      66            1 : func NewTestKeysMaskingFilter() TestKeysMaskingFilter {
      67            1 :         return TestKeysMaskingFilter{BlockIntervalFilter: NewTestKeysBlockPropertyFilter(0, math.MaxUint64)}
      68            1 : }
      69              : 
      70              : // TestKeysMaskingFilter implements BlockPropertyFilterMask and may be used to mask
      71              : // point keys with the testkeys-style suffixes (eg, @4) that are masked by range
      72              : // keys with testkeys-style suffixes.
      73              : type TestKeysMaskingFilter struct {
      74              :         *BlockIntervalFilter
      75              : }
      76              : 
      77              : // SetSuffix implements pebble.BlockPropertyFilterMask.
      78            1 : func (f TestKeysMaskingFilter) SetSuffix(suffix []byte) error {
      79            1 :         ts, err := testkeys.ParseSuffix(suffix)
      80            1 :         if err != nil {
      81            0 :                 return err
      82            0 :         }
      83            1 :         f.BlockIntervalFilter.SetInterval(uint64(ts), math.MaxUint64)
      84            1 :         return nil
      85              : }
      86              : 
      87              : // Intersects implements the BlockPropertyFilter interface.
      88            1 : func (f TestKeysMaskingFilter) Intersects(prop []byte) (bool, error) {
      89            1 :         return f.BlockIntervalFilter.Intersects(prop)
      90            1 : }
      91              : 
      92              : // SyntheticSuffixIntersects implements the BlockPropertyFilter interface.
      93            1 : func (f TestKeysMaskingFilter) SyntheticSuffixIntersects(prop []byte, suffix []byte) (bool, error) {
      94            1 :         return f.BlockIntervalFilter.SyntheticSuffixIntersects(prop, suffix)
      95            1 : }
      96              : 
      97              : // testKeysSuffixIntervalMapper maps keys to intervals according to the
      98              : // timestamps in MVCC-like suffixes for keys (e.g. "foo@123" -> 123).
      99              : type testKeysSuffixIntervalMapper struct {
     100              :         ignorePoints    bool
     101              :         ignoreRangeKeys bool
     102              : }
     103              : 
     104              : var _ IntervalMapper = &testKeysSuffixIntervalMapper{}
     105              : 
     106              : // MapPointKey is part of the IntervalMapper interface.
     107              : func (c *testKeysSuffixIntervalMapper) MapPointKey(
     108              :         key InternalKey, value []byte,
     109            1 : ) (BlockInterval, error) {
     110            1 :         if c.ignorePoints {
     111            0 :                 return BlockInterval{}, nil
     112            0 :         }
     113            1 :         n := testkeys.Comparer.Split(key.UserKey)
     114            1 :         return testKeysSuffixToInterval(key.UserKey[n:]), nil
     115              : }
     116              : 
     117              : // MapRangeKeys is part of the IntervalMapper interface.
     118            1 : func (c *testKeysSuffixIntervalMapper) MapRangeKeys(span Span) (BlockInterval, error) {
     119            1 :         if c.ignoreRangeKeys {
     120            0 :                 return BlockInterval{}, nil
     121            0 :         }
     122            1 :         var result BlockInterval
     123            1 :         for _, k := range span.Keys {
     124            1 :                 if len(k.Suffix) > 0 {
     125            1 :                         result.UnionWith(testKeysSuffixToInterval(k.Suffix))
     126            1 :                 }
     127              :         }
     128            1 :         return result, nil
     129              : }
     130              : 
     131            1 : func testKeysSuffixToInterval(suffix []byte) BlockInterval {
     132            1 :         if len(suffix) == 0 {
     133            1 :                 return BlockInterval{0, math.MaxUint64}
     134            1 :         }
     135            1 :         n, err := testkeys.ParseSuffix(suffix)
     136            1 :         if err != nil {
     137            0 :                 panic(err)
     138              :         }
     139            1 :         return BlockInterval{uint64(n), uint64(n) + 1}
     140              : }
     141              : 
     142              : type MaxTestKeysSuffixProperty struct{}
     143              : 
     144              : // Name is part of the MaxTestKeysSuffixProperty interface.
     145            0 : func (testprop MaxTestKeysSuffixProperty) Name() string {
     146            0 :         return `pebble.internal.testkeys.suffixes`
     147            0 : }
     148              : 
     149              : // Extract is part of the MaxTestKeysSuffixProperty interface used to extract the
     150              : // latest suffix from the block property.
     151              : func (testprop MaxTestKeysSuffixProperty) Extract(
     152              :         dst []byte, encodedProperty []byte,
     153            0 : ) (suffix []byte, ok bool, err error) {
     154            0 :         if len(encodedProperty) <= 1 {
     155            0 :                 return nil, false, nil
     156            0 :         }
     157              :         // First byte is shortID, skip it and decode interval from remainder.
     158            0 :         interval, err := DecodeBlockInterval(encodedProperty[1:])
     159            0 :         if err != nil {
     160            0 :                 return nil, false, err
     161            0 :         } else if interval.IsEmpty() {
     162            0 :                 return nil, false, nil
     163            0 :         }
     164            0 :         dst = append(dst, '@')
     165            0 :         dst = strconv.AppendUint(dst, (interval.Upper - 1), 10)
     166            0 :         return dst, true, nil
     167              : }
        

Generated by: LCOV version 2.0-1