From d16237a3df4749d937fafdd7abe029597205f89b 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 aba2ad565b617..fe83ad2019f30 100644 --- a/meta/autoid/autoid.go +++ b/meta/autoid/autoid.go @@ -285,6 +285,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 3bcea04a1322cd8ab297db4e0be9e85b756adcdf 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 fe83ad2019f30..5d77fbbb46d1e 100644 --- a/meta/autoid/autoid.go +++ b/meta/autoid/autoid.go @@ -292,6 +292,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 8f5278687df5a79eb4bab84758eb6815190b6619 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 0b8cd60257cf4..912b1e173bc8c 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" @@ -594,3 +595,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 +}