From 6be3ad36bebe478aff0b8711ef9c8318f0c94a5a Mon Sep 17 00:00:00 2001 From: zhangwenkang Date: Tue, 4 Jul 2023 22:01:54 +0800 Subject: [PATCH] clientv3: remove v3.WithFirstKey() in Barrier.Wait() fix the unexpected blocking when using Barrier.Wait(), e.g. NewBarrier(client, "a").Wait() will block if key "a" is not existed but "a0" is existed, but it should return immediately. Signed-off-by: zhangwenkang --- client/v3/experimental/recipes/barrier.go | 2 +- .../experimental/recipes/v3_barrier_test.go | 39 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/client/v3/experimental/recipes/barrier.go b/client/v3/experimental/recipes/barrier.go index 7e950a3e385..ce88e4ff86d 100644 --- a/client/v3/experimental/recipes/barrier.go +++ b/client/v3/experimental/recipes/barrier.go @@ -49,7 +49,7 @@ func (b *Barrier) Release() error { // Wait blocks on the barrier key until it is deleted. If there is no key, Wait // assumes Release has already been called and returns immediately. func (b *Barrier) Wait() error { - resp, err := b.client.Get(b.ctx, b.key, v3.WithFirstKey()...) + resp, err := b.client.Get(b.ctx, b.key) if err != nil { return err } diff --git a/tests/integration/clientv3/experimental/recipes/v3_barrier_test.go b/tests/integration/clientv3/experimental/recipes/v3_barrier_test.go index 52bde238d43..57f08037047 100644 --- a/tests/integration/clientv3/experimental/recipes/v3_barrier_test.go +++ b/tests/integration/clientv3/experimental/recipes/v3_barrier_test.go @@ -83,3 +83,42 @@ func testBarrier(t *testing.T, waiters int, chooseClient func() *clientv3.Client } } } + +func TestBarrierWaitNonexistentKey(t *testing.T) { + integration.BeforeTest(t) + clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1}) + defer clus.Terminate(t) + cli := clus.Client(0) + + if _, err := cli.Put(cli.Ctx(), "test-barrier-0", ""); err != nil { + t.Errorf("could not put test-barrier0, err:%v", err) + } + + donec := make(chan struct{}) + stopc := make(chan struct{}) + defer close(stopc) + + waiters := 5 + for i := 0; i < waiters; i++ { + go func() { + br := recipe.NewBarrier(cli, "test-barrier") + if err := br.Wait(); err != nil { + t.Errorf("could not wait on barrier (%v)", err) + } + select { + case donec <- struct{}{}: + case <-stopc: + } + }() + } + + // all waiters should return immediately if waiting on a nonexistent key "test-barrier" even if key "test-barrier-0" exists + timerC := time.After(time.Duration(waiters*100) * time.Millisecond) + for i := 0; i < waiters; i++ { + select { + case <-timerC: + t.Fatal("barrier timed out") + case <-donec: + } + } +}