Skip to content

ddl: extract add-index KV generation helper#69706

Open
expxiaoli wants to merge 2 commits into
pingcap:masterfrom
expxiaoli:tikv_precheck_PR_helper
Open

ddl: extract add-index KV generation helper#69706
expxiaoli wants to merge 2 commits into
pingcap:masterfrom
expxiaoli:tikv_precheck_PR_helper

Conversation

@expxiaoli

@expxiaoli expxiaoli commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: ref #68354

Problem Summary:

This PR is split from #68490.

The add-index backfill path already has logic for generating index KVs, including multi-valued indexes, global indexes, partial indexes, and common-handle restored data. Future prediction/precheck logic needs to reuse the same behavior instead of reimplementing another index KV generation path.

What changed and how does it work?

This PR extracts helper logic for add-index KV generation with minimal behavior change:

  • Extract generateIndexKVsForRow so follow-up TiKV precheck PRs can generate sampled index KVs through the same path as real add-index backfill.
  • Add EncodeRawIndexKeyValues so follow-up TiKV precheck PRs can encode raw index key suffixes in the same value order as index KV generation.

Check List

Tests

  • Unit test
  • Integration test
  • Manual test (add detailed scripts or steps below)
  • No need to test
GOPATH="$HOME/go" GOSUMDB=sum.golang.org make bazel_prepare
GOPATH="$HOME/go" GOSUMDB=sum.golang.org ./tools/check/failpoint-go-test.sh pkg/table/tables -run 'Test(EncodeRawIndexKeyValues|TryGetHandleRestoredData)$' -count=1
GOPATH="$HOME/go" GOSUMDB=sum.golang.org ./tools/check/failpoint-go-test.sh pkg/ddl -run '^$' -count=1
GOPATH="$HOME/go" GOSUMDB=sum.golang.org make lint
git diff --check

Side effects

  • Performance regression: Consumes more CPU
  • Performance regression: Consumes more Memory
  • Breaking backward compatibility

Documentation

  • Affects user behaviors
  • Contains syntax changes
  • Contains variable changes
  • Contains experimental features
  • Changes MySQL compatibility

Release note

None

Summary by CodeRabbit

  • New Features

    • Index key generation now supports more consistent handling of global indexes and partition-aware handles.
    • Added support for generating raw index key values from indexed data, including multi-value array indexes.
  • Bug Fixes

    • Improved index backfilling to use the correct table identifier during chunk processing.
    • Multi-value index expansion now follows the expected column metadata when building index values.
  • Tests

    • Added coverage for raw index key generation and handle wrapping behavior.

@ti-chi-bot ti-chi-bot Bot added do-not-merge/needs-linked-issue release-note-none Denotes a PR that doesn't merit a release note. do-not-merge/needs-triage-completed size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. labels Jul 7, 2026
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds generateIndexKVsForRow and indexKVHandleForPhysicalTable to centralize per-row index KV generation and global-index handle wrapping in writeChunk/writeOneKV, threading a new physicalID parameter through the call chain. Also extracts BuildMultiValueIndexValueGroups and adds EncodeRawIndexKeyValues in pkg/table/tables/index.go, with accompanying tests and a Bazel shard-count bump.

Changes

DDL index backfill KV generation

Layer / File(s) Summary
Per-row KV generation helpers
pkg/ddl/index.go
Adds generateIndexKVsForRow to abstract partial-index filtering, indexed-value extraction, restore-data selection, handle wrapping, and KV writing; adds indexKVHandleForPhysicalTable to wrap/unwrap global index handles at GlobalIndexVersionV1+.
writeChunk/writeOneKV wiring
pkg/ddl/index.go, pkg/ddl/backfilling_operators.go
writeChunk gains a physicalID parameter and delegates its per-index loop to generateIndexKVsForRow; writeOneKV now consumes a pre-built iterator/handle instead of constructing one internally; indexIngestWorker.WriteChunk passes w.tbl.GetPhysicalID().
Global handle test
pkg/ddl/reorg_util_test.go
Adds a test validating indexKVHandleForPhysicalTable wraps a global index handle into a non-nested kv.PartitionHandle.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Multi-value index helper extraction

Layer / File(s) Summary
MV index expansion helpers and encoding
pkg/table/tables/index.go, pkg/table/tables/index_test.go, pkg/table/tables/BUILD.bazel
Extracts BuildMultiValueIndexValueGroups from getIndexedValue, adds EncodeRawIndexKeyValues for truncated/encoded raw index keys, adds TestEncodeRawIndexKeyValues, and bumps test shard count from 44 to 45.

Estimated code review effort: 2 (Simple) | ~15 minutes

Possibly related PRs

  • pingcap/tidb#68831: Both touch the partial-index predicate path used by indexConditionCheckers in writeChunk.
  • pingcap/tidb#69658: Both modify writeChunk, writeOneKV, and global-index handle wrapping logic in pkg/ddl/index.go.
  • pingcap/tidb#69702: Both change the writeChunk signature/logic in the same reorg/backfill KV path with different added parameters.

