From d8661250e71a60f053f575496d2b66d704549d6e Mon Sep 17 00:00:00 2001 From: Alexander Morozov Date: Tue, 19 May 2015 12:32:40 -0700 Subject: [PATCH] Use goroutine-safe version of rand.Source Signed-off-by: Alexander Morozov --- pkg/namesgenerator/names-generator.go | 5 ++-- pkg/random/random.go | 34 +++++++++++++++++++++++++++ pkg/random/random_test.go | 22 +++++++++++++++++ pkg/stringutils/stringutils.go | 9 +++---- 4 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 pkg/random/random.go create mode 100644 pkg/random/random_test.go diff --git a/pkg/namesgenerator/names-generator.go b/pkg/namesgenerator/names-generator.go index 1087ece992..b081cc7db3 100644 --- a/pkg/namesgenerator/names-generator.go +++ b/pkg/namesgenerator/names-generator.go @@ -3,7 +3,8 @@ package namesgenerator import ( "fmt" "math/rand" - "time" + + "github.com/docker/docker/pkg/random" ) var ( @@ -309,7 +310,7 @@ var ( "yonath", } - rnd = rand.New(rand.NewSource(time.Now().UnixNano())) + rnd = rand.New(random.NewSource()) ) func GetRandomName(retry int) string { diff --git a/pkg/random/random.go b/pkg/random/random.go new file mode 100644 index 0000000000..05b7f7fb37 --- /dev/null +++ b/pkg/random/random.go @@ -0,0 +1,34 @@ +package random + +import ( + "math/rand" + "sync" + "time" +) + +// copypaste from standard math/rand +type lockedSource struct { + lk sync.Mutex + src rand.Source +} + +func (r *lockedSource) Int63() (n int64) { + r.lk.Lock() + n = r.src.Int63() + r.lk.Unlock() + return +} + +func (r *lockedSource) Seed(seed int64) { + r.lk.Lock() + r.src.Seed(seed) + r.lk.Unlock() +} + +// NewSource returns math/rand.Source safe for concurrent use and initialized +// with current unix-nano timestamp +func NewSource() rand.Source { + return &lockedSource{ + src: rand.NewSource(time.Now().UnixNano()), + } +} diff --git a/pkg/random/random_test.go b/pkg/random/random_test.go new file mode 100644 index 0000000000..cf405f78cb --- /dev/null +++ b/pkg/random/random_test.go @@ -0,0 +1,22 @@ +package random + +import ( + "math/rand" + "sync" + "testing" +) + +// for go test -v -race +func TestConcurrency(t *testing.T) { + rnd := rand.New(NewSource()) + var wg sync.WaitGroup + + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + rnd.Int63() + wg.Done() + }() + } + wg.Wait() +} diff --git a/pkg/stringutils/stringutils.go b/pkg/stringutils/stringutils.go index e3ebf5d1ed..aee2648b2d 100644 --- a/pkg/stringutils/stringutils.go +++ b/pkg/stringutils/stringutils.go @@ -2,9 +2,10 @@ package stringutils import ( "bytes" - mathrand "math/rand" + "math/rand" "strings" - "time" + + "github.com/docker/docker/pkg/random" ) // Generate alpha only random stirng with length n @@ -12,7 +13,7 @@ func GenerateRandomAlphaOnlyString(n int) string { // make a really long string letters := []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") b := make([]byte, n) - r := mathrand.New(mathrand.NewSource(time.Now().UTC().UnixNano())) + r := rand.New(random.NewSource()) for i := range b { b[i] = letters[r.Intn(len(letters))] } @@ -26,7 +27,7 @@ func GenerateRandomAsciiString(n int) string { "~!@#$%^&*()-_+={}[]\\|<,>.?/\"';:` " res := make([]byte, n) for i := 0; i < n; i++ { - res[i] = chars[mathrand.Intn(len(chars))] + res[i] = chars[rand.Intn(len(chars))] } return string(res) }