github.com/zuoyebang/bitalostable@v1.0.1-0.20240229032404-e3b99a834294/internal/metamorphic/generator.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 (
     8  	"bytes"
     9  	"fmt"
    10  
    11  	"github.com/zuoyebang/bitalostable"
    12  	"github.com/zuoyebang/bitalostable/internal/randvar"
    13  	"github.com/zuoyebang/bitalostable/internal/testkeys"
    14  	"golang.org/x/exp/rand"
    15  )
    16  
    17  type iterOpts struct {
    18  	lower    []byte
    19  	upper    []byte
    20  	keyTypes uint32 // bitalostable.IterKeyType
    21  	// maskSuffix may be set if keyTypes is IterKeyTypePointsAndRanges to
    22  	// configure IterOptions.RangeKeyMasking.Suffix.
    23  	maskSuffix []byte
    24  
    25  	// If filterMax is >0, this iterator will filter out any keys that have
    26  	// suffixes that don't fall within the range [filterMin,filterMax).
    27  	// Additionally, the iterator will be constructed with a block-property
    28  	// filter that filters out blocks accordingly. Not all OPTIONS hook up the
    29  	// corresponding block property collector, so block-filtering may still be
    30  	// effectively disabled in some runs. The iterator operations themselves
    31  	// however will always skip past any points that should be filtered to
    32  	// ensure determinism.
    33  	filterMin uint64
    34  	filterMax uint64
    35  
    36  	// NB: If adding or removing fields, ensure IsZero is in sync.
    37  }
    38  
    39  func (o iterOpts) IsZero() bool {
    40  	return o.lower == nil && o.upper == nil && o.keyTypes == 0 &&
    41  		o.maskSuffix == nil && o.filterMin == 0 && o.filterMax == 0
    42  }
    43  
    44  type generator struct {
    45  	cfg config
    46  	rng *rand.Rand
    47  
    48  	init *initOp
    49  	ops  []op
    50  
    51  	// keyManager tracks the state of keys a operation generation time.
    52  	keyManager *keyManager
    53  	// Unordered sets of object IDs for live objects. Used to randomly select on
    54  	// object when generating an operation. There are 4 concrete objects: the DB
    55  	// (of which there is exactly 1), batches, iterators, and snapshots.
    56  	//
    57  	// liveBatches contains the live indexed and write-only batches.
    58  	liveBatches objIDSlice
    59  	// liveIters contains the live iterators.
    60  	liveIters     objIDSlice
    61  	itersLastOpts map[objID]iterOpts
    62  	// liveReaders contains the DB, and any live indexed batches and snapshots. The DB is always
    63  	// at index 0.
    64  	liveReaders objIDSlice
    65  	// liveSnapshots contains the live snapshots.
    66  	liveSnapshots objIDSlice
    67  	// liveWriters contains the DB, and any live batches. The DB is always at index 0.
    68  	liveWriters objIDSlice
    69  
    70  	// Maps used to find associated objects during generation. These maps are not
    71  	// needed during test execution.
    72  	//
    73  	// batchID -> batch iters: used to keep track of the open iterators on an
    74  	// indexed batch. The iter set value will also be indexed by the readers map.
    75  	batches map[objID]objIDSet
    76  	// iterID -> reader iters: used to keep track of all of the open
    77  	// iterators. The iter set value will also be indexed by either the batches
    78  	// or snapshots maps.
    79  	iters map[objID]objIDSet
    80  	// readerID -> reader iters: used to keep track of the open iterators on a
    81  	// reader. The iter set value will also be indexed by either the batches or
    82  	// snapshots maps. This map is the union of batches and snapshots maps.
    83  	readers map[objID]objIDSet
    84  	// snapshotID -> snapshot iters: used to keep track of the open iterators on
    85  	// a snapshot. The iter set value will also be indexed by the readers map.
    86  	snapshots map[objID]objIDSet
    87  	// iterSequenceNumber is the metaTimestamp at which the iter was created.
    88  	iterCreationTimestamp map[objID]int
    89  	// iterReaderID is a map from an iterID to a readerID.
    90  	iterReaderID map[objID]objID
    91  }
    92  
    93  func newGenerator(rng *rand.Rand, cfg config, km *keyManager) *generator {
    94  	g := &generator{
    95  		cfg:                   cfg,
    96  		rng:                   rng,
    97  		init:                  &initOp{},
    98  		keyManager:            km,
    99  		liveReaders:           objIDSlice{makeObjID(dbTag, 0)},
   100  		liveWriters:           objIDSlice{makeObjID(dbTag, 0)},
   101  		batches:               make(map[objID]objIDSet),
   102  		iters:                 make(map[objID]objIDSet),
   103  		readers:               make(map[objID]objIDSet),
   104  		snapshots:             make(map[objID]objIDSet),
   105  		itersLastOpts:         make(map[objID]iterOpts),
   106  		iterCreationTimestamp: make(map[objID]int),
   107  		iterReaderID:          make(map[objID]objID),
   108  	}
   109  	// Note that the initOp fields are populated during generation.
   110  	g.ops = append(g.ops, g.init)
   111  	return g
   112  }
   113  
   114  func generate(rng *rand.Rand, count uint64, cfg config, km *keyManager) []op {
   115  	g := newGenerator(rng, cfg, km)
   116  
   117  	generators := []func(){
   118  		batchAbort:           g.batchAbort,
   119  		batchCommit:          g.batchCommit,
   120  		dbCheckpoint:         g.dbCheckpoint,
   121  		dbCompact:            g.dbCompact,
   122  		dbFlush:              g.dbFlush,
   123  		dbRestart:            g.dbRestart,
   124  		iterClose:            g.randIter(g.iterClose),
   125  		iterFirst:            g.randIter(g.iterFirst),
   126  		iterLast:             g.randIter(g.iterLast),
   127  		iterNext:             g.randIter(g.iterNext),
   128  		iterNextWithLimit:    g.randIter(g.iterNextWithLimit),
   129  		iterPrev:             g.randIter(g.iterPrev),
   130  		iterPrevWithLimit:    g.randIter(g.iterPrevWithLimit),
   131  		iterSeekGE:           g.randIter(g.iterSeekGE),
   132  		iterSeekGEWithLimit:  g.randIter(g.iterSeekGEWithLimit),
   133  		iterSeekLT:           g.randIter(g.iterSeekLT),
   134  		iterSeekLTWithLimit:  g.randIter(g.iterSeekLTWithLimit),
   135  		iterSeekPrefixGE:     g.randIter(g.iterSeekPrefixGE),
   136  		iterSetBounds:        g.randIter(g.iterSetBounds),
   137  		iterSetOptions:       g.randIter(g.iterSetOptions),
   138  		newBatch:             g.newBatch,
   139  		newIndexedBatch:      g.newIndexedBatch,
   140  		newIter:              g.newIter,
   141  		newIterUsingClone:    g.newIterUsingClone,
   142  		newSnapshot:          g.newSnapshot,
   143  		readerGet:            g.readerGet,
   144  		snapshotClose:        g.snapshotClose,
   145  		writerApply:          g.writerApply,
   146  		writerDelete:         g.writerDelete,
   147  		writerDeleteRange:    g.writerDeleteRange,
   148  		writerIngest:         g.writerIngest,
   149  		writerMerge:          g.writerMerge,
   150  		writerRangeKeyDelete: g.writerRangeKeyDelete,
   151  		writerRangeKeySet:    g.writerRangeKeySet,
   152  		writerRangeKeyUnset:  g.writerRangeKeyUnset,
   153  		writerSet:            g.writerSet,
   154  		writerSingleDelete:   g.writerSingleDelete,
   155  	}
   156  
   157  	// TPCC-style deck of cards randomization. Every time the end of the deck is
   158  	// reached, we shuffle the deck.
   159  	deck := randvar.NewDeck(g.rng, cfg.ops...)
   160  	for i := uint64(0); i < count; i++ {
   161  		generators[deck.Int()]()
   162  	}
   163  
   164  	g.dbClose()
   165  	return g.ops
   166  }
   167  
   168  func (g *generator) add(op op) {
   169  	g.ops = append(g.ops, op)
   170  	g.keyManager.update(op)
   171  }
   172  
   173  // randKeyToWrite returns a key for any write other than SingleDelete.
   174  //
   175  // TODO(peter): make the size and distribution of keys configurable. See
   176  // keyDist and keySizeDist in config.go.
   177  func (g *generator) randKeyToWrite(newKey float64) []byte {
   178  	return g.randKeyHelper(g.keyManager.eligibleWriteKeys(), newKey)
   179  }
   180  
   181  // prefixKeyRange generates a [start, end) pair consisting of two prefix keys.
   182  func (g *generator) prefixKeyRange() ([]byte, []byte) {
   183  	start := g.randPrefixToWrite(0.001)
   184  	end := g.randPrefixToWrite(0.001)
   185  	for g.cmp(start, end) == 0 {
   186  		end = g.randPrefixToWrite(0.05)
   187  	}
   188  	if g.cmp(start, end) > 0 {
   189  		start, end = end, start
   190  	}
   191  	return start, end
   192  }
   193  
   194  // randPrefixToWrite returns a prefix key (a key with no suffix) for a range key
   195  // write operation.
   196  func (g *generator) randPrefixToWrite(newPrefix float64) []byte {
   197  	prefixes := g.keyManager.prefixes()
   198  	if len(prefixes) > 0 && g.rng.Float64() > newPrefix {
   199  		// Use an existing prefix.
   200  		p := g.rng.Intn(len(prefixes))
   201  		return prefixes[p]
   202  	}
   203  
   204  	// Use a new prefix.
   205  	var prefix []byte
   206  	for {
   207  		prefix = g.randKeyHelperSuffix(nil, 4, 12, 0)
   208  		if !g.keyManager.prefixExists(prefix) {
   209  			if !g.keyManager.addNewKey(prefix) {
   210  				panic("key must not exist if prefix doesn't exist")
   211  			}
   212  			return prefix
   213  		}
   214  	}
   215  }
   216  
   217  // randSuffixToWrite generates a random suffix according to the configuration's suffix
   218  // distribution. It takes a probability 0 ≤ p ≤ 1.0 indicating the probability
   219  // with which the generator should increase the max suffix generated by the
   220  // generator.
   221  //
   222  // randSuffixToWrite may return a nil suffix, with the probability the
   223  // configuration's suffix distribution assigns to the zero suffix.
   224  func (g *generator) randSuffixToWrite(incMaxProb float64) []byte {
   225  	if g.rng.Float64() < incMaxProb {
   226  		g.cfg.writeSuffixDist.IncMax(1)
   227  	}
   228  	return suffixFromInt(int(g.cfg.writeSuffixDist.Uint64(g.rng)))
   229  }
   230  
   231  // randSuffixToRead generates a random suffix used during reads. The suffixes
   232  // generated by this function are within the same range as suffixes generated by
   233  // randSuffixToWrite, however randSuffixToRead pulls from a uniform
   234  // distribution.
   235  func (g *generator) randSuffixToRead() []byte {
   236  	// When reading, don't apply the recency skewing in order to better exercise
   237  	// a reading a mix of older and newer keys.
   238  	max := g.cfg.writeSuffixDist.Max()
   239  	return suffixFromInt(int(g.rng.Uint64n(max)))
   240  }
   241  
   242  func suffixFromInt(suffix int) []byte {
   243  	// Treat the zero as no suffix to match the behavior during point key
   244  	// generation in randKeyHelper.
   245  	if suffix == 0 {
   246  		return nil
   247  	}
   248  	return testkeys.Suffix(suffix)
   249  }
   250  
   251  func (g *generator) randKeyToSingleDelete(id objID) []byte {
   252  	keys := g.keyManager.eligibleSingleDeleteKeys(id)
   253  	length := len(keys)
   254  	if length == 0 {
   255  		return nil
   256  	}
   257  	return keys[g.rng.Intn(length)]
   258  }
   259  
   260  // randKeyToRead returns a key for read operations.
   261  func (g *generator) randKeyToRead(newKey float64) []byte {
   262  	return g.randKeyHelper(g.keyManager.eligibleReadKeys(), newKey)
   263  }
   264  
   265  func (g *generator) randKeyHelper(keys [][]byte, newKey float64) []byte {
   266  	switch {
   267  	case len(keys) > 0 && g.rng.Float64() > newKey:
   268  		// Use an existing user key.
   269  		return keys[g.rng.Intn(len(keys))]
   270  
   271  	case len(keys) > 0 && g.rng.Float64() > g.cfg.newPrefix:
   272  		// Use an existing prefix but a new suffix, producing a new user key.
   273  		prefixes := g.keyManager.prefixes()
   274  		var key []byte
   275  		for {
   276  			// Pick a prefix on each iteration in case most or all suffixes are
   277  			// already in use for any individual prefix.
   278  			p := g.rng.Intn(len(prefixes))
   279  			suffix := int(g.cfg.writeSuffixDist.Uint64(g.rng))
   280  
   281  			if suffix > 0 {
   282  				key = resizeBuffer(key, len(prefixes[p]), testkeys.SuffixLen(suffix))
   283  				n := copy(key, prefixes[p])
   284  				testkeys.WriteSuffix(key[n:], suffix)
   285  			} else {
   286  				key = resizeBuffer(key, len(prefixes[p]), 0)
   287  				copy(key, prefixes[p])
   288  			}
   289  			if g.keyManager.addNewKey(key) {
   290  				return key
   291  			}
   292  
   293  			// If the generated key already existed, increase the suffix
   294  			// distribution to make a generating a new user key with an existing
   295  			// prefix more likely.
   296  			g.cfg.writeSuffixDist.IncMax(1)
   297  		}
   298  
   299  	default:
   300  		// Use a new prefix, producing a new user key.
   301  		suffix := int(g.cfg.writeSuffixDist.Uint64(g.rng))
   302  		var key []byte
   303  		for {
   304  			key = g.randKeyHelperSuffix(nil, 4, 12, suffix)
   305  			if !g.keyManager.prefixExists(key[:testkeys.Comparer.Split(key)]) {
   306  				if !g.keyManager.addNewKey(key) {
   307  					panic("key must not exist if prefix doesn't exist")
   308  				}
   309  				return key
   310  			}
   311  		}
   312  	}
   313  }
   314  
   315  // randKeyHelperSuffix is a helper function for randKeyHelper, and should not be
   316  // invoked directly.
   317  func (g *generator) randKeyHelperSuffix(dst []byte, minPrefixLen, maxPrefixLen, suffix int) []byte {
   318  	n := minPrefixLen
   319  	if maxPrefixLen > minPrefixLen {
   320  		n += g.rng.Intn(maxPrefixLen - minPrefixLen)
   321  	}
   322  	// In order to test a mix of suffixed and unsuffixed keys, omit the zero
   323  	// suffix.
   324  	if suffix == 0 {
   325  		dst = resizeBuffer(dst, n, 0)
   326  		g.fillRand(dst)
   327  		return dst
   328  	}
   329  	suffixLen := testkeys.SuffixLen(suffix)
   330  	dst = resizeBuffer(dst, n, suffixLen)
   331  	g.fillRand(dst[:n])
   332  	testkeys.WriteSuffix(dst[n:], suffix)
   333  	return dst
   334  }
   335  
   336  func resizeBuffer(buf []byte, prefixLen, suffixLen int) []byte {
   337  	if cap(buf) >= prefixLen+suffixLen {
   338  		return buf[:prefixLen+suffixLen]
   339  	}
   340  	return make([]byte, prefixLen+suffixLen)
   341  }
   342  
   343  // TODO(peter): make the value size configurable. See valueSizeDist in
   344  // config.go.
   345  func (g *generator) randValue(min, max int) []byte {
   346  	n := min
   347  	if max > min {
   348  		n += g.rng.Intn(max - min)
   349  	}
   350  	buf := make([]byte, n)
   351  	g.fillRand(buf)
   352  	return buf
   353  }
   354  
   355  func (g *generator) fillRand(buf []byte) {
   356  	// NB: The actual random values are not particularly important. We only use
   357  	// lowercase letters because that makes visual determination of ordering
   358  	// easier, rather than having to remember the lexicographic ordering of
   359  	// uppercase vs lowercase, or letters vs numbers vs punctuation.
   360  	const letters = "abcdefghijklmnopqrstuvwxyz"
   361  	const lettersLen = uint64(len(letters))
   362  	const lettersCharsPerRand = 12 // floor(log(math.MaxUint64)/log(lettersLen))
   363  
   364  	var r uint64
   365  	var q int
   366  	for i := 0; i < len(buf); i++ {
   367  		if q == 0 {
   368  			r = g.rng.Uint64()
   369  			q = lettersCharsPerRand
   370  		}
   371  		buf[i] = letters[r%lettersLen]
   372  		r = r / lettersLen
   373  		q--
   374  	}
   375  }
   376  
   377  func (g *generator) newBatch() {
   378  	batchID := makeObjID(batchTag, g.init.batchSlots)
   379  	g.init.batchSlots++
   380  	g.liveBatches = append(g.liveBatches, batchID)
   381  	g.liveWriters = append(g.liveWriters, batchID)
   382  
   383  	g.add(&newBatchOp{
   384  		batchID: batchID,
   385  	})
   386  }
   387  
   388  func (g *generator) newIndexedBatch() {
   389  	batchID := makeObjID(batchTag, g.init.batchSlots)
   390  	g.init.batchSlots++
   391  	g.liveBatches = append(g.liveBatches, batchID)
   392  	g.liveReaders = append(g.liveReaders, batchID)
   393  	g.liveWriters = append(g.liveWriters, batchID)
   394  
   395  	iters := make(objIDSet)
   396  	g.batches[batchID] = iters
   397  	g.readers[batchID] = iters
   398  
   399  	g.add(&newIndexedBatchOp{
   400  		batchID: batchID,
   401  	})
   402  }
   403  
   404  func (g *generator) batchClose(batchID objID) {
   405  	g.liveBatches.remove(batchID)
   406  	iters := g.batches[batchID]
   407  	delete(g.batches, batchID)
   408  
   409  	if iters != nil {
   410  		g.liveReaders.remove(batchID)
   411  		delete(g.readers, batchID)
   412  	}
   413  	g.liveWriters.remove(batchID)
   414  	for _, id := range iters.sorted() {
   415  		g.liveIters.remove(id)
   416  		delete(g.iters, id)
   417  		g.add(&closeOp{objID: id})
   418  	}
   419  }
   420  
   421  func (g *generator) batchAbort() {
   422  	if len(g.liveBatches) == 0 {
   423  		return
   424  	}
   425  
   426  	batchID := g.liveBatches.rand(g.rng)
   427  	g.batchClose(batchID)
   428  
   429  	g.add(&closeOp{objID: batchID})
   430  }
   431  
   432  func (g *generator) batchCommit() {
   433  	if len(g.liveBatches) == 0 {
   434  		return
   435  	}
   436  
   437  	batchID := g.liveBatches.rand(g.rng)
   438  	g.batchClose(batchID)
   439  
   440  	g.add(&batchCommitOp{
   441  		batchID: batchID,
   442  	})
   443  }
   444  
   445  func (g *generator) dbClose() {
   446  	// Close any live iterators and snapshots, so that we can close the DB
   447  	// cleanly.
   448  	for len(g.liveIters) > 0 {
   449  		g.randIter(g.iterClose)()
   450  	}
   451  	for len(g.liveSnapshots) > 0 {
   452  		g.snapshotClose()
   453  	}
   454  	g.add(&closeOp{objID: makeObjID(dbTag, 0)})
   455  }
   456  
   457  func (g *generator) dbCheckpoint() {
   458  	g.add(&checkpointOp{})
   459  }
   460  
   461  func (g *generator) dbCompact() {
   462  	// Generate new key(s) with a 1% probability.
   463  	start := g.randKeyToRead(0.01)
   464  	end := g.randKeyToRead(0.01)
   465  	if g.cmp(start, end) > 0 {
   466  		start, end = end, start
   467  	}
   468  	g.add(&compactOp{
   469  		start:       start,
   470  		end:         end,
   471  		parallelize: g.rng.Float64() < 0.5,
   472  	})
   473  }
   474  
   475  func (g *generator) dbFlush() {
   476  	g.add(&flushOp{})
   477  }
   478  
   479  func (g *generator) dbRestart() {
   480  	// Close any live iterators and snapshots, so that we can close the DB
   481  	// cleanly.
   482  	for len(g.liveIters) > 0 {
   483  		g.randIter(g.iterClose)()
   484  	}
   485  	for len(g.liveSnapshots) > 0 {
   486  		g.snapshotClose()
   487  	}
   488  	// Close the batches.
   489  	for len(g.liveBatches) > 0 {
   490  		g.batchClose(g.liveBatches[0])
   491  	}
   492  	if len(g.liveReaders) != 1 || len(g.liveWriters) != 1 {
   493  		panic(fmt.Sprintf("unexpected counts: liveReaders %d, liveWriters: %d",
   494  			len(g.liveReaders), len(g.liveWriters)))
   495  	}
   496  	g.add(&dbRestartOp{})
   497  }
   498  
   499  func (g *generator) newIter() {
   500  	iterID := makeObjID(iterTag, g.init.iterSlots)
   501  	g.init.iterSlots++
   502  	g.liveIters = append(g.liveIters, iterID)
   503  
   504  	readerID := g.liveReaders.rand(g.rng)
   505  	if iters := g.readers[readerID]; iters != nil {
   506  		iters[iterID] = struct{}{}
   507  		g.iters[iterID] = iters
   508  		//lint:ignore SA9003 - readability
   509  	} else {
   510  		// NB: the DB object does not track its open iterators because it never
   511  		// closes.
   512  	}
   513  
   514  	var opts iterOpts
   515  	// Generate lower/upper bounds with a 10% probability.
   516  	if g.rng.Float64() <= 0.1 {
   517  		// Generate a new key with a .1% probability.
   518  		opts.lower = g.randKeyToRead(0.001)
   519  	}
   520  	if g.rng.Float64() <= 0.1 {
   521  		// Generate a new key with a .1% probability.
   522  		opts.upper = g.randKeyToRead(0.001)
   523  	}
   524  	if g.cmp(opts.lower, opts.upper) > 0 {
   525  		opts.lower, opts.upper = opts.upper, opts.lower
   526  	}
   527  	opts.keyTypes, opts.maskSuffix = g.randKeyTypesAndMask()
   528  
   529  	// With a low probability, enable automatic filtering of keys with suffixes
   530  	// not in the provided range. This filtering occurs both through
   531  	// block-property filtering and explicitly within the iterator operations to
   532  	// ensure determinism.
   533  	if g.rng.Intn(10) == 1 {
   534  		max := g.cfg.writeSuffixDist.Max()
   535  		opts.filterMin, opts.filterMax = g.rng.Uint64n(max)+1, g.rng.Uint64n(max)+1
   536  		if opts.filterMin > opts.filterMax {
   537  			opts.filterMin, opts.filterMax = opts.filterMax, opts.filterMin
   538  		} else if opts.filterMin == opts.filterMax {
   539  			opts.filterMax = opts.filterMin + 1
   540  		}
   541  	}
   542  
   543  	g.itersLastOpts[iterID] = opts
   544  	g.iterCreationTimestamp[iterID] = g.keyManager.nextMetaTimestamp()
   545  	g.iterReaderID[iterID] = readerID
   546  	g.add(&newIterOp{
   547  		readerID: readerID,
   548  		iterID:   iterID,
   549  		iterOpts: opts,
   550  	})
   551  }
   552  
   553  func (g *generator) randKeyTypesAndMask() (keyTypes uint32, maskSuffix []byte) {
   554  	// Iterate over different key types.
   555  	p := g.rng.Float64()
   556  	switch {
   557  	case p < 0.2: // 20% probability
   558  		keyTypes = uint32(bitalostable.IterKeyTypePointsOnly)
   559  	case p < 0.8: // 60% probability
   560  		keyTypes = uint32(bitalostable.IterKeyTypePointsAndRanges)
   561  		// With 50% probability, enable masking.
   562  		if g.rng.Intn(2) == 1 {
   563  			maskSuffix = g.randSuffixToRead()
   564  		}
   565  	default: // 20% probability
   566  		keyTypes = uint32(bitalostable.IterKeyTypeRangesOnly)
   567  	}
   568  	return keyTypes, maskSuffix
   569  }
   570  
   571  func (g *generator) newIterUsingClone() {
   572  	if len(g.liveIters) == 0 {
   573  		return
   574  	}
   575  	existingIterID := g.liveIters.rand(g.rng)
   576  	iterID := makeObjID(iterTag, g.init.iterSlots)
   577  	g.init.iterSlots++
   578  	g.liveIters = append(g.liveIters, iterID)
   579  	if iters := g.iters[existingIterID]; iters != nil {
   580  		iters[iterID] = struct{}{}
   581  		g.iters[iterID] = iters
   582  		//lint:ignore SA9003 - readability
   583  	} else {
   584  		// NB: the DB object does not track its open iterators because it never
   585  		// closes.
   586  	}
   587  
   588  	var opts iterOpts
   589  	if g.rng.Intn(2) == 1 {
   590  		g.maybeMutateOptions(&opts)
   591  		g.itersLastOpts[iterID] = opts
   592  	} else {
   593  		g.itersLastOpts[iterID] = g.itersLastOpts[existingIterID]
   594  	}
   595  
   596  	g.iterCreationTimestamp[iterID] = g.keyManager.nextMetaTimestamp()
   597  	g.iterReaderID[iterID] = g.iterReaderID[existingIterID]
   598  	g.add(&newIterUsingCloneOp{
   599  		existingIterID: existingIterID,
   600  		iterID:         iterID,
   601  		refreshBatch:   g.rng.Intn(2) == 1,
   602  		iterOpts:       opts,
   603  	})
   604  }
   605  
   606  func (g *generator) iterClose(iterID objID) {
   607  	g.liveIters.remove(iterID)
   608  	if readerIters, ok := g.iters[iterID]; ok {
   609  		delete(g.iters, iterID)
   610  		delete(readerIters, iterID)
   611  		//lint:ignore SA9003 - readability
   612  	} else {
   613  		// NB: the DB object does not track its open iterators because it never
   614  		// closes.
   615  	}
   616  
   617  	g.add(&closeOp{objID: iterID})
   618  }
   619  
   620  func (g *generator) iterSetBounds(iterID objID) {
   621  	iterLastOpts := g.itersLastOpts[iterID]
   622  	var lower, upper []byte
   623  	genLower := g.rng.Float64() <= 0.9
   624  	genUpper := g.rng.Float64() <= 0.9
   625  	// When one of ensureLowerGE, ensureUpperLE is true, the new bounds
   626  	// don't overlap with the previous bounds.
   627  	var ensureLowerGE, ensureUpperLE bool
   628  	if genLower && iterLastOpts.upper != nil && g.rng.Float64() <= 0.9 {
   629  		ensureLowerGE = true
   630  	}
   631  	if (!ensureLowerGE || g.rng.Float64() < 0.5) && genUpper && iterLastOpts.lower != nil {
   632  		ensureUpperLE = true
   633  		ensureLowerGE = false
   634  	}
   635  	attempts := 0
   636  	for {
   637  		attempts++
   638  		if genLower {
   639  			// Generate a new key with a .1% probability.
   640  			lower = g.randKeyToRead(0.001)
   641  		}
   642  		if genUpper {
   643  			// Generate a new key with a .1% probability.
   644  			upper = g.randKeyToRead(0.001)
   645  		}
   646  		if g.cmp(lower, upper) > 0 {
   647  			lower, upper = upper, lower
   648  		}
   649  		if ensureLowerGE && g.cmp(iterLastOpts.upper, lower) > 0 {
   650  			if attempts < 25 {
   651  				continue
   652  			}
   653  			lower = iterLastOpts.upper
   654  			upper = lower
   655  			break
   656  		}
   657  		if ensureUpperLE && g.cmp(upper, iterLastOpts.lower) > 0 {
   658  			if attempts < 25 {
   659  				continue
   660  			}
   661  			upper = iterLastOpts.lower
   662  			lower = upper
   663  			break
   664  		}
   665  		break
   666  	}
   667  	newOpts := iterLastOpts
   668  	newOpts.lower = lower
   669  	newOpts.upper = upper
   670  	g.itersLastOpts[iterID] = newOpts
   671  	g.add(&iterSetBoundsOp{
   672  		iterID: iterID,
   673  		lower:  lower,
   674  		upper:  upper,
   675  	})
   676  	// Additionally seek the iterator in a manner consistent with the bounds,
   677  	// and do some steps (Next/Prev). The seeking exercises typical
   678  	// CockroachDB behavior when using iterators and the steps are trying to
   679  	// stress the region near the bounds. Ideally, we should not do this as
   680  	// part of generating a single op, but this is easier than trying to
   681  	// control future op generation via generator state.
   682  	doSeekLT := upper != nil && g.rng.Float64() < 0.5
   683  	doSeekGE := lower != nil && g.rng.Float64() < 0.5
   684  	if doSeekLT && doSeekGE {
   685  		// Pick the seek.
   686  		if g.rng.Float64() < 0.5 {
   687  			doSeekGE = false
   688  		} else {
   689  			doSeekLT = false
   690  		}
   691  	}
   692  	if doSeekLT {
   693  		g.add(&iterSeekLTOp{
   694  			iterID: iterID,
   695  			key:    upper,
   696  		})
   697  		if g.rng.Float64() < 0.5 {
   698  			g.iterNext(iterID)
   699  		}
   700  		if g.rng.Float64() < 0.5 {
   701  			g.iterNext(iterID)
   702  		}
   703  		if g.rng.Float64() < 0.5 {
   704  			g.iterPrev(iterID)
   705  		}
   706  	} else if doSeekGE {
   707  		g.add(&iterSeekGEOp{
   708  			iterID: iterID,
   709  			key:    lower,
   710  		})
   711  		if g.rng.Float64() < 0.5 {
   712  			g.iterPrev(iterID)
   713  		}
   714  		if g.rng.Float64() < 0.5 {
   715  			g.iterPrev(iterID)
   716  		}
   717  		if g.rng.Float64() < 0.5 {
   718  			g.iterNext(iterID)
   719  		}
   720  	}
   721  }
   722  
   723  func (g *generator) iterSetOptions(iterID objID) {
   724  	opts := g.itersLastOpts[iterID]
   725  	g.maybeMutateOptions(&opts)
   726  	g.itersLastOpts[iterID] = opts
   727  	g.add(&iterSetOptionsOp{
   728  		iterID:   iterID,
   729  		iterOpts: opts,
   730  	})
   731  
   732  	// Additionally, perform a random absolute positioning operation. The
   733  	// SetOptions contract requires one before the next relative positioning
   734  	// operation. Ideally, we should not do this as part of generating a single
   735  	// op, but this is easier than trying to control future op generation via
   736  	// generator state.
   737  	g.pickOneUniform(
   738  		g.iterFirst,
   739  		g.iterLast,
   740  		g.iterSeekGE,
   741  		g.iterSeekGEWithLimit,
   742  		g.iterSeekPrefixGE,
   743  		g.iterSeekLT,
   744  		g.iterSeekLTWithLimit,
   745  	)(iterID)
   746  }
   747  
   748  func (g *generator) iterSeekGE(iterID objID) {
   749  	g.add(&iterSeekGEOp{
   750  		iterID: iterID,
   751  		key:    g.randKeyToRead(0.001), // 0.1% new keys
   752  	})
   753  }
   754  
   755  func (g *generator) iterSeekGEWithLimit(iterID objID) {
   756  	// 0.1% new keys
   757  	key, limit := g.randKeyToRead(0.001), g.randKeyToRead(0.001)
   758  	if g.cmp(key, limit) > 0 {
   759  		key, limit = limit, key
   760  	}
   761  	g.add(&iterSeekGEOp{
   762  		iterID: iterID,
   763  		key:    key,
   764  		limit:  limit,
   765  	})
   766  }
   767  
   768  func (g *generator) randKeyToReadWithinBounds(lower, upper []byte, readerID objID) []*keyMeta {
   769  	var inRangeKeys []*keyMeta
   770  	for _, keyMeta := range g.keyManager.byObj[readerID] {
   771  		posKey := keyMeta.key
   772  		if g.cmp(posKey, lower) < 0 || g.cmp(posKey, upper) >= 0 {
   773  			continue
   774  		}
   775  		inRangeKeys = append(inRangeKeys, keyMeta)
   776  	}
   777  	return inRangeKeys
   778  }
   779  
   780  func (g *generator) iterSeekPrefixGE(iterID objID) {
   781  	lower := g.itersLastOpts[iterID].lower
   782  	upper := g.itersLastOpts[iterID].upper
   783  	iterCreationTimestamp := g.iterCreationTimestamp[iterID]
   784  	var key []byte
   785  
   786  	// We try to make sure that the SeekPrefixGE key is within the iter bounds,
   787  	// and that the iter can read the key. If the key was created on a batch
   788  	// which deleted the key, then the key will still be considered visible
   789  	// by the current logic. We're also not accounting for keys written to
   790  	// batches which haven't been presisted to the DB. But we're only picking
   791  	// keys in a best effort manner, and the logic is better than picking a
   792  	// random key.
   793  	if g.rng.Intn(10) >= 1 {
   794  		possibleKeys := make([][]byte, 0, 100)
   795  		inRangeKeys := g.randKeyToReadWithinBounds(lower, upper, dbObjID)
   796  		for _, keyMeta := range inRangeKeys {
   797  			posKey := keyMeta.key
   798  			var foundWriteWithoutDelete bool
   799  			for _, update := range keyMeta.updateOps {
   800  				if update.metaTimestamp > iterCreationTimestamp {
   801  					break
   802  				}
   803  
   804  				if update.deleted {
   805  					foundWriteWithoutDelete = false
   806  				} else {
   807  					foundWriteWithoutDelete = true
   808  				}
   809  			}
   810  			if foundWriteWithoutDelete {
   811  				possibleKeys = append(possibleKeys, posKey)
   812  			}
   813  		}
   814  
   815  		if len(possibleKeys) > 0 {
   816  			key = []byte(possibleKeys[g.rng.Int31n(int32(len(possibleKeys)))])
   817  		}
   818  	}
   819  
   820  	if key == nil {
   821  		// TODO(bananabrick): We should try and use keys within the bounds,
   822  		// even if we couldn't find any keys visible to the iterator. However,
   823  		// doing this in experiments didn't really increase the valid
   824  		// SeekPrefixGE calls by much.
   825  		key = g.randKeyToRead(0) // 0% new keys
   826  	}
   827  
   828  	g.add(&iterSeekPrefixGEOp{
   829  		iterID: iterID,
   830  		key:    key,
   831  	})
   832  }
   833  
   834  func (g *generator) iterSeekLT(iterID objID) {
   835  	g.add(&iterSeekLTOp{
   836  		iterID: iterID,
   837  		key:    g.randKeyToRead(0.001), // 0.1% new keys
   838  	})
   839  }
   840  
   841  func (g *generator) iterSeekLTWithLimit(iterID objID) {
   842  	// 0.1% new keys
   843  	key, limit := g.randKeyToRead(0.001), g.randKeyToRead(0.001)
   844  	if g.cmp(limit, key) > 0 {
   845  		key, limit = limit, key
   846  	}
   847  	g.add(&iterSeekLTOp{
   848  		iterID: iterID,
   849  		key:    key,
   850  		limit:  limit,
   851  	})
   852  }
   853  
   854  // randIter performs partial func application ("currying"), returning a new
   855  // function that supplies the given func with a random iterator.
   856  func (g *generator) randIter(gen func(objID)) func() {
   857  	return func() {
   858  		if len(g.liveIters) == 0 {
   859  			return
   860  		}
   861  		gen(g.liveIters.rand(g.rng))
   862  	}
   863  }
   864  
   865  func (g *generator) iterFirst(iterID objID) { g.add(&iterFirstOp{iterID: iterID}) }
   866  func (g *generator) iterLast(iterID objID)  { g.add(&iterLastOp{iterID: iterID}) }
   867  func (g *generator) iterNext(iterID objID)  { g.add(&iterNextOp{iterID: iterID}) }
   868  func (g *generator) iterPrev(iterID objID)  { g.add(&iterPrevOp{iterID: iterID}) }
   869  
   870  func (g *generator) iterNextWithLimit(iterID objID) {
   871  	g.add(&iterNextOp{
   872  		iterID: iterID,
   873  		limit:  g.randKeyToRead(0.001), // 0.1% new keys
   874  	})
   875  }
   876  
   877  func (g *generator) iterPrevWithLimit(iterID objID) {
   878  	g.add(&iterPrevOp{
   879  		iterID: iterID,
   880  		limit:  g.randKeyToRead(0.001), // 0.1% new keys
   881  	})
   882  }
   883  
   884  func (g *generator) readerGet() {
   885  	if len(g.liveReaders) == 0 {
   886  		return
   887  	}
   888  
   889  	g.add(&getOp{
   890  		readerID: g.liveReaders.rand(g.rng),
   891  		key:      g.randKeyToRead(0.001), // 0.1% new keys
   892  	})
   893  }
   894  
   895  func (g *generator) newSnapshot() {
   896  	snapID := makeObjID(snapTag, g.init.snapshotSlots)
   897  	g.init.snapshotSlots++
   898  	g.liveSnapshots = append(g.liveSnapshots, snapID)
   899  	g.liveReaders = append(g.liveReaders, snapID)
   900  
   901  	iters := make(objIDSet)
   902  	g.snapshots[snapID] = iters
   903  	g.readers[snapID] = iters
   904  
   905  	g.add(&newSnapshotOp{
   906  		snapID: snapID,
   907  	})
   908  }
   909  
   910  func (g *generator) snapshotClose() {
   911  	if len(g.liveSnapshots) == 0 {
   912  		return
   913  	}
   914  
   915  	snapID := g.liveSnapshots.rand(g.rng)
   916  	g.liveSnapshots.remove(snapID)
   917  	iters := g.snapshots[snapID]
   918  	delete(g.snapshots, snapID)
   919  	g.liveReaders.remove(snapID)
   920  	delete(g.readers, snapID)
   921  
   922  	for _, id := range iters.sorted() {
   923  		g.liveIters.remove(id)
   924  		delete(g.iters, id)
   925  		g.add(&closeOp{objID: id})
   926  	}
   927  
   928  	g.add(&closeOp{objID: snapID})
   929  }
   930  
   931  func (g *generator) writerApply() {
   932  	if len(g.liveBatches) == 0 {
   933  		return
   934  	}
   935  	if len(g.liveWriters) < 2 {
   936  		panic(fmt.Sprintf("insufficient liveWriters (%d) to apply batch", len(g.liveWriters)))
   937  	}
   938  
   939  	batchID := g.liveBatches.rand(g.rng)
   940  
   941  	var writerID objID
   942  	for {
   943  		writerID = g.liveWriters.rand(g.rng)
   944  		if writerID != batchID {
   945  			break
   946  		}
   947  	}
   948  
   949  	g.batchClose(batchID)
   950  
   951  	g.add(&applyOp{
   952  		writerID: writerID,
   953  		batchID:  batchID,
   954  	})
   955  }
   956  
   957  func (g *generator) writerDelete() {
   958  	if len(g.liveWriters) == 0 {
   959  		return
   960  	}
   961  
   962  	writerID := g.liveWriters.rand(g.rng)
   963  	g.add(&deleteOp{
   964  		writerID: writerID,
   965  		key:      g.randKeyToWrite(0.001), // 0.1% new keys
   966  	})
   967  }
   968  
   969  func (g *generator) writerDeleteRange() {
   970  	if len(g.liveWriters) == 0 {
   971  		return
   972  	}
   973  
   974  	start := g.randKeyToWrite(0.001)
   975  	end := g.randKeyToWrite(0.001)
   976  	if g.cmp(start, end) > 0 {
   977  		start, end = end, start
   978  	}
   979  
   980  	writerID := g.liveWriters.rand(g.rng)
   981  	g.add(&deleteRangeOp{
   982  		writerID: writerID,
   983  		start:    start,
   984  		end:      end,
   985  	})
   986  }
   987  
   988  func (g *generator) writerRangeKeyDelete() {
   989  	if len(g.liveWriters) == 0 {
   990  		return
   991  	}
   992  	start, end := g.prefixKeyRange()
   993  
   994  	writerID := g.liveWriters.rand(g.rng)
   995  	g.add(&rangeKeyDeleteOp{
   996  		writerID: writerID,
   997  		start:    start,
   998  		end:      end,
   999  	})
  1000  }
  1001  
  1002  func (g *generator) writerRangeKeySet() {
  1003  	if len(g.liveWriters) == 0 {
  1004  		return
  1005  	}
  1006  	start, end := g.prefixKeyRange()
  1007  
  1008  	// 90% of the time, set a suffix.
  1009  	var suffix []byte
  1010  	if g.rng.Float64() < 0.90 {
  1011  		// Increase the max suffix 5% of the time.
  1012  		suffix = g.randSuffixToWrite(0.05)
  1013  	}
  1014  
  1015  	writerID := g.liveWriters.rand(g.rng)
  1016  	g.add(&rangeKeySetOp{
  1017  		writerID: writerID,
  1018  		start:    start,
  1019  		end:      end,
  1020  		suffix:   suffix,
  1021  		value:    g.randValue(0, 20),
  1022  	})
  1023  }
  1024  
  1025  func (g *generator) writerRangeKeyUnset() {
  1026  	if len(g.liveWriters) == 0 {
  1027  		return
  1028  	}
  1029  	start, end := g.prefixKeyRange()
  1030  
  1031  	// 90% of the time, set a suffix.
  1032  	var suffix []byte
  1033  	if g.rng.Float64() < 0.90 {
  1034  		// Increase the max suffix 5% of the time.
  1035  		suffix = g.randSuffixToWrite(0.05)
  1036  	}
  1037  
  1038  	// TODO(jackson): Increase probability of effective unsets? Purely random
  1039  	// unsets are unlikely to remove an active range key.
  1040  
  1041  	writerID := g.liveWriters.rand(g.rng)
  1042  	g.add(&rangeKeyUnsetOp{
  1043  		writerID: writerID,
  1044  		start:    start,
  1045  		end:      end,
  1046  		suffix:   suffix,
  1047  	})
  1048  }
  1049  
  1050  func (g *generator) writerIngest() {
  1051  	if len(g.liveBatches) == 0 {
  1052  		return
  1053  	}
  1054  
  1055  	// TODO(nicktrav): this is resulting in too many single batch ingests.
  1056  	// Consider alternatives. One possibility would be to pass through whether
  1057  	// we can tolerate failure or not, and if the ingestOp encounters a
  1058  	// failure, it would retry after splitting into single batch ingests.
  1059  
  1060  	// Ingest between 1 and 3 batches.
  1061  	batchIDs := make([]objID, 0, 1+g.rng.Intn(3))
  1062  	canFail := cap(batchIDs) > 1
  1063  	for i := 0; i < cap(batchIDs); i++ {
  1064  		batchID := g.liveBatches.rand(g.rng)
  1065  		if canFail && !g.keyManager.canTolerateApplyFailure(batchID) {
  1066  			continue
  1067  		}
  1068  		// After the ingest runs, it either succeeds and the keys are in the
  1069  		// DB, or it fails and these keys never make it to the DB.
  1070  		g.batchClose(batchID)
  1071  		batchIDs = append(batchIDs, batchID)
  1072  		if len(g.liveBatches) == 0 {
  1073  			break
  1074  		}
  1075  	}
  1076  	if len(batchIDs) == 0 && len(g.liveBatches) > 0 {
  1077  		// Unable to find multiple batches because of the
  1078  		// canTolerateApplyFailure call above, so just pick one batch.
  1079  		batchID := g.liveBatches.rand(g.rng)
  1080  		g.batchClose(batchID)
  1081  		batchIDs = append(batchIDs, batchID)
  1082  	}
  1083  	g.add(&ingestOp{
  1084  		batchIDs: batchIDs,
  1085  	})
  1086  }
  1087  
  1088  func (g *generator) writerMerge() {
  1089  	if len(g.liveWriters) == 0 {
  1090  		return
  1091  	}
  1092  
  1093  	writerID := g.liveWriters.rand(g.rng)
  1094  	g.add(&mergeOp{
  1095  		writerID: writerID,
  1096  		// 20% new keys.
  1097  		key:   g.randKeyToWrite(0.2),
  1098  		value: g.randValue(0, 20),
  1099  	})
  1100  }
  1101  
  1102  func (g *generator) writerSet() {
  1103  	if len(g.liveWriters) == 0 {
  1104  		return
  1105  	}
  1106  
  1107  	writerID := g.liveWriters.rand(g.rng)
  1108  	g.add(&setOp{
  1109  		writerID: writerID,
  1110  		// 50% new keys.
  1111  		key:   g.randKeyToWrite(0.5),
  1112  		value: g.randValue(0, 20),
  1113  	})
  1114  }
  1115  
  1116  func (g *generator) writerSingleDelete() {
  1117  	if len(g.liveWriters) == 0 {
  1118  		return
  1119  	}
  1120  
  1121  	writerID := g.liveWriters.rand(g.rng)
  1122  	key := g.randKeyToSingleDelete(writerID)
  1123  	if key == nil {
  1124  		return
  1125  	}
  1126  	g.add(&singleDeleteOp{
  1127  		writerID: writerID,
  1128  		key:      key,
  1129  		// Keys eligible for single deletes can be removed with a regular
  1130  		// delete. Mutate a percentage of SINGLEDEL ops into DELETEs. Note that
  1131  		// here we are only determining whether the replacement *could* happen.
  1132  		// At test runtime, the `replaceSingleDelete` test option must also be
  1133  		// set to true for the single delete to be replaced.
  1134  		maybeReplaceDelete: g.rng.Float64() < 0.25,
  1135  	})
  1136  }
  1137  
  1138  func (g *generator) maybeMutateOptions(opts *iterOpts) {
  1139  	// With 95% probability, allow changes to any options at all. This ensures
  1140  	// that in 5% of cases there are no changes, and SetOptions hits its fast
  1141  	// path.
  1142  	if g.rng.Intn(100) >= 5 {
  1143  		// With 1/3 probability, clear existing bounds.
  1144  		if opts.lower != nil && g.rng.Intn(3) == 0 {
  1145  			opts.lower = nil
  1146  		}
  1147  		if opts.upper != nil && g.rng.Intn(3) == 0 {
  1148  			opts.upper = nil
  1149  		}
  1150  		// With 1/3 probability, update the bounds.
  1151  		if g.rng.Intn(3) == 0 {
  1152  			// Generate a new key with a .1% probability.
  1153  			opts.lower = g.randKeyToRead(0.001)
  1154  		}
  1155  		if g.rng.Intn(3) == 0 {
  1156  			// Generate a new key with a .1% probability.
  1157  			opts.upper = g.randKeyToRead(0.001)
  1158  		}
  1159  		if g.cmp(opts.lower, opts.upper) > 0 {
  1160  			opts.lower, opts.upper = opts.upper, opts.lower
  1161  		}
  1162  
  1163  		// With 1/3 probability, update the key-types/mask.
  1164  		if g.rng.Intn(3) == 0 {
  1165  			opts.keyTypes, opts.maskSuffix = g.randKeyTypesAndMask()
  1166  		}
  1167  
  1168  		// With 1/3 probability, clear existing filter.
  1169  		if opts.filterMax > 0 && g.rng.Intn(3) == 0 {
  1170  			opts.filterMax, opts.filterMin = 0, 0
  1171  		}
  1172  		// With 10% probability, set a filter range.
  1173  		if g.rng.Intn(10) == 1 {
  1174  			max := g.cfg.writeSuffixDist.Max()
  1175  			opts.filterMin, opts.filterMax = g.rng.Uint64n(max)+1, g.rng.Uint64n(max)+1
  1176  			if opts.filterMin > opts.filterMax {
  1177  				opts.filterMin, opts.filterMax = opts.filterMax, opts.filterMin
  1178  			} else if opts.filterMin == opts.filterMax {
  1179  				opts.filterMax = opts.filterMin + 1
  1180  			}
  1181  		}
  1182  	}
  1183  }
  1184  
  1185  func (g *generator) pickOneUniform(options ...func(objID)) func(objID) {
  1186  	i := g.rng.Intn(len(options))
  1187  	return options[i]
  1188  }
  1189  
  1190  func (g *generator) cmp(a, b []byte) int {
  1191  	return g.keyManager.comparer.Compare(a, b)
  1192  }
  1193  
  1194  func (g *generator) String() string {
  1195  	var buf bytes.Buffer
  1196  	for _, op := range g.ops {
  1197  		fmt.Fprintf(&buf, "%s\n", op)
  1198  	}
  1199  	return buf.String()
  1200  }