Преглед изворни кода

Use goroutine-safe version of rand.Source

Signed-off-by: Alexander Morozov <lk4d4@docker.com>
Alexander Morozov пре 10 година
родитељ
комит
d8661250e7

+ 3 - 2
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 {

+ 34 - 0
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()),
+	}
+}

+ 22 - 0
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()
+}

+ 5 - 4
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)
 }