Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RC transactions may see inconsistent data when there are concurrent DDLs #21498

Closed
MyonKeminta opened this issue Dec 4, 2020 · 7 comments · Fixed by #22152
Closed

RC transactions may see inconsistent data when there are concurrent DDLs #21498

MyonKeminta opened this issue Dec 4, 2020 · 7 comments · Fixed by #22152
Assignees
Labels
severity/critical sig/transaction SIG:Transaction type/bug The issue is confirmed as a bug.

Comments

@MyonKeminta
Copy link
Contributor

MyonKeminta commented Dec 4, 2020

Bug Report

The reason: In the current implementation of RC transaction, it fetches a latest ts to read data for each read statement. However it always uses the schema at the transaction's startTS (if I'm correct). So if the schema changed while the transaction is running, the transaction may see data that doesn't match the definition of the schema.

1. Minimal reproduce step (Required)

There may be various cases. Here are two examples.

Case 1: RC transaction uses IndexReader when the index is dropped and before GC.

create table t (id int primary key, v int, index iv (v));
insert into t values (1, 10), (2, 20), (3, 30), (4, 40);
session1 session2 result
set transaction isolation level read committed; begin;
explain select * from t where v = 10; IndexReader/IndexRangeScan
select * from t where v = 10; (1, 10)
alter table t drop index iv;
update t set v = 11 where id = 1;
explain select * from t where v = 10; IndexReader/IndexRangeScan
select * from t where v = 10; (1, 10)
select * from t where id = 1; (1, 11)

Case 2: RC transactionuses IndexLookup when the index is dropped and before GC.

create table t (id int primary key, v int, index iv (v), v2 int);
insert into t values (1, 10, 100), (2, 20, 200), (3, 30, 300), (4, 40, 400);
session1 session2 result
set transaction isolation level read committed; begin;
select * from t use index (iv) where v = 10; (1, 10, 100)
alter table t drop index iv;
update t set v = 11 where id = 1;
select * from t use index (iv) where v = 10; (1, 11, 100)
update t set id = 5 where id = 1;
select * from t use index (iv) where v = 10; ERROR 1105 (HY000): inconsistent index iv handle count 1 isn't equal to value count 0

2. What did you expect to see? (Required)

For case 1, there last select * from t where v = 10; should return empty result;
For case 2, session 1 should be able to use index (iv) in the last query

3. What did you see instead (Required)

As listed in the table above.

4. What is your TiDB version? (Required)

master (3a32bd2), compiled with fail point (but not used)

@you06
Copy link
Contributor

you06 commented Dec 11, 2020

Here are some cases in RR.

  • Update
/* init */ drop table if exists t;
/* init */ create table t (id int primary key, v int, unique index iv (v), v2 int);
/* init */ insert into t values (1, 10, 100), (2, 20, 200);

/* t1 */ set tx_isolation = 'REPEATABLE-READ';
/* t1 */ set tidb_enable_amend_pessimistic_txn=1;

/* t1 */ begin pessimistic;

/* t2 */ alter table t drop index iv;
/* t2 */ update t set v = 11 where v = 10;

/* t1 */ update t set v = 12 where v = 11; -- 0 rows affected, expect 1
/* t1 */ update t set v2 = 201 where id = 2; -- 0 related schema will let txn fail
/* t1 */ commit;

/* init */ select * from t; -- got (1, 11, 100), (2, 20, 201), expect (1, 12, 100), (2, 20, 201)
  • Delete
/* init */ drop table if exists t;
/* init */ create table t (id int primary key, v int, unique index iv (v), v2 int);
/* init */ insert into t values (1, 10, 100), (2, 20, 200);

/* t1 */ set tx_isolation = 'REPEATABLE-READ';
/* t1 */ set tidb_enable_amend_pessimistic_txn=1;

/* t1 */ begin pessimistic;

/* t2 */ alter table t drop index iv;
/* t2 */ update t set v = 11 where v = 10;

/* t1 */ delete from t where v = 11; -- 0 rows affected, expect 1
/* t1 */ update t set v2 = 201 where id = 2; -- 0 related schema will let txn fail
/* t1 */ commit;

/* init */ select * from t; -- got (1, 11, 100), (2, 20, 201), expect (2, 20, 201)
  • Select inside Insert
/* init */ drop table if exists t;
/* init */ create table t (id int primary key, v int, unique index iv (v), v2 int);
/* init */ insert into t values (1, 10, 100), (2, 20, 200);

/* t1 */ set tx_isolation = 'REPEATABLE-READ';
/* t1 */ set tidb_enable_amend_pessimistic_txn=1;

/* t1 */ begin pessimistic;

/* t2 */ alter table t drop index iv;
/* t2 */ update t set v = 11 where v = 10;

/* t1 */ insert into t(id, v, v2) select 3 * id, 3 * v, 3 * v2 from t where v = 11; -- 0 rows affected, expect 1
/* t1 */ update t set v2 = 201 where id = 2; -- 0 related schema will let txn fail
/* t1 */ commit;

/* init */ select * from t; -- got (1, 11, 100), (2, 20, 201), expect (1, 11, 100), (2, 20, 201), (3, 33, 300)

@you06
Copy link
Contributor

you06 commented Dec 21, 2020

  • Select from another table inside Insert
/* init */ drop table if exists t, t1;
/* init */ create table t (id int primary key, v int, unique index iv (v), v2 int);
/* init */ create table t1 (id int primary key, v int, v2 int);
/* init */ insert into t values (1, 10, 100), (2, 20, 200);

/* t1 */ set tx_isolation = 'REPEATABLE-READ';
/* t1 */ set tidb_enable_amend_pessimistic_txn=1;

/* t1 */ begin pessimistic;

/* t2 */ alter table t drop index iv;
/* t2 */ update t set v = 11 where v = 10;
/* t2 */ update t set v = 21 where v = 20;

/* t1 */ insert into t1(id, v, v2) select * from t where v = 11; -- 0 rows affected, expect 1
/* t1 */ insert into t1(id, v, v2) select * from t where v = 20; -- 1 rows affected, expect 0
/* t1 */ commit;

/* init */ select * from t1; -- got (2, 21, 200)?!, expect (1, 11, 100)

@you06
Copy link
Contributor

you06 commented Dec 24, 2020

The patch has been included in release-4.0.

@you06
Copy link
Contributor

you06 commented Dec 24, 2020

/unassign

@cfzjywxk
Copy link
Contributor

For release-4.0 a temporary solution is used to solve this proble in #21596. For v5.0 and the master branch, a complete solution is needed, it's still under discussion.

@cfzjywxk
Copy link
Contributor

cfzjywxk commented Jan 7, 2021

Currently we still consider using the temporary solution to on the master branch.

@ti-srebot
Copy link
Contributor

ti-srebot commented Jan 12, 2021

Please edit this comment or add a new comment to complete the following information

Not a bug

  1. Remove the 'type/bug' label
  2. Add notes to indicate why it is not a bug

Duplicate bug

  1. Add the 'type/duplicate' label
  2. Add the link to the original bug

Bug

Note: Make Sure that 'component', and 'severity' labels are added
Example for how to fill out the template: #20100

1. Root Cause Analysis (RCA) (optional)

ForUpdateRead will use schema of snapshotTS to read data with a newer version.

2. Symptom (optional)

When amend transaction is off in RR isolation level, there will be inconsistency inside a transaction, but it'll fail when committing.

When amend transaction is on or the isolation level is RC, there will be incorrect data.

3. All Trigger Conditions (optional)

4. Workaround (optional)

5. Affected versions

[v4.0.1:v4.0.9]

6. Fixed versions

v4.0.10, master

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
severity/critical sig/transaction SIG:Transaction type/bug The issue is confirmed as a bug.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants