[br] BR can restore into a concurrently created incompatible table and report success with a corrupted index
- Dominant language
- Go
- Stars
- 40.5k
- Forks
- 6.2k
- PR merge metrics
- PR metrics pending
Description
## Bug Report
### 1. Minimal reproduce step (Required)
**Environment**
master 05b396fb6636; verified BR a942e4684f43
**Steps**
Back up t(id PK,a,b,UNIQUE uk(a)). Drop t and start br restore table with default checkpoint mode. After the precheck has passed and checkpoint initialization begins, concurrently create t(id PK,a,b,UNIQUE uk(b)). Wait for BR success, then force uk for WHERE b=10 and run ADMIN CHECK TABLE.
### 2. What did you expect to see? (Required)
The restore must atomically claim the target table identity. If another actor creates the name after admission, BR must fail before generating rewrite rules or ingesting KVs unless the exact expected schema and identity are proven compatible.
### 3. What did you see instead? (Required)
Two independent runs exited 0, reported Table Restore success, and validated checksum. The table kept uk(b), but its restored index keys encoded backup column a. WHERE b=10 returned a row with b=100, WHERE b=100 returned no row, ADMIN CHECK returned 8223, and UPDATE ... WHERE b=10 successfully modified the b=100 row.
### 4. What is your TiDB version? (Required)
master 05b396fb6636; verified BR a942e4684f43
Likely root cause and fix direction
**Likely root cause**
checkTableExistence proves absence only at one InfoSchema snapshot. BR later calls BatchCreateTableWithInfo with OnExistIgnore, so a concurrent CREATE is treated as successful BR creation. SnapClient then reacquires the table by name, checks only IsCommonHandle, and GetIndexIDMap maps indexes solely by name before physical ingest.
**Fix direction**
Use an atomic target-name claim or make BR table creation fail on existence after the precheck. Bind every rewrite rule to the exact table ID created by BR. If idempotent reuse is required, compare a full restore-relevant schema fingerprint, including columns, types, defaults, generated expressions, primary handle, indexes, constraints, and special metadata, before ingest.
Contributor guide
Research direction
Trace checkTableExistence, BatchCreateTableWithInfo, SnapClient, and GetIndexIDMap through the BR restore path, then reproduce the concurrent CREATE scenario described above. Verify that an incompatible table cannot be claimed or ingested into, and that the restore fails without leaving mismatched index keys or reporting success.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- databases, distributed-systems
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100