Suggested labels: approved, lgtm

Suggested reviewers: D3Hunter, wjhuang2016, GMHDBJD

Poem

A hop, a skip, a KV byte,
Handles wrapped both snug and tight,
Partial indexes checked with care,
Multi-value groups expanded fair,
Forty-five shards now stand in line —
This burrow's code is looking fine! 🐇✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is concise and accurately summarizes the main refactor in this PR.
Description check ✅ Passed The description follows the template and includes the issue link, problem summary, changes, tests, side effects, and release note.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jul 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 6.41026% with 73 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.8452%. Comparing base (09d2140) to head (0861e8f).
⚠️ Report is 7 commits behind head on master.

Additional details and impacted files
@@               Coverage Diff                @@
##             master     #69706        +/-   ##
================================================
- Coverage   76.3227%   75.8452%   -0.4775%     
================================================
  Files          2041       2078        +37     
  Lines        560399     582317     +21918     
================================================
+ Hits         427712     441660     +13948     
- Misses       131786     138096      +6310     
- Partials        901       2561      +1660     
Flag Coverage Δ
integration 45.7800% <6.4102%> (+6.0748%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
dumpling 60.4471% <ø> (ø)
parser ∅ <ø> (∅)
br 63.7469% <ø> (+1.0255%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
pkg/table/tables/mutation_checker_test.go (1)

403-440: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider covering the other branches of TryGetHandleRestoredData.

This test only exercises the "column needs restored data, no matching secondary-index column" path. The function has two other notable branches that remain untested: the SetNull path (when NeedRestoredDataWithCollate is false for a PK column) and the bin-collation tail-space-count conversion path (ConvertDatumToTailSpaceCount), plus the truncation path where idx actually shares a column with pkIdx (exercising maxIndexLen). Given this helper now has a wider blast radius (called directly from DDL index KV generation, not just through the wrapper), broader coverage would help catch regressions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/table/tables/mutation_checker_test.go` around lines 403 - 440, Expand
TestTryGetHandleRestoredData to cover the remaining TryGetHandleRestoredData
branches: add cases where NeedRestoredDataWithCollate is false so the SetNull
path is exercised, where a PK column uses bin collation so
ConvertDatumToTailSpaceCount is covered, and where the secondary index shares a
column with the PK index so the maxIndexLen truncation path runs. Use
TryGetHandleRestoredData, FindPrimaryIndex, and the existing tableInfo/index
setup as anchors when adding the new assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/ddl/index.go`:
- Around line 2742-2748: The handling in indexKVHandleForPhysicalTable should
always rebuild the kv.PartitionHandle for V1 global indexes using the current
physicalID instead of trusting an existing PartitionHandle. Update the logic in
indexKVHandleForPhysicalTable so that when the input handle is already a
kv.PartitionHandle, you unwrap its inner handle and create a new
kv.NewPartitionHandle with physicalID, ensuring reused or decoded handles cannot
preserve a stale partition ID.

In `@pkg/table/tables/tables.go`:
- Around line 1787-1815: TryGetHandleRestoredData is mutating the shared
restored-handle buffer that generateIndexKVsForRow reuses across indexes, so
later indexes in the same row can see truncated or null-marked values from
earlier ones. Fix this by avoiding in-place modification of the input slice:
either clone handleDts at the start of TryGetHandleRestoredData before calling
TryTruncateRestoredData and ConvertDatumToTailSpaceCount, or copy the buffer at
the generateIndexKVsForRow call site so each index works on its own
restored-handle data. Keep the behavior of needHandleRestoredData and the
returned filtered slice unchanged.

---

Nitpick comments:
In `@pkg/table/tables/mutation_checker_test.go`:
- Around line 403-440: Expand TestTryGetHandleRestoredData to cover the
remaining TryGetHandleRestoredData branches: add cases where
NeedRestoredDataWithCollate is false so the SetNull path is exercised, where a
PK column uses bin collation so ConvertDatumToTailSpaceCount is covered, and
where the secondary index shares a column with the PK index so the maxIndexLen
truncation path runs. Use TryGetHandleRestoredData, FindPrimaryIndex, and the
existing tableInfo/index setup as anchors when adding the new assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 5cc96f35-39d5-49ec-879f-79f2094e0328

📥 Commits

Reviewing files that changed from the base of the PR and between cd225b6 and d1effb2.

📒 Files selected for processing (8)
  • pkg/ddl/backfilling_operators.go
  • pkg/ddl/index.go
  • pkg/ddl/index_cop.go
  • pkg/table/tables/BUILD.bazel
  • pkg/table/tables/index.go
  • pkg/table/tables/index_test.go
  • pkg/table/tables/mutation_checker_test.go
  • pkg/table/tables/tables.go
💤 Files with no reviewable changes (1)
  • pkg/ddl/index_cop.go

Comment thread pkg/ddl/index.go
Comment thread pkg/table/tables/tables.go Outdated
@expxiaoli

Copy link
Copy Markdown
Contributor Author

/retest-required

1 similar comment
@expxiaoli

Copy link
Copy Markdown
Contributor Author

/retest-required

@expxiaoli expxiaoli force-pushed the tikv_precheck_PR_helper branch from 0d2840b to ded1ed2 Compare July 7, 2026 11:28

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
pkg/executor/admin.go (1)

407-414: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Hoist invariant lookups out of the per-row loop.

tblInfo, e.table.UseNewCollate(), and tables.FindPrimaryIndex(tblInfo) don't change across rows/chunks within fetchRecoverRows, yet they're recomputed on every row iteration. FindPrimaryIndex scans the table's indices, so this is unnecessary repeated work in what can be a large batch-processing loop.

♻️ Proposed refactor: compute once outside the loop
 func (e *RecoverIndexExec) fetchRecoverRows(ctx context.Context, srcResult distsql.SelectResult, result *backfillResult) ([]recoverRows, error) {
 	e.recoverRows = e.recoverRows[:0]
 	idxValLen := len(e.index.Meta().Columns)
 	result.scanRowCount = 0
+	tblInfo := e.table.Meta()
+	useNewCollate := e.table.UseNewCollate()
+	pkIdx := tables.FindPrimaryIndex(tblInfo)
 
 	for {
 		...
 			e.idxValsBufs[result.scanRowCount] = idxVals
-			tblInfo := e.table.Meta()
 			rsData := tables.TryGetHandleRestoredData(
-				e.table.UseNewCollate(),
-				tblInfo,
-				tables.FindPrimaryIndex(tblInfo),
+				useNewCollate,
+				tblInfo,
+				pkIdx,
 				plannercore.GetCommonHandleDatum(e.handleCols, row),
 				e.index.Meta(),
 			)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/executor/admin.go` around lines 407 - 414, Hoist the invariant table
metadata lookups out of the per-row loop in fetchRecoverRows: tblInfo,
e.table.UseNewCollate(), and tables.FindPrimaryIndex(tblInfo) are constant
across iterations and should be computed once before processing rows/chunks. Use
the existing fetchRecoverRows flow and the tblInfo /
tables.TryGetHandleRestoredData call site to move those values into local
variables outside the loop, then reuse them for each row.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@pkg/executor/admin.go`:
- Around line 407-414: Hoist the invariant table metadata lookups out of the
per-row loop in fetchRecoverRows: tblInfo, e.table.UseNewCollate(), and
tables.FindPrimaryIndex(tblInfo) are constant across iterations and should be
computed once before processing rows/chunks. Use the existing fetchRecoverRows
flow and the tblInfo / tables.TryGetHandleRestoredData call site to move those
values into local variables outside the loop, then reuse them for each row.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 5e197e82-7aca-4567-b149-c9fb5c70d3cc

📥 Commits

Reviewing files that changed from the base of the PR and between 0d2840b and ded1ed2.

📒 Files selected for processing (10)
  • pkg/ddl/backfilling_operators.go
  • pkg/ddl/index.go
  • pkg/ddl/index_cop.go
  • pkg/ddl/reorg_util_test.go
  • pkg/executor/admin.go
  • pkg/table/tables/BUILD.bazel
  • pkg/table/tables/index.go
  • pkg/table/tables/index_test.go
  • pkg/table/tables/mutation_checker_test.go
  • pkg/table/tables/tables.go
💤 Files with no reviewable changes (1)
  • pkg/ddl/index_cop.go
✅ Files skipped from review due to trivial changes (1)
  • pkg/table/tables/BUILD.bazel
🚧 Files skipped from review as they are similar to previous changes (7)
  • pkg/ddl/reorg_util_test.go
  • pkg/table/tables/index_test.go
  • pkg/table/tables/index.go
  • pkg/ddl/index.go
  • pkg/ddl/backfilling_operators.go
  • pkg/table/tables/mutation_checker_test.go
  • pkg/table/tables/tables.go

@expxiaoli

Copy link
Copy Markdown
Contributor Author

/retest-required

Comment thread pkg/table/tables/tables.go Outdated
}

// TryGetHandleRestoredData returns restored common-handle data if needed.
func TryGetHandleRestoredData(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why ddl space precheck feature need to change this part? why not directly check the encoded KV size

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Directly checking encoded KV size will miss restored handle data for common handle and new collation indexes. Reusing the add-index KV helper keeps precheck and real backfill using the same encoding path.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kv size already include them

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I check the following split PR, TryGetHandleRestoredData is not required for the KV helper extraction. I will remove this helper to keep this PR clean.

@ti-chi-bot ti-chi-bot Bot removed the size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. label Jul 8, 2026
@ti-chi-bot

ti-chi-bot Bot commented Jul 8, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign djshow832 for approval. For more information see the Code Review Process.
Please ensure that each of them provides their approval before proceeding.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@ti-chi-bot ti-chi-bot Bot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Jul 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release-note-none Denotes a PR that doesn't merit a release note. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants