Skip to content

Commit 166b3f0

Browse files
committed
fix the issue that INSERT IGNORE doesn't lock the parent table
Signed-off-by: Yang Keao <[email protected]>
1 parent 7599574 commit 166b3f0

File tree

3 files changed

+45
-8
lines changed

3 files changed

+45
-8
lines changed

pkg/executor/foreign_key.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ func (fkc *FKCheckExec) doCheck(ctx context.Context) error {
223223
fkc.stats = &FKCheckRuntimeStats{}
224224
defer fkc.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(fkc.ID(), fkc.stats)
225225
}
226-
if len(fkc.toBeCheckedKeys) == 0 && len(fkc.toBeCheckedPrefixKeys) == 0 {
226+
if len(fkc.toBeCheckedKeys) == 0 && len(fkc.toBeCheckedPrefixKeys) == 0 && len(fkc.toBeLockedKeys) == 0 {
227227
return nil
228228
}
229229
start := time.Now()
@@ -248,6 +248,7 @@ func (fkc *FKCheckExec) doCheck(ctx context.Context) error {
248248
if fkc.stats != nil {
249249
fkc.stats.Check = time.Since(start)
250250
}
251+
251252
if len(fkc.toBeLockedKeys) == 0 {
252253
return nil
253254
}
@@ -263,9 +264,6 @@ func (fkc *FKCheckExec) doCheck(ctx context.Context) error {
263264
// doLockKeys may set TxnCtx.ForUpdate to 1, then if the lock meet write conflict, TiDB can't retry for update.
264265
// So reset TxnCtx.ForUpdate to 0 then can be retry if meet write conflict.
265266
atomic.StoreUint32(&sessVars.TxnCtx.ForUpdate, forUpdate)
266-
if fkc.stats != nil {
267-
fkc.stats.Lock = time.Since(start) - fkc.stats.Check
268-
}
269267
return err
270268
}
271269

@@ -542,7 +540,7 @@ type fkCheckKey struct {
542540
isPrefix bool
543541
}
544542

545-
func (fkc FKCheckExec) checkRows(ctx context.Context, sc *stmtctx.StatementContext, txn kv.Transaction, rows []toBeCheckedRow) error {
543+
func (fkc *FKCheckExec) checkRows(ctx context.Context, sc *stmtctx.StatementContext, txn kv.Transaction, rows []toBeCheckedRow) error {
546544
if fkc.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl != nil {
547545
fkc.stats = &FKCheckRuntimeStats{}
548546
defer fkc.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(fkc.ID(), fkc.stats)

pkg/executor/test/fktest/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ go_test(
88
"main_test.go",
99
],
1010
flaky = True,
11-
shard_count = 25,
11+
shard_count = 26,
1212
deps = [
1313
"//pkg/config",
1414
"//pkg/executor",

pkg/executor/test/fktest/foreign_key_test.go

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2088,8 +2088,8 @@ func TestExplainAnalyzeDMLWithFKInfo(t *testing.T) {
20882088
{
20892089
sql: "explain analyze insert ignore into t6 values (1,1,10)",
20902090
plan: "Insert_.* root time:.* loops:.* prepare:.* check_insert.* fk_check:.*" +
2091-
"├─Foreign_Key_Check.* 0 root table:t5 total:0s, foreign_keys:1 foreign_key:fk_1, check_exist N/A N/A.*" +
2092-
"├─Foreign_Key_Check.* 0 root table:t5, index:idx2 total:0s, foreign_keys:1 foreign_key:fk_2, check_exist N/A N/A.*" +
2091+
"├─Foreign_Key_Check.* 0 root table:t5 total:.*, lock:.*, foreign_keys:1 foreign_key:fk_1, check_exist N/A N/A.*" +
2092+
"├─Foreign_Key_Check.* 0 root table:t5, index:idx2 total:.*, lock:.*, foreign_keys:1 foreign_key:fk_2, check_exist N/A N/A.*" +
20932093
"└─Foreign_Key_Check.* 0 root table:t5, index:idx3 total:0s, foreign_keys:1 foreign_key:fk_3, check_exist N/A N/A",
20942094
},
20952095
{
@@ -2494,3 +2494,42 @@ func TestFKBuild(t *testing.T) {
24942494
tk.MustExec("delete from test.t3")
24952495
tk.MustQuery("select * from test.t2").Check(testkit.Rows())
24962496
}
2497+
2498+
func TestLockKeysInInsertIgnore(t *testing.T) {
2499+
store := realtikvtest.CreateMockStoreAndSetup(t)
2500+
tk := testkit.NewTestKit(t, store)
2501+
tk.MustExec("use test")
2502+
tk.MustExec("create table t1 (id int primary key);")
2503+
tk.MustExec("create table t2 (id int primary key, foreign key fk (id) references t1(id));")
2504+
tk.MustExec("insert into t1 values (1)")
2505+
2506+
tk.MustExec("BEGIN")
2507+
tk.MustExec("INSERT IGNORE INTO t2 VALUES (1)")
2508+
2509+
var wg sync.WaitGroup
2510+
var tk2CommitTime time.Time
2511+
tk2StartTime := time.Now()
2512+
wg.Add(1)
2513+
go func() {
2514+
defer wg.Done()
2515+
2516+
tk2 := testkit.NewTestKit(t, store)
2517+
// unistore has a bug to handle the fair locking mechanism. We need to disable it to pass this test.
2518+
// Ref: https://github.com/pingcap/tidb/issues/56663
2519+
tk2.MustExec("set tidb_pessimistic_txn_fair_locking = 'OFF'")
2520+
tk2.MustExec("use test")
2521+
tk2.MustExec("BEGIN")
2522+
require.NotNil(t, tk2.ExecToErr("UPDATE t1 SET id = 2 WHERE id = 1"))
2523+
tk2.MustExec("COMMIT")
2524+
tk2CommitTime = time.Now()
2525+
}()
2526+
2527+
sleepDuration := 500 * time.Millisecond
2528+
time.Sleep(sleepDuration)
2529+
tk.MustExec("COMMIT")
2530+
wg.Wait()
2531+
2532+
require.Greater(t, tk2CommitTime.Sub(tk2StartTime), sleepDuration)
2533+
tk.MustQuery("SELECT * FROM t1").Check(testkit.Rows("1"))
2534+
tk.MustQuery("SELECT * FROM t2").Check(testkit.Rows("1"))
2535+
}

0 commit comments

Comments
 (0)