pingcap / pingcap/tidb

[import] Classic IMPORT INTO can report success with an empty unique index after concurrent ADD INDEX

Open
#70,107 1 comment 0 reactions 0 assignees View on GitHub
component/import found-by-ai may-affects-7.5 may-affects-8.1 may-affects-8.5 severity/moderate type/bug
Dominant language
Go
Stars
40.5k
Forks
6.2k
PR merge metrics
PR metrics pending

Description

## Bug Report

### 1. Minimal reproduce step (Required)

**Environment**

TiDB master 05b396fb66; Classic kernel

**Steps**

Create empty t(id BIGINT PRIMARY KEY, v BIGINT NOT NULL). Start IMPORT INTO from a large object prefix or directory so file discovery is in progress. After target resolution but before TableMode acquisition, run ALTER TABLE t ADD UNIQUE INDEX kv(v) in another session. Let import finish, compare USE INDEX() and FORCE INDEX(kv), insert a duplicate v, and run ADMIN CHECK TABLE. The stored real-TiKV test models discovery with 60,000 unrelated files and reproduced 3/3.

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

TableMode acquisition must atomically validate that the current target identity and schema generation equal the schema captured by the import plan. A successful import must populate every current public index and preserve unique constraints.

### 3. What did you see instead? (Required)

The DDL and import both succeed and the job is finished. The record scan returns three imported rows, FORCE INDEX(kv) returns zero, the default required checksum logs checksum pass, INSERT (4,101) succeeds despite existing imported (1,101), and ADMIN CHECK TABLE returns error 8223.

### 4. What is your TiDB version? (Required)

TiDB master 05b396fb66; Classic kernel

Likely root cause and fix direction

**Likely root cause**

IMPORT INTO skips statement MDL and copies tbl.Meta() into its plan before file discovery and prechecks. Classic TableModeImport is acquired only during task submission and blocks future changes, but does not compare the current schema with the captured schema. Workers therefore encode with stale TableInfo. A completely missing current index contributes zero to the remote checksum, matching the stale row-only local checksum.

**Fix direction**

Atomically compare an expected schema token while transitioning Normal to Import mode, then submit workers only after the claim succeeds. Abort or rebuild schema-dependent state on mismatch. Also make terminal validation require closure for every public index in the current schema.

Contributor guide

Open the contributing guide

Research direction

Start by tracing Classic TableModeImport acquisition during IMPORT INTO task submission, then inspect how the captured TableInfo reaches workers after file discovery. Reproduce the concurrent ADD INDEX case with the described large-prefix or 60,000-file setup; done means the import rejects or safely handles schema changes and terminal validation covers every current public index.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, sql
Domain
databases, distributed-systems
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.