|
@@ -18,6 +18,7 @@ import (
|
|
|
"context"
|
|
"context"
|
|
|
"errors"
|
|
"errors"
|
|
|
"fmt"
|
|
"fmt"
|
|
|
|
|
+ "sync"
|
|
|
|
|
|
|
|
"github.com/coreos/etcd/clientv3/concurrency"
|
|
"github.com/coreos/etcd/clientv3/concurrency"
|
|
|
|
|
|
|
@@ -47,6 +48,8 @@ func runRacerFunc(cmd *cobra.Command, args []string) {
|
|
|
|
|
|
|
|
rcs := make([]roundClient, totalClientConnections)
|
|
rcs := make([]roundClient, totalClientConnections)
|
|
|
ctx := context.Background()
|
|
ctx := context.Background()
|
|
|
|
|
+ // mu ensures validate and release funcs are atomic.
|
|
|
|
|
+ var mu sync.Mutex
|
|
|
cnt := 0
|
|
cnt := 0
|
|
|
|
|
|
|
|
eps := endpointsFromFlag(cmd)
|
|
eps := endpointsFromFlag(cmd)
|
|
@@ -69,12 +72,16 @@ func runRacerFunc(cmd *cobra.Command, args []string) {
|
|
|
m := concurrency.NewMutex(s, racers)
|
|
m := concurrency.NewMutex(s, racers)
|
|
|
rcs[i].acquire = func() error { return m.Lock(ctx) }
|
|
rcs[i].acquire = func() error { return m.Lock(ctx) }
|
|
|
rcs[i].validate = func() error {
|
|
rcs[i].validate = func() error {
|
|
|
|
|
+ mu.Lock()
|
|
|
|
|
+ defer mu.Unlock()
|
|
|
if cnt++; cnt != 1 {
|
|
if cnt++; cnt != 1 {
|
|
|
return fmt.Errorf("bad lock; count: %d", cnt)
|
|
return fmt.Errorf("bad lock; count: %d", cnt)
|
|
|
}
|
|
}
|
|
|
return nil
|
|
return nil
|
|
|
}
|
|
}
|
|
|
rcs[i].release = func() error {
|
|
rcs[i].release = func() error {
|
|
|
|
|
+ mu.Lock()
|
|
|
|
|
+ defer mu.Unlock()
|
|
|
if err := m.Unlock(ctx); err != nil {
|
|
if err := m.Unlock(ctx); err != nil {
|
|
|
return err
|
|
return err
|
|
|
}
|
|
}
|