From 71a25b0b762f988c5c7192733fa7702673c9b3a3 Mon Sep 17 00:00:00 2001 From: Dousir9 <736191200@qq.com> Date: Sat, 14 Jan 2023 14:52:46 +0800 Subject: [PATCH 1/3] add lock at Base --- meta/autoid/autoid.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/meta/autoid/autoid.go b/meta/autoid/autoid.go index 8ee99f5939a0e..3a31de31b5475 100644 --- a/meta/autoid/autoid.go +++ b/meta/autoid/autoid.go @@ -222,6 +222,8 @@ func SetStep(s int64) { // Base implements autoid.Allocator Base interface. func (alloc *allocator) Base() int64 { + alloc.mu.Lock() + defer alloc.mu.Unlock() return alloc.base } From 3133623c117b05936a627370e3e6c1ff146c6230 Mon Sep 17 00:00:00 2001 From: Dousir9 <736191200@qq.com> Date: Mon, 16 Jan 2023 22:11:51 +0800 Subject: [PATCH 2/3] add lock on allocator.End --- meta/autoid/autoid.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/meta/autoid/autoid.go b/meta/autoid/autoid.go index 3a31de31b5475..bfbb04b72a906 100644 --- a/meta/autoid/autoid.go +++ b/meta/autoid/autoid.go @@ -229,6 +229,8 @@ func (alloc *allocator) Base() int64 { // End implements autoid.Allocator End interface. func (alloc *allocator) End() int64 { + alloc.mu.Lock() + defer alloc.mu.Unlock() return alloc.end } From 9c2f2be355a6eb4a0bd63421c3d6551740fb59fb Mon Sep 17 00:00:00 2001 From: Dousir9 <736191200@qq.com> Date: Mon, 16 Jan 2023 22:12:56 +0800 Subject: [PATCH 3/3] add unit test --- meta/autoid/autoid_test.go | 55 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/meta/autoid/autoid_test.go b/meta/autoid/autoid_test.go index 16cfc7c64ac1c..b414378beea66 100644 --- a/meta/autoid/autoid_test.go +++ b/meta/autoid/autoid_test.go @@ -20,6 +20,7 @@ import ( "math" "math/rand" "sync" + "sync/atomic" "testing" "time" @@ -593,3 +594,57 @@ func TestAllocComputationIssue(t *testing.T) { require.Equal(t, int64(7), min) require.Equal(t, int64(13), max) } + +func TestIssue40584(t *testing.T) { + store, err := mockstore.NewMockStore() + require.NoError(t, err) + defer func() { + err := store.Close() + require.NoError(t, err) + }() + + ctx := kv.WithInternalSourceType(context.Background(), kv.InternalTxnMeta) + err = kv.RunInNewTxn(ctx, store, false, func(ctx context.Context, txn kv.Transaction) error { + m := meta.NewMeta(txn) + err = m.CreateDatabase(&model.DBInfo{ID: 1, Name: model.NewCIStr("a")}) + require.NoError(t, err) + err = m.CreateTableOrView(1, &model.TableInfo{ID: 1, Name: model.NewCIStr("t")}) + require.NoError(t, err) + return nil + }) + require.NoError(t, err) + + alloc := autoid.NewAllocator(store, 1, 1, false, autoid.RowIDAllocType) + require.NotNil(t, alloc) + + finishAlloc := make(chan bool) + finishBase := make(chan bool) + var done int32 = 0 + + // call allocator.Alloc and allocator.Base in parallel for 3 seconds to detect data race + go func() { + for { + alloc.Alloc(ctx, 1, 1, 1) + if atomic.LoadInt32(&done) > 0 { + break + } + } + finishAlloc <- true + }() + + go func() { + for { + alloc.Base() + if atomic.LoadInt32(&done) > 0 { + break + } + } + finishBase <- true + }() + + runTime := time.NewTimer(time.Second * 3) + <-runTime.C + atomic.AddInt32(&done, 1) + <-finishAlloc + <-finishBase +}