github.com/cockroachdb/pebble@v0.0.0-20231214172447-ab4952c5f87b/metamorphic/config.go (about)

     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  type opType int
    10  
    11  const (
    12  	batchAbort opType = iota
    13  	batchCommit
    14  	dbCheckpoint
    15  	dbClose
    16  	dbCompact
    17  	dbFlush
    18  	dbRatchetFormatMajorVersion
    19  	dbRestart
    20  	iterClose
    21  	iterFirst
    22  	iterLast
    23  	iterNext
    24  	iterNextWithLimit
    25  	iterNextPrefix
    26  	iterCanSingleDelete
    27  	iterPrev
    28  	iterPrevWithLimit
    29  	iterSeekGE
    30  	iterSeekGEWithLimit
    31  	iterSeekLT
    32  	iterSeekLTWithLimit
    33  	iterSeekPrefixGE
    34  	iterSetBounds
    35  	iterSetOptions
    36  	newBatch
    37  	newIndexedBatch
    38  	newIter
    39  	newIterUsingClone
    40  	newSnapshot
    41  	readerGet
    42  	replicate
    43  	snapshotClose
    44  	writerApply
    45  	writerDelete
    46  	writerDeleteRange
    47  	writerIngest
    48  	writerIngestAndExcise
    49  	writerMerge
    50  	writerRangeKeyDelete
    51  	writerRangeKeySet
    52  	writerRangeKeyUnset
    53  	writerSet
    54  	writerSingleDelete
    55  )
    56  
    57  func (o opType) isDelete() bool {
    58  	return o == writerDelete || o == writerDeleteRange || o == writerSingleDelete
    59  }
    60  
    61  type config struct {
    62  	// Weights for the operation mix to generate. ops[i] corresponds to the
    63  	// weight for opType(i).
    64  	ops []int
    65  
    66  	// newPrefix configures the probability that when generating a new user key,
    67  	// the generated key uses a new key prefix rather than an existing prefix
    68  	// with a suffix.
    69  	newPrefix float64
    70  	// writeSuffixDist defines the distribution of key suffixes during writing.
    71  	// It's a dynamic randvar to roughly emulate workloads with MVCC timestamps,
    72  	// skewing towards most recent timestamps.
    73  	writeSuffixDist randvar.Dynamic
    74  
    75  	// numInstances defines the number of pebble instances created for this
    76  	// metamorphic test run.
    77  	numInstances int
    78  
    79  	// TODO(peter): unimplemented
    80  	// keyDist        randvar.Dynamic
    81  	// keySizeDist    randvar.Static
    82  	// valueSizeDist  randvar.Static
    83  	// updateFrac     float64
    84  	// lowerBoundFrac float64
    85  	// upperBoundFrac float64
    86  }
    87  
    88  func (c config) withNewPrefixProbability(p float64) config {
    89  	c.newPrefix = p
    90  	return c
    91  }
    92  
    93  func (c config) withOpWeight(op opType, weight int) config {
    94  	c.ops[op] = weight
    95  	return c
    96  }
    97  
    98  var presetConfigs = []config{
    99  	defaultConfig(),
   100  	// Generate a configuration that helps exercise code paths dependent on many
   101  	// versions of keys with the same prefixes. The default configuration does
   102  	// not tend to generate many versions of the same key. Additionally, its
   103  	// relatively high weight for deletion write operations makes it less likely
   104  	// that we'll accumulate enough versions to exercise some code paths (eg,
   105  	// see #2921 which requires >16 SETs for versions of the same prefix to
   106  	// reside in a single block to exercise the code path).
   107  	//
   108  	// To encourage generation of many versions of the same keys, generate a new
   109  	// prefix only 4% of the time when generating a new key. The remaining 96%
   110  	// of new key generations will use an existing prefix. To keep the size of
   111  	// the database growing, we also reduce the probability of delete write
   112  	// operations significantly.
   113  	defaultConfig().
   114  		withNewPrefixProbability(0.04).
   115  		withOpWeight(writerDeleteRange, 1).
   116  		withOpWeight(writerDelete, 5).
   117  		withOpWeight(writerSingleDelete, 5).
   118  		withOpWeight(writerMerge, 0),
   119  }
   120  
   121  var multiInstancePresetConfig = multiInstanceConfig()
   122  
   123  func defaultConfig() config {
   124  	return config{
   125  		// dbClose is not in this list since it is deterministically generated once, at the end of the test.
   126  		ops: []int{
   127  			batchAbort:                  5,
   128  			batchCommit:                 5,
   129  			dbCheckpoint:                1,
   130  			dbCompact:                   1,
   131  			dbFlush:                     2,
   132  			dbRatchetFormatMajorVersion: 1,
   133  			dbRestart:                   2,
   134  			iterClose:                   5,
   135  			iterFirst:                   100,
   136  			iterLast:                    100,
   137  			iterNext:                    100,
   138  			iterNextWithLimit:           20,
   139  			iterNextPrefix:              20,
   140  			iterCanSingleDelete:         20,
   141  			iterPrev:                    100,
   142  			iterPrevWithLimit:           20,
   143  			iterSeekGE:                  100,
   144  			iterSeekGEWithLimit:         20,
   145  			iterSeekLT:                  100,
   146  			iterSeekLTWithLimit:         20,
   147  			iterSeekPrefixGE:            100,
   148  			iterSetBounds:               100,
   149  			iterSetOptions:              10,
   150  			newBatch:                    5,
   151  			newIndexedBatch:             5,
   152  			newIter:                     10,
   153  			newIterUsingClone:           5,
   154  			newSnapshot:                 10,
   155  			readerGet:                   100,
   156  			replicate:                   0,
   157  			snapshotClose:               10,
   158  			writerApply:                 10,
   159  			writerDelete:                100,
   160  			writerDeleteRange:           50,
   161  			writerIngest:                100,
   162  			writerIngestAndExcise:       0, // TODO(bilal): Enable this.
   163  			writerMerge:                 100,
   164  			writerRangeKeySet:           10,
   165  			writerRangeKeyUnset:         10,
   166  			writerRangeKeyDelete:        5,
   167  			writerSet:                   100,
   168  			writerSingleDelete:          50,
   169  		},
   170  		// Use a new prefix 75% of the time (and 25% of the time use an existing
   171  		// prefix with an alternative suffix).
   172  		newPrefix: 0.75,
   173  		// Use a skewed distribution of suffixes to mimic MVCC timestamps. The
   174  		// range will be widened whenever a suffix is found to already be in use
   175  		// for a particular prefix.
   176  		writeSuffixDist: mustDynamic(randvar.NewSkewedLatest(0, 1, 0.99)),
   177  	}
   178  }
   179  
   180  func multiInstanceConfig() config {
   181  	cfg := defaultConfig()
   182  	cfg.ops[replicate] = 5
   183  	cfg.ops[writerIngestAndExcise] = 50
   184  	// Single deletes and merges are disabled in multi-instance mode, as
   185  	// replicateOp doesn't support them.
   186  	cfg.ops[writerSingleDelete] = 0
   187  	cfg.ops[writerMerge] = 0
   188  	return cfg
   189  }
   190  
   191  func mustDynamic(dyn randvar.Dynamic, err error) randvar.Dynamic {
   192  	if err != nil {
   193  		panic(err)
   194  	}
   195  	return dyn
   196  }