Skip to content

Commit

Permalink
ddl, parser: fix concurrent rename table (pingcap#33354)
Browse files Browse the repository at this point in the history
  • Loading branch information
wjhuang2016 authored Apr 7, 2022
1 parent 1bb87b2 commit be76f88
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 16 deletions.
120 changes: 120 additions & 0 deletions ddl/db_change_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import (
"github.com/pingcap/tidb/util/admin"
"github.com/pingcap/tidb/util/gcutil"
"github.com/pingcap/tidb/util/sqlexec"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"go.uber.org/zap"
)
Expand Down Expand Up @@ -1991,3 +1992,122 @@ func (s *stateChangeSuite) TestRestrainDropColumnWithIndex() {
tk.MustExec("alter table t drop column a;")
tk.MustExec("drop table if exists t;")
}

func TestParallelRenameTable(t *testing.T) {
store, d, clean := testkit.CreateMockStoreAndDomain(t)
defer clean()
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("create database test2")
tk.MustExec("drop table if exists t")
tk.MustExec("create table t(a int default 0, b int default 0, key idx((b+1)))")
tk1 := testkit.NewTestKit(t, store)
tk1.MustExec("use test")
tk3 := testkit.NewTestKit(t, store)
tk3.MustExec("use test")

var concurrentDDLQueryPre string
var concurrentDDLQuery string
firstDDL := true

var wg sync.WaitGroup
var checkErr error
d2 := d.DDL()
originalCallback := d2.GetHook()
defer d2.SetHook(originalCallback)
callback := &ddl.TestDDLCallback{Do: d}
callback.OnJobRunBeforeExported = func(job *model.Job) {
switch job.SchemaState {
case model.StateNone:
if firstDDL {
firstDDL = false
} else {
return
}
wg.Add(1)
go func() {
if concurrentDDLQueryPre != "" {
wg.Add(1)
go func() {
// We assume that no error, we don't want to test it.
tk3.MustExec(concurrentDDLQueryPre)
wg.Done()
}()
time.Sleep(10 * time.Millisecond)
}
_, err := tk1.Exec(concurrentDDLQuery)
if err != nil {
checkErr = err
}
wg.Done()
}()
time.Sleep(10 * time.Millisecond)
}
}

d2.SetHook(callback)

// rename then add column
concurrentDDLQuery = "alter table t add column g int"
tk.MustExec("rename table t to t1")
wg.Wait()
require.Error(t, checkErr)
require.True(t, strings.Contains(checkErr.Error(), "Table 'test.t' doesn't exist"), checkErr.Error())
tk.MustExec("rename table t1 to t")
checkErr = nil

// rename then add column, but rename to other database
concurrentDDLQuery = "alter table t add column g int"
firstDDL = true
tk.MustExec("rename table t to test2.t1")
wg.Wait()
require.Error(t, checkErr)
// [schema:1146]Table '(Schema ID 1).(Table ID 65)' doesn't exist
require.True(t, strings.Contains(checkErr.Error(), "doesn't exist"), checkErr.Error())
tk.MustExec("rename table test2.t1 to test.t")
checkErr = nil

// rename then add column, but rename to other database and create same name table
concurrentDDLQuery = "alter table t add column g int"
firstDDL = true
tk.MustExec("rename table t to test2.t1")
concurrentDDLQueryPre = "create table t(a int)"
wg.Wait()
require.Error(t, checkErr)
// [schema:1146]Table '(Schema ID 1).(Table ID 65)' doesn't exist
require.True(t, strings.Contains(checkErr.Error(), "doesn't exist"), checkErr.Error())
tk.MustExec("rename table test2.t1 to test.t")
concurrentDDLQueryPre = ""
checkErr = nil

// rename then rename
concurrentDDLQuery = "rename table t to t2"
firstDDL = true
tk.MustExec("rename table t to t1")
wg.Wait()
require.Error(t, checkErr)
require.True(t, strings.Contains(checkErr.Error(), "Table 'test.t' doesn't exist"), checkErr.Error())
tk.MustExec("rename table t1 to t")
checkErr = nil

// rename then rename, but rename to other database
concurrentDDLQuery = "rename table t to t2"
firstDDL = true
tk.MustExec("rename table t to test2.t1")
wg.Wait()
require.Error(t, checkErr)
require.True(t, strings.Contains(checkErr.Error(), "doesn't exist"), checkErr.Error())
tk.MustExec("rename table test2.t1 to test.t")
checkErr = nil

// renames then add index on one table
tk.MustExec("create table t2(a int)")
tk.MustExec("create table t3(a int)")
concurrentDDLQuery = "alter table t add index(a)"
firstDDL = true
tk.MustExec("rename table t to tt, t2 to tt2, t3 to tt3")
wg.Wait()
require.Error(t, checkErr)
require.True(t, strings.Contains(checkErr.Error(), "Table 'test.t' doesn't exist"), checkErr.Error())
tk.MustExec("rename table tt to t")
}
Loading

0 comments on commit be76f88

Please sign in to comment.