pingcap / pingcap/tidb

ddl: region pre-split paths mishandle scatter scope and global group IDs

Open
#70,945 0 comments 0 reactions 0 assignees View on GitHub
affects-9.0 component/ddl severity/moderate type/bug
Dominant language
Go
Stars
40.5k
Forks
6.2k
PR merge metrics
PR metrics pending

Description

## Bug Report

Please answer these questions before submitting the issue. Thanks!

### 1. Minimal reproduce step (Required)

Two existing Region pre-split paths mishandle `tidb_scatter_region`. Both are already reachable with `split-table = true`; enabling explicit split configuration when `split-table = false` also exposes them.

#### Case 1: partition pre-split confuses the global scatter group with a physical table ID

Start TiDB with a storage engine that supports Region splitting, then run:

```sql
SET SESSION tidb_scatter_region = 'global';

CREATE TABLE p (
a BIGINT,
b BIGINT,
KEY li(a),
UNIQUE KEY gi(b) GLOBAL
) SHARD_ROW_ID_BITS = 2 PRE_SPLIT_REGIONS = 2
PARTITION BY HASH(a) PARTITIONS 2;
```

Inspect the Region split requests or resulting PD Region boundaries. In `splitPartitionTableRegion`, `getScatterConfig(..., 'global')` returns `GlobalScatterGroupID` (`-1`), which is then passed to `splitIndexRegion` as its `physicalTableID` argument.

#### Case 2: persistent split policies use the DDL worker session's scatter scope

On a cluster with multiple TiKV stores, run:

```sql
SET SESSION tidb_scatter_region = 'table';

CREATE TABLE t (a BIGINT PRIMARY KEY);
ALTER TABLE t SPLIT BETWEEN (0) AND (10000) REGIONS 4;
SHOW TABLE t REGIONS;
```

Inspect the `LEADER_STORE_ID` values and PD scatter requests immediately after the DDL. The same problem affects policy reapplication during `TRUNCATE TABLE`, `ADD PARTITION`, and `TRUNCATE PARTITION`.

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

- Case 1: index split keys use the real logical/physical table IDs, while every split request uses global scatter group `-1` only as its scatter-group ID. Global indexes are included and no split key is created under table ID `-1`.
- Case 2: the `tidb_scatter_region` value captured from the submitting session in the DDL job is used by all policy split requests. `table` and `global` should schedule the corresponding PD scatter operations.

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

- Case 1: `splitPartitionTableRegion` passes the global scatter-group ID `-1` as `splitIndexRegion`'s physical table ID. This skips global indexes, selects local indexes, and encodes spurious local-index split keys under table ID `-1`. For nonpartitioned tables, index keys are correct but index Regions use the physical table ID as their scatter group instead of global group `-1`.
- Case 2: worker-side policy operations recover the correct scope from the DDL job for the outer synchronous/wait decision, but `applySplitPoliciesForTable` ignores it and reads `ScatterRegion` from the internal pooled DDL session. A session-level `table` or `global` request therefore normally calls `SplitRegions` with `scatter=false`; the outer path can still wait as if scattering had been requested.

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

Reproduced by code inspection on current master / PR #70919:

```text
v9.0.0-beta.2.pre-2204-g20a593131d
```

The defects predate PR #70919:

- Case 1 traces to `9971301fbc3991528d2c11aed87151171f7df5ac` (`ddl: let partition table pre split index regions`, #59547).
- Case 2 traces to `35d50f2b1277c3eb6280e84d923a46fb2a627a4d` (`ddl: support region split policy`, #65133).

### Analysis

- `splitIndexRegion` currently uses one integer for both physical key encoding/index selection and the scatter-group ID. These values must be passed separately.
- `applySplitPoliciesForTable` should receive the captured `scatterScope` explicitly instead of consulting the DDL worker session.
- Existing Region-count tests do not validate the split keys, PD scatter flag, or scatter group, so both problems can pass while producing the requested number of Regions.

Contributor guide

Open the contributing guide

Research direction

Start with splitPartitionTableRegion and splitIndexRegion to trace physical table IDs separately from scatter-group IDs, then inspect applySplitPoliciesForTable and the existing Region-count tests. Verify the partition and persistent-policy paths, including TRUNCATE and ADD PARTITION cases, by checking split keys, PD scatter flags, scatter groups, and the captured session scope.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, sql
Domain
databases, distributed-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
64/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.