// Copyright 2019 The LevelDB-Go and Pebble Authors. All rights reserved. Use // of this source code is governed by a BSD-style license that can be found in // the LICENSE file. package metamorphic import ( "fmt" "sort" "golang.org/x/exp/rand" ) // objTag identifies the type for an object: DB, Batch, Iter, or Snapshot. type objTag uint8 const ( dbTag objTag = iota + 1 batchTag iterTag snapTag ) // objID identifies a particular object. The top 4-bits store the tag // identifying the type of object, while the bottom 28-bits store the slot used // to index with the test.{batches,iters,snapshots} slices. type objID uint32 func makeObjID(t objTag, slot uint32) objID { return objID((uint32(t) << 28) | slot) } func (i objID) tag() objTag { return objTag(i >> 28) } func (i objID) slot() uint32 { return uint32(i) & ((1 << 28) - 1) } func (i objID) String() string { switch i.tag() { case dbTag: return fmt.Sprintf("db%d", i.slot()) case batchTag: return fmt.Sprintf("batch%d", i.slot()) case iterTag: return fmt.Sprintf("iter%d", i.slot()) case snapTag: return fmt.Sprintf("snap%d", i.slot()) } return fmt.Sprintf("unknown%d", i.slot()) } // objIDSlice is an unordered set of integers used when random selection of an // element is required. type objIDSlice []objID func (s objIDSlice) Len() int { return len(s) } func (s objIDSlice) Less(i, j int) bool { return s[i] < s[j] } func (s objIDSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } // Remove removes the specified integer from the set. // // TODO(peter): If this proves slow, we can replace this implementation with a // map and a slice. The slice would provide for random selection of an element, // while the map would provide quick location of an element to remove. func (s *objIDSlice) remove(id objID) { n := len(*s) for j := 0; j < n; j++ { if (*s)[j] == id { (*s)[j], (*s)[n-1] = (*s)[n-1], (*s)[j] (*s) = (*s)[:n-1] break } } } func (s *objIDSlice) rand(rng *rand.Rand) objID { return (*s)[rng.Intn(len(*s))] } // objIDSet is an unordered set of object IDs. type objIDSet map[objID]struct{} // sortedKeys returns a sorted slice of the set's keys for deterministic // iteration. func (s objIDSet) sorted() []objID { keys := make(objIDSlice, 0, len(s)) for id := range s { keys = append(keys, id) } sort.Sort(keys) return keys } // firstError returns the first non-nil error of err0 and err1, or nil if both // are nil. func firstError(err0, err1 error) error { if err0 != nil { return err0 } return err1 }