github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/workload/schemachange/deck.go (about) 1 // Copyright 2020 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package schemachange 12 13 import ( 14 "math/rand" 15 16 "github.com/cockroachdb/cockroach/pkg/util/syncutil" 17 ) 18 19 // Deck is a random number generator that generates numbers in the range 20 // [0,len(weights)-1] where the probability of i is 21 // weights(i)/sum(weights). Unlike Weighted, the weights are specified as 22 // integers and used in a deck-of-cards style random number selection which 23 // ensures that each element is returned with a desired frequency within the 24 // size of the deck. 25 type deck struct { 26 rng *rand.Rand 27 mu struct { 28 syncutil.Mutex 29 index int 30 vals []int 31 } 32 } 33 34 // newDeck returns a new deck random number generator. 35 func newDeck(rng *rand.Rand, weights ...int) *deck { 36 var sum int 37 for i := range weights { 38 sum += weights[i] 39 } 40 vals := make([]int, 0, sum) 41 for i := range weights { 42 for j := 0; j < weights[i]; j++ { 43 vals = append(vals, i) 44 } 45 } 46 d := &deck{ 47 rng: rng, 48 } 49 d.mu.index = len(vals) 50 d.mu.vals = vals 51 return d 52 } 53 54 // Int returns a random number in the range [0,len(weights)-1] where the 55 // probability of i is weights(i)/sum(weights). 56 func (d *deck) Int() int { 57 d.mu.Lock() 58 if d.mu.index == len(d.mu.vals) { 59 d.rng.Shuffle(len(d.mu.vals), func(i, j int) { 60 d.mu.vals[i], d.mu.vals[j] = d.mu.vals[j], d.mu.vals[i] 61 }) 62 d.mu.index = 0 63 } 64 result := d.mu.vals[d.mu.index] 65 d.mu.index++ 66 d.mu.Unlock() 67 return result 68 }