github.com/cockroachdb/pebble@v0.0.0-20231214172447-ab4952c5f87b/metamorphic/utils.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  	"fmt"
     9  	"sort"
    10  
    11  	"golang.org/x/exp/rand"
    12  )
    13  
    14  // objTag identifies the type for an object: DB, Batch, Iter, or Snapshot.
    15  type objTag uint8
    16  
    17  const (
    18  	dbTag objTag = iota + 1
    19  	batchTag
    20  	iterTag
    21  	snapTag
    22  )
    23  
    24  // objID identifies a particular object. The top 4-bits store the tag
    25  // identifying the type of object, while the bottom 28-bits store the slot used
    26  // to index with the test.{batches,iters,snapshots} slices.
    27  type objID uint32
    28  
    29  func makeObjID(t objTag, slot uint32) objID {
    30  	return objID((uint32(t) << 28) | slot)
    31  }
    32  
    33  func (i objID) tag() objTag {
    34  	return objTag(i >> 28)
    35  }
    36  
    37  func (i objID) slot() uint32 {
    38  	return uint32(i) & ((1 << 28) - 1)
    39  }
    40  
    41  func (i objID) String() string {
    42  	switch i.tag() {
    43  	case dbTag:
    44  		return fmt.Sprintf("db%d", i.slot())
    45  	case batchTag:
    46  		return fmt.Sprintf("batch%d", i.slot())
    47  	case iterTag:
    48  		return fmt.Sprintf("iter%d", i.slot())
    49  	case snapTag:
    50  		return fmt.Sprintf("snap%d", i.slot())
    51  	}
    52  	return fmt.Sprintf("unknown%d", i.slot())
    53  }
    54  
    55  // objIDSlice is an unordered set of integers used when random selection of an
    56  // element is required.
    57  type objIDSlice []objID
    58  
    59  func (s objIDSlice) Len() int           { return len(s) }
    60  func (s objIDSlice) Less(i, j int) bool { return s[i] < s[j] }
    61  func (s objIDSlice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
    62  
    63  // Remove removes the specified integer from the set.
    64  //
    65  // TODO(peter): If this proves slow, we can replace this implementation with a
    66  // map and a slice. The slice would provide for random selection of an element,
    67  // while the map would provide quick location of an element to remove.
    68  func (s *objIDSlice) remove(id objID) {
    69  	n := len(*s)
    70  	for j := 0; j < n; j++ {
    71  		if (*s)[j] == id {
    72  			(*s)[j], (*s)[n-1] = (*s)[n-1], (*s)[j]
    73  			(*s) = (*s)[:n-1]
    74  			break
    75  		}
    76  	}
    77  }
    78  
    79  func (s *objIDSlice) rand(rng *rand.Rand) objID {
    80  	return (*s)[rng.Intn(len(*s))]
    81  }
    82  
    83  // objIDSet is an unordered set of object IDs.
    84  type objIDSet map[objID]struct{}
    85  
    86  // sortedKeys returns a sorted slice of the set's keys for deterministic
    87  // iteration.
    88  func (s objIDSet) sorted() []objID {
    89  	keys := make(objIDSlice, 0, len(s))
    90  	for id := range s {
    91  		keys = append(keys, id)
    92  	}
    93  	sort.Sort(keys)
    94  	return keys
    95  }
    96  
    97  // firstError returns the first non-nil error of err0 and err1, or nil if both
    98  // are nil.
    99  func firstError(err0, err1 error) error {
   100  	if err0 != nil {
   101  		return err0
   102  	}
   103  	return err1
   104  }