services/syncbase: fix --race errors.
Fix race conditions detected by Syncbase --race testing:
* Add a mutex for a random number generator that uses a NewSource().
* Goroutines spawned in a loop must get a copy of the loop iterator,
not access it through closure.
Change-Id: I88094fceac6708be2a3fbb49d2861de105534c80
diff --git a/services/syncbase/server/watchable/util.go b/services/syncbase/server/watchable/util.go
index b77b15f..5eb1bb4 100644
--- a/services/syncbase/server/watchable/util.go
+++ b/services/syncbase/server/watchable/util.go
@@ -11,6 +11,7 @@
import (
"fmt"
"math/rand"
+ "sync"
"time"
"v.io/syncbase/x/ref/services/syncbase/server/util"
@@ -18,7 +19,10 @@
"v.io/v23/verror"
)
-var rng *rand.Rand = rand.New(rand.NewSource(time.Now().UTC().UnixNano()))
+var (
+ rng *rand.Rand = rand.New(rand.NewSource(time.Now().UTC().UnixNano()))
+ rngLock sync.Mutex
+)
func makeVersionKey(key []byte) []byte {
return []byte(join(util.VersionPrefix, string(key)))
@@ -46,7 +50,11 @@
}
func putVersioned(tx store.Transaction, key, value []byte) error {
- version := []byte(fmt.Sprintf("%x", rng.Int63()))
+ rngLock.Lock()
+ num := rng.Int63()
+ rngLock.Unlock()
+
+ version := []byte(fmt.Sprintf("%x", num))
if err := tx.Put(makeVersionKey(key), version); err != nil {
return err
}
diff --git a/services/syncbase/store/test/transaction.go b/services/syncbase/store/test/transaction.go
index 7b697b4..889e05b 100644
--- a/services/syncbase/store/test/transaction.go
+++ b/services/syncbase/store/test/transaction.go
@@ -148,8 +148,8 @@
var wg sync.WaitGroup
wg.Add(k)
for i := 0; i < k; i++ {
- go func() {
- rnd := rand.New(rand.NewSource(239017 * int64(i)))
+ go func(idx int) {
+ rnd := rand.New(rand.NewSource(239017 * int64(idx)))
perm := rnd.Perm(n)
if err := store.RunInTransaction(st, func(st store.StoreReadWriter) error {
for j := 0; j <= m; j++ {
@@ -183,7 +183,7 @@
panic(fmt.Errorf("can't commit transaction: %v", err))
}
wg.Done()
- }()
+ }(i)
}
wg.Wait()
var sum int64