LCOV - code coverage report
Current view: top level - pebble/metamorphic - config.go (source / functions) Hit Total Coverage
Test: 2024-03-08 08:15Z 1f7e8ee4 - tests + meta.lcov Lines: 196 197 99.5 %
Date: 2024-03-08 08:17:01 Functions: 0 0 -

          Line data    Source code
       1             : // Copyright 2019 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 metamorphic
       6             : 
       7             : import "github.com/cockroachdb/pebble/internal/randvar"
       8             : 
       9             : // OpType is an enum of possible operation types.
      10             : type OpType int
      11             : 
      12             : // These constants define the set of possible operation types performed by the
      13             : // metamorphic test.
      14             : const (
      15             :         OpBatchAbort OpType = iota
      16             :         OpBatchCommit
      17             :         OpDBCheckpoint
      18             :         OpDBClose
      19             :         OpDBCompact
      20             :         OpDBFlush
      21             :         OpDBRatchetFormatMajorVersion
      22             :         OpDBRestart
      23             :         OpIterClose
      24             :         OpIterFirst
      25             :         OpIterLast
      26             :         OpIterNext
      27             :         OpIterNextWithLimit
      28             :         OpIterNextPrefix
      29             :         OpIterCanSingleDelete
      30             :         OpIterPrev
      31             :         OpIterPrevWithLimit
      32             :         OpIterSeekGE
      33             :         OpIterSeekGEWithLimit
      34             :         OpIterSeekLT
      35             :         OpIterSeekLTWithLimit
      36             :         OpIterSeekPrefixGE
      37             :         OpIterSetBounds
      38             :         OpIterSetOptions
      39             :         OpNewBatch
      40             :         OpNewIndexedBatch
      41             :         OpNewIter
      42             :         OpNewIterUsingClone
      43             :         OpNewSnapshot
      44             :         OpNewExternalObj
      45             :         OpReaderGet
      46             :         OpReplicate
      47             :         OpSnapshotClose
      48             :         OpWriterApply
      49             :         OpWriterDelete
      50             :         OpWriterDeleteRange
      51             :         OpWriterIngest
      52             :         OpWriterIngestAndExcise
      53             :         OpWriterIngestExternalFiles
      54             :         OpWriterLogData
      55             :         OpWriterMerge
      56             :         OpWriterRangeKeyDelete
      57             :         OpWriterRangeKeySet
      58             :         OpWriterRangeKeyUnset
      59             :         OpWriterSet
      60             :         OpWriterSingleDelete
      61             :         NumOpTypes
      62             : )
      63             : 
      64           1 : func (o OpType) isDelete() bool {
      65           1 :         return o == OpWriterDelete || o == OpWriterDeleteRange || o == OpWriterSingleDelete
      66           1 : }
      67             : 
      68             : // OpConfig describes the distribution of operations and their attributes.
      69             : type OpConfig struct {
      70             :         // Weights for the operation mix to generate. ops[i] corresponds to the
      71             :         // weight for opType(i).
      72             :         ops [NumOpTypes]int
      73             : 
      74             :         // newPrefix configures the probability that when generating a new user key,
      75             :         // the generated key uses a new key prefix rather than an existing prefix
      76             :         // with a suffix.
      77             :         newPrefix float64
      78             :         // writeSuffixDist defines the distribution of key suffixes during writing.
      79             :         // It's a dynamic randvar to roughly emulate workloads with MVCC timestamps,
      80             :         // skewing towards most recent timestamps.
      81             :         writeSuffixDist randvar.Dynamic
      82             : 
      83             :         // numInstances defines the number of pebble instances created for this
      84             :         // metamorphic test run.
      85             :         numInstances int
      86             : 
      87             :         // TODO(peter): unimplemented
      88             :         // keyDist        randvar.Dynamic
      89             :         // keySizeDist    randvar.Static
      90             :         // valueSizeDist  randvar.Static
      91             :         // updateFrac     float64
      92             :         // lowerBoundFrac float64
      93             :         // upperBoundFrac float64
      94             : }
      95             : 
      96             : // WithNewPrefixProbability returns a modified op configuration with the
      97             : // probability of generating a new key prefix set to the provided value in
      98             : // [0,1.0].
      99           2 : func (c OpConfig) WithNewPrefixProbability(p float64) OpConfig {
     100           2 :         c.newPrefix = p
     101           2 :         return c
     102           2 : }
     103             : 
     104             : // WithOpWeight returns a modified op configuration with the weight of the
     105             : // provided operation type overidden.
     106           2 : func (c OpConfig) WithOpWeight(op OpType, weight int) OpConfig {
     107           2 :         c.ops[op] = weight
     108           2 :         return c
     109           2 : }
     110             : 
     111             : var presetConfigs = []OpConfig{
     112             :         DefaultOpConfig(),
     113             :         // Generate a configuration that helps exercise code paths dependent on many
     114             :         // versions of keys with the same prefixes. The default configuration does
     115             :         // not tend to generate many versions of the same key. Additionally, its
     116             :         // relatively high weight for deletion write operations makes it less likely
     117             :         // that we'll accumulate enough versions to exercise some code paths (eg,
     118             :         // see #2921 which requires >16 SETs for versions of the same prefix to
     119             :         // reside in a single block to exercise the code path).
     120             :         //
     121             :         // To encourage generation of many versions of the same keys, generate a new
     122             :         // prefix only 4% of the time when generating a new key. The remaining 96%
     123             :         // of new key generations will use an existing prefix. To keep the size of
     124             :         // the database growing, we also reduce the probability of delete write
     125             :         // operations significantly.
     126             :         DefaultOpConfig().
     127             :                 WithNewPrefixProbability(0.04).
     128             :                 WithOpWeight(OpWriterDeleteRange, 1).
     129             :                 WithOpWeight(OpWriterDelete, 5).
     130             :                 WithOpWeight(OpWriterSingleDelete, 5).
     131             :                 WithOpWeight(OpWriterMerge, 0),
     132             : }
     133             : 
     134             : var multiInstancePresetConfig = multiInstanceConfig()
     135             : 
     136             : // DefaultOpConfig returns the default distribution of operations.
     137           2 : func DefaultOpConfig() OpConfig {
     138           2 :         return OpConfig{
     139           2 :                 // dbClose is not in this list since it is deterministically generated once, at the end of the test.
     140           2 :                 ops: [NumOpTypes]int{
     141           2 :                         OpBatchAbort:                  5,
     142           2 :                         OpBatchCommit:                 5,
     143           2 :                         OpDBCheckpoint:                1,
     144           2 :                         OpDBCompact:                   1,
     145           2 :                         OpDBFlush:                     2,
     146           2 :                         OpDBRatchetFormatMajorVersion: 1,
     147           2 :                         OpDBRestart:                   2,
     148           2 :                         OpIterClose:                   5,
     149           2 :                         OpIterFirst:                   100,
     150           2 :                         OpIterLast:                    100,
     151           2 :                         OpIterNext:                    100,
     152           2 :                         OpIterNextWithLimit:           20,
     153           2 :                         OpIterNextPrefix:              20,
     154           2 :                         OpIterCanSingleDelete:         20,
     155           2 :                         OpIterPrev:                    100,
     156           2 :                         OpIterPrevWithLimit:           20,
     157           2 :                         OpIterSeekGE:                  100,
     158           2 :                         OpIterSeekGEWithLimit:         20,
     159           2 :                         OpIterSeekLT:                  100,
     160           2 :                         OpIterSeekLTWithLimit:         20,
     161           2 :                         OpIterSeekPrefixGE:            100,
     162           2 :                         OpIterSetBounds:               100,
     163           2 :                         OpIterSetOptions:              10,
     164           2 :                         OpNewBatch:                    5,
     165           2 :                         OpNewIndexedBatch:             5,
     166           2 :                         OpNewIter:                     10,
     167           2 :                         OpNewIterUsingClone:           5,
     168           2 :                         OpNewSnapshot:                 10,
     169           2 :                         OpReaderGet:                   100,
     170           2 :                         OpReplicate:                   0,
     171           2 :                         OpSnapshotClose:               10,
     172           2 :                         OpWriterApply:                 10,
     173           2 :                         OpWriterDelete:                100,
     174           2 :                         OpWriterDeleteRange:           50,
     175           2 :                         OpWriterIngest:                100,
     176           2 :                         OpWriterIngestAndExcise:       0, // TODO(bilal): Enable this.
     177           2 :                         OpWriterLogData:               10,
     178           2 :                         OpWriterMerge:                 100,
     179           2 :                         OpWriterRangeKeySet:           10,
     180           2 :                         OpWriterRangeKeyUnset:         10,
     181           2 :                         OpWriterRangeKeyDelete:        5,
     182           2 :                         OpWriterSet:                   100,
     183           2 :                         OpWriterSingleDelete:          50,
     184           2 :                         OpNewExternalObj:              5,
     185           2 :                         OpWriterIngestExternalFiles:   100,
     186           2 :                 },
     187           2 :                 // Use a new prefix 75% of the time (and 25% of the time use an existing
     188           2 :                 // prefix with an alternative suffix).
     189           2 :                 newPrefix: 0.75,
     190           2 :                 // Use a skewed distribution of suffixes to mimic MVCC timestamps. The
     191           2 :                 // range will be widened whenever a suffix is found to already be in use
     192           2 :                 // for a particular prefix.
     193           2 :                 writeSuffixDist: mustDynamic(randvar.NewSkewedLatest(0, 1, 0.99)),
     194           2 :         }
     195           2 : }
     196             : 
     197             : // ReadOpConfig builds an OpConfig that performs only read operations.
     198           1 : func ReadOpConfig() OpConfig {
     199           1 :         return OpConfig{
     200           1 :                 // dbClose is not in this list since it is deterministically generated once, at the end of the test.
     201           1 :                 ops: [NumOpTypes]int{
     202           1 :                         OpBatchAbort:                  0,
     203           1 :                         OpBatchCommit:                 0,
     204           1 :                         OpDBCheckpoint:                0,
     205           1 :                         OpDBCompact:                   0,
     206           1 :                         OpDBFlush:                     0,
     207           1 :                         OpDBRatchetFormatMajorVersion: 0,
     208           1 :                         OpDBRestart:                   0,
     209           1 :                         OpIterClose:                   5,
     210           1 :                         OpIterFirst:                   100,
     211           1 :                         OpIterLast:                    100,
     212           1 :                         OpIterNext:                    100,
     213           1 :                         OpIterNextWithLimit:           20,
     214           1 :                         OpIterNextPrefix:              20,
     215           1 :                         OpIterPrev:                    100,
     216           1 :                         OpIterPrevWithLimit:           20,
     217           1 :                         OpIterSeekGE:                  100,
     218           1 :                         OpIterSeekGEWithLimit:         20,
     219           1 :                         OpIterSeekLT:                  100,
     220           1 :                         OpIterSeekLTWithLimit:         20,
     221           1 :                         OpIterSeekPrefixGE:            100,
     222           1 :                         OpIterSetBounds:               100,
     223           1 :                         OpIterSetOptions:              10,
     224           1 :                         OpNewBatch:                    0,
     225           1 :                         OpNewIndexedBatch:             0,
     226           1 :                         OpNewIter:                     10,
     227           1 :                         OpNewIterUsingClone:           5,
     228           1 :                         OpNewSnapshot:                 10,
     229           1 :                         OpReaderGet:                   100,
     230           1 :                         OpSnapshotClose:               10,
     231           1 :                         OpWriterApply:                 0,
     232           1 :                         OpWriterDelete:                0,
     233           1 :                         OpWriterDeleteRange:           0,
     234           1 :                         OpWriterIngest:                0,
     235           1 :                         OpWriterLogData:               0,
     236           1 :                         OpWriterMerge:                 0,
     237           1 :                         OpWriterRangeKeySet:           0,
     238           1 :                         OpWriterRangeKeyUnset:         0,
     239           1 :                         OpWriterRangeKeyDelete:        0,
     240           1 :                         OpWriterSet:                   0,
     241           1 :                         OpWriterSingleDelete:          0,
     242           1 :                 },
     243           1 :                 // Use a new prefix 75% of the time (and 25% of the time use an existing
     244           1 :                 // prefix with an alternative suffix).
     245           1 :                 newPrefix: 0.75,
     246           1 :                 // Use a skewed distribution of suffixes to mimic MVCC timestamps. The
     247           1 :                 // range will be widened whenever a suffix is found to already be in use
     248           1 :                 // for a particular prefix.
     249           1 :                 writeSuffixDist: mustDynamic(randvar.NewSkewedLatest(0, 1, 0.99)),
     250           1 :         }
     251           1 : }
     252             : 
     253             : // WriteOpConfig builds an OpConfig suitable for generating a random test
     254             : // database. It generates Writer operations and some meta database operations
     255             : // like flushes and manual compactions, but it does not generate any reads.
     256           1 : func WriteOpConfig() OpConfig {
     257           1 :         return OpConfig{
     258           1 :                 // dbClose is not in this list since it is deterministically generated once, at the end of the test.
     259           1 :                 ops: [NumOpTypes]int{
     260           1 :                         OpBatchAbort:                  0,
     261           1 :                         OpBatchCommit:                 5,
     262           1 :                         OpDBCheckpoint:                0,
     263           1 :                         OpDBCompact:                   1,
     264           1 :                         OpDBFlush:                     2,
     265           1 :                         OpDBRatchetFormatMajorVersion: 1,
     266           1 :                         OpDBRestart:                   2,
     267           1 :                         OpIterClose:                   0,
     268           1 :                         OpIterFirst:                   0,
     269           1 :                         OpIterLast:                    0,
     270           1 :                         OpIterNext:                    0,
     271           1 :                         OpIterNextWithLimit:           0,
     272           1 :                         OpIterNextPrefix:              0,
     273           1 :                         OpIterPrev:                    0,
     274           1 :                         OpIterPrevWithLimit:           0,
     275           1 :                         OpIterSeekGE:                  0,
     276           1 :                         OpIterSeekGEWithLimit:         0,
     277           1 :                         OpIterSeekLT:                  0,
     278           1 :                         OpIterSeekLTWithLimit:         0,
     279           1 :                         OpIterSeekPrefixGE:            0,
     280           1 :                         OpIterSetBounds:               0,
     281           1 :                         OpIterSetOptions:              0,
     282           1 :                         OpNewBatch:                    10,
     283           1 :                         OpNewIndexedBatch:             0,
     284           1 :                         OpNewIter:                     0,
     285           1 :                         OpNewIterUsingClone:           0,
     286           1 :                         OpNewSnapshot:                 10,
     287           1 :                         OpReaderGet:                   0,
     288           1 :                         OpSnapshotClose:               10,
     289           1 :                         OpWriterApply:                 10,
     290           1 :                         OpWriterDelete:                100,
     291           1 :                         OpWriterDeleteRange:           20,
     292           1 :                         OpWriterIngest:                100,
     293           1 :                         OpWriterLogData:               10,
     294           1 :                         OpWriterMerge:                 100,
     295           1 :                         OpWriterRangeKeySet:           10,
     296           1 :                         OpWriterRangeKeyUnset:         10,
     297           1 :                         OpWriterRangeKeyDelete:        5,
     298           1 :                         OpWriterSet:                   100,
     299           1 :                         OpWriterSingleDelete:          50,
     300           1 :                 },
     301           1 :                 // Use a new prefix 75% of the time (and 25% of the time use an existing
     302           1 :                 // prefix with an alternative suffix).
     303           1 :                 newPrefix: 0.75,
     304           1 :                 // Use a skewed distribution of suffixes to mimic MVCC timestamps. The
     305           1 :                 // range will be widened whenever a suffix is found to already be in use
     306           1 :                 // for a particular prefix.
     307           1 :                 writeSuffixDist: mustDynamic(randvar.NewSkewedLatest(0, 1, 0.99)),
     308           1 :         }
     309           1 : }
     310             : 
     311           2 : func multiInstanceConfig() OpConfig {
     312           2 :         cfg := DefaultOpConfig()
     313           2 :         cfg.ops[OpReplicate] = 5
     314           2 :         cfg.ops[OpWriterIngestAndExcise] = 50
     315           2 :         // Single deletes and merges are disabled in multi-instance mode, as
     316           2 :         // replicateOp and ingestAndExciseOp don't support them.
     317           2 :         cfg.ops[OpWriterSingleDelete] = 0
     318           2 :         cfg.ops[OpWriterMerge] = 0
     319           2 : 
     320           2 :         // TODO(radu): external file ingest doesn't yet work with OpReplicate ("cannot
     321           2 :         // use skip-shared iteration due to non-shareable files in lower levels").
     322           2 :         cfg.ops[OpNewExternalObj] = 0
     323           2 :         cfg.ops[OpWriterIngestExternalFiles] = 0
     324           2 :         return cfg
     325           2 : }
     326             : 
     327           2 : func mustDynamic(dyn randvar.Dynamic, err error) randvar.Dynamic {
     328           2 :         if err != nil {
     329           0 :                 panic(err)
     330             :         }
     331           2 :         return dyn
     332             : }

Generated by: LCOV version 1.14