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 }