From 5c7aba6bf0702cc3825514866f5771d0138fe468 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 1f5ffeb2fd094..8a92fb195c8cd 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 43b1dac86ccf287c2a99b42b0842107331325053 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 8a92fb195c8cd..8c5e1d7bc58d8 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 ec518cf926c8d5389ade5874b423683e7b2031b3 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 +}