Skip to content

Hotfix/hf 1059/v6.5.6 - #70375

Open
lichunzhu wants to merge 23 commits into
pingcap:release-6.5-20231229-v6.5.6from
lichunzhu:hotfix/HF-1059/v6.5.6
Open

Hotfix/hf 1059/v6.5.6#70375
lichunzhu wants to merge 23 commits into
pingcap:release-6.5-20231229-v6.5.6from
lichunzhu:hotfix/HF-1059/v6.5.6

Conversation

@lichunzhu

@lichunzhu lichunzhu commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: close #xxx

Problem Summary:

What changed and how does it work?

Check List

Tests

  • Unit test
  • Integration test
  • Manual test (add detailed scripts or steps below)
  • No need to test
    • I checked and no code files have been changed.

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

Please refer to Release Notes Language Style Guide to write a quality release note.

None

Summary by CodeRabbit

  • New Features
    • Added background merging of empty regions, configurable drop-table force merge, and an endpoint to reset merge progress.
    • Added statistics-owner controls and the tidb_enable_stats_owner and tidb_enable_drop_table_force_merge settings.
    • Added detailed DDL backfill metrics and improved cleanup.
  • Bug Fixes
    • Improved duplicate-row handling, partitioned-table row ID warnings, query plan pruning, and stale-read behavior for internal operations.
    • Improved subscription shutdown and recovery when callbacks fail.
    • Restricted sql_require_primary_key changes to authorized administrators.
  • Performance
    • Added memory-limit interruption handling during index range processing.

ti-chi-bot and others added 23 commits December 22, 2025 22:24
@lichunzhu
lichunzhu requested a review from a team as a code owner August 6, 2026 14:43
@ti-chi-bot ti-chi-bot Bot added do-not-merge/invalid-title release-note-none Denotes a PR that doesn't merit a release note. contribution This PR is from a community contributor. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. needs-ok-to-test Indicates a PR created by contributors and need ORG member send '/ok-to-test' to start testing. labels Aug 6, 2026
@ti-chi-bot

ti-chi-bot Bot commented Aug 6, 2026

Copy link
Copy Markdown

Hi @lichunzhu. Thanks for your PR.

I'm waiting for a pingcap member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@lichunzhu

Copy link
Copy Markdown
Contributor Author

/ok-to-test

@ti-chi-bot

ti-chi-bot Bot commented Aug 6, 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 youjiali1995 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

@pingcap-cla-assistant

pingcap-cla-assistant Bot commented Aug 6, 2026

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
10 out of 11 committers have signed the CLA.

✅ YangKeao
✅ hawkingrei
✅ winoros
✅ lichunzhu
✅ tiancaiamao
✅ YuJuncen
✅ Debra-He
✅ mjonss
✅ qw4990
✅ wshwsh12
❌ tangenta


tangenta seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@ti-chi-bot

ti-chi-bot Bot commented Aug 6, 2026

Copy link
Copy Markdown

@lichunzhu: Cannot trigger testing until a trusted user reviews the PR and leaves an /ok-to-test message.

Details

In response to this:

/ok-to-test

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This change adds DDL backfill metric cleanup, PD force-merge processing, domain-owned statistics control, context-aware subscription shutdown, planner and executor corrections, runtime variables, and related tests and build updates.

Changes

Stream subscription lifecycle

Layer / File(s) Summary
Context-aware shutdown and panic handling
br/pkg/streamhelper/flush_subscriber.go, br/pkg/streamhelper/advancer.go
Subscription shutdown now propagates contexts, supports cancellation, recovers callback panics, and invokes daemon-exit callbacks.
Lifecycle tests
br/pkg/streamhelper/advancer_test.go, br/pkg/streamhelper/BUILD.bazel
Tests cover ownership-loss cleanup and checkpoint advancement after callback panics. The test target uses 24 shards.

DDL backfill metrics

Layer / File(s) Summary
Table-scoped metric registry
metrics/ddl.go, ddl/backfill_metrics.go
Backfill counters and gauges now register labels by table ID and support cleanup.
DDL worker integration
ddl/column.go, ddl/index.go, ddl/index_merge_tmp.go, ddl/reorg.go, infoschema/builder.go
Workers use table-, column-, index-, and partition-specific metrics. Cleanup runs after reorganization and table creation.
Metric validation
ddl/backfill_metrics_test.go, ddl/BUILD.bazel
Tests cover partition IDs, logical IDs, Prometheus removal, and idempotent cleanup.

PD force merge

Layer / File(s) Summary
Range generation
ddl/pkdb_force_merge.go, ddl/pkdb_force_merge_test.go
DDL code derives physical, logical, and empty table-ID key ranges with filtering for unsupported tables and actions.
PD synchronization
domain/infosync/pkdb_force_merge.go, domain/infosync/info.go, domain/infosync/pkdb_force_merge_test.go
Infosync batches encoded ranges, retries with fresh request bodies, applies timeouts, and handles cancellation.
Checkpoint processing
domain/pkdb_force_merge.go, meta/meta.go, store/gcworker/gc_worker.go
The domain scans from a persisted checkpoint, conditionally advances it, and reports ranges after delete-range completion.
Reset endpoint
server/http_handler.go, server/http_status.go, server/http_handler_test.go
TiKV status HTTP now exposes a POST endpoint that resets the scan checkpoint.

Statistics ownership

Layer / File(s) Summary
Owner lifecycle
owner/manager.go, owner/mock.go, ddl/ddl.go, ddl/ddl_running_jobs.go
Owner retirement hooks reset DDL running-job state, which now separates processing jobs from unfinished schema conflicts.
Domain statistics workers
domain/domain.go, domain/domain_test.go, config/config.go, sessionctx/variable/*
Statistics ownership is domain-owned and can be enabled or disabled through configuration and system variables.
DDL event cleanup
ddl/schema.go, ddl/table.go, ddl/util/event.go, statistics/handle/*
DDL events include dropped table IDs, and statistics metadata versions update for truncation and schema drops.

Planner and executor

Layer / File(s) Summary
Planner corrections
planner/core/*
Column pruning, empty aggregation handling, result ordering, correlated apply behavior, semi-join rewriting, index pushdown, and partitioned _tidb_rowid warnings are updated.
Executor corrections
executor/*, distsql/request_builder.go, util/memory/tracker.go
Index range conversion tracks memory and kill signals. Duplicate replacement and partitioned update handling are corrected.

Runtime and compatibility updates

Layer / File(s) Summary
System variables and sessions
sessionctx/variable/*, session/session.go, sessiontxn/staleread/externalts_test.go
Force-merge and statistics-owner variables are added. Internal SQL bypasses stale-read validation.
Privilege and supporting fixes
privilege/privileges/privileges_test.go, infoschema/builder.go, util/printer/printer.go
Dynamic privilege coverage is added, partition exchange reloads allocators, and the buildVersion linkname is disabled.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

  • pingcap/tidb#65865: Extends the same DDL backfill-metrics cleanup and table-ID registration paths.
  • pingcap/tidb#69590: Modifies the same streamhelper subscription and advancer code.
  • pingcap/tidb#69943: Shares changes across statistics ownership, force merge, planner, executor, and configuration.

Suggested labels: component/statistics

Suggested reviewers: gmhdbjd, qw4990

Poem

A rabbit checks each metric bright,
And guides lost regions through the night.
Owners hop when terms expire,
Callbacks calm the panic fire.
Ranges march to PD’s door—
Clean tables bloom once more.

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description retains the template with placeholder issue information and omits the problem, implementation, test, side-effect, and release-note details. Add a real issue reference, problem summary, implementation details, completed test checklist, side-effect assessment, and an appropriate release note.
Docstring Coverage ⚠️ Warning Docstring coverage is 18.10% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title identifies a hotfix release but does not describe the primary changes in the pull request. Replace the release-style title with a concise summary of the main fixes, such as planner, DDL, statistics, and force-merge fixes.
✅ Passed checks (2 passed)
Check name Status Explanation
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions
The command is terminated due to an error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions


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.

@ti-chi-bot

ti-chi-bot Bot commented Aug 6, 2026

Copy link
Copy Markdown

[FORMAT CHECKER NOTIFICATION]

Notice: To remove the do-not-merge/invalid-title label, please follow title format, for example pkg [, pkg2, pkg3]: what is changed or *: what is changed.

The title description (the part after :) must be between 1 and 320 characters. Please check if your title exceeds this limit.

📖 For more info, you can check the "Contribute Code" section in the development guide.

@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: 17

🧹 Nitpick comments (4)
domain/infosync/pkdb_force_merge.go (1)

102-108: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use errors.Errorf for the unsupported-endpoint error.

The rest of the function wraps errors with github.com/pingcap/errors. fmt.Errorf creates an error without a stack trace, so callers lose context. fmt is then only needed for this one call.

♻️ Proposed change
-			err = fmt.Errorf("PD %s endpoint is unsupported or rejected by precondition", route)
+			err = errors.Errorf("PD %s endpoint is unsupported or rejected by precondition", route)
🤖 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 `@domain/infosync/pkdb_force_merge.go` around lines 102 - 108, Replace the
fmt.Errorf call in the respBody nil branch of the force-merge request function
with github.com/pingcap/errors.Errorf, then remove the fmt import if it is no
longer used. Preserve the existing error message and logging behavior.
ddl/delete_range.go (1)

275-293: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

One force-merge reporter is copied into two packages. reportForceMergeRanges and doGCForceMergeRanges perform the same four steps: check variable.EnableDropTableForceMerge, load the history DDL job, fail when the job is missing, and call infosync.AddForceMergeRanges. The copies already diverge in the missing-job error type, so future fixes must be applied twice.

  • ddl/delete_range.go#L275-L293: replace the body with a call to a new exported helper in the ddl package, for example ReportForceMergeRangesForGCDeleteRange(ctx, sctx, r, cache), and keep dbterror.ErrDDLJobNotFound as the single missing-job error.
  • store/gcworker/gc_worker.go#L766-L784: delete doGCForceMergeRanges and call the same ddl helper from deleteRanges.
🤖 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 `@ddl/delete_range.go` around lines 275 - 293, The duplicated force-merge
reporting logic must be centralized. In ddl/delete_range.go:275-293, add an
exported ddl helper such as ReportForceMergeRangesForGCDeleteRange and have
reportForceMergeRanges delegate to it, preserving dbterror.ErrDDLJobNotFound for
missing jobs. In store/gcworker/gc_worker.go:766-784, remove
doGCForceMergeRanges and update deleteRanges to call the shared ddl helper.
config/config.go (1)

506-506: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add doc comments for the new exported symbols.

  • config/config.go#L506-L506: add a comment that starts with TiDBEnableStatsOwner and describes the instance configuration state.
  • sessionctx/variable/tidb_vars.go#L1220-L1220: add a comment that starts with EnableDropTableForceMerge and describes the process-level flag.

As per coding guidelines, keep exported-symbol doc comments.

🤖 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 `@config/config.go` at line 506, Add Go doc comments for both exported symbols:
in config/config.go at lines 506-506, add a comment beginning with
TiDBEnableStatsOwner that describes the instance configuration state; in
sessionctx/variable/tidb_vars.go at lines 1220-1220, add a comment beginning
with EnableDropTableForceMerge that describes the process-level flag.

Source: Coding guidelines

ddl/ddl_running_jobs_test.go (1)

98-110: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for nonterminal remove calls.

This test only removes jobs after JobStateDone. The new behavior must retain unfinishedSchema when a worker releases a nonterminal job. Add an assertion that remove clears allIDs() but keeps a conflicting job unrunnable until the original job becomes done or synced.

🤖 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 `@ddl/ddl_running_jobs_test.go` around lines 98 - 110, Extend the removal test
around j.remove to cover a nonterminal job state: remove a job before setting it
to JobStateDone, assert it is absent from allIDs(), and verify checkRunnable
still rejects a conflicting job. Then transition the original job to done or
synced and assert the conflicting job becomes runnable, preserving the existing
terminal-removal checks.
🤖 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 `@br/pkg/streamhelper/advancer_test.go`:
- Around line 414-419: In TestOwnershipLost and TestSubscriptionPanic, validate
every failpoint.Enable and failpoint.Disable call with require.NoError(t, ...),
including the setup at br/pkg/streamhelper/advancer_test.go lines 414-419 and
the sibling call at lines 436-436. Ensure failures abort the tests before
exercising paths that depend on the failpoints.
- Around line 432-433: The subscription exit callbacks are registered too early,
allowing injected panics to invoke wg.Done more times than the initial count. In
the test setup around TEST_registerCallbackForSubscriptions, inject the panic
failpoints first, then register callbacks immediately before cancellation,
assert that at least one current subscription was registered, and retain the
final wg.Wait behavior.

In `@br/pkg/streamhelper/advancer.go`:
- Around line 628-635: Add a Go doc comment immediately above
CheckpointAdvancer.TEST_registerCallbackForSubscriptions stating that it
registers a callback on the current subscriptions; ensure the comment starts
with TEST_registerCallbackForSubscriptions.

In `@br/pkg/streamhelper/flush_subscriber.go`:
- Around line 264-272: Separate the recovery logic from the onDaemonExit
callback in the deferred cleanup around the subscriber execution. Ensure
recover() handles the original panic before invoking onDaemonExit, so a panic
from the callback cannot prevent recovery; preserve the existing warning and
emitError handling through the recovery delegate.

In `@ddl/ddl.go`:
- Around line 757-759: Update the runningJobs lifecycle in the owner setup: add
a locked runningJobs.reset method that clears the existing object in place, and
call it from the SetRetireOwnerHook callback instead of replacing d.runningJobs.
Ensure this hook is registered before DDL ownership or campaigning is enabled,
so the callback is installed before any ownership transition can occur.

In `@ddl/table.go`:
- Line 814: Update ddl/table.go at lines 814-814 in asyncNotifyEvent to include
oldPartitionIDs while retaining the old logical tableID. Update
statistics/handle/ddl.go at lines 51-55 so truncate cleanup advances metadata
versions for both the logical table ID and every old physical partition ID. Add
static- and dynamic-pruning partitioned truncate cases in
statistics/handle/ddl_test.go at lines 87-105, verifying all old statistics rows
receive a new version.

In `@distsql/request_builder.go`:
- Around line 747-749: Update the memory accounting in the helper around the
memTracker.Consume call to charge all preallocated kv.KeyRange values: use the
total backing-array capacity represented by len(tids) and len(ranges), rather
than only len(ranges), while preserving the existing key-byte accounting.

In `@domain/BUILD.bazel`:
- Line 11: Regenerate domain/BUILD.bazel using make bazel_prepare so the
domain_test target includes pkdb_force_merge_test.go while preserving
shard_count at 25 and adding no dependencies.

In `@domain/pkdb_force_merge.go`:
- Around line 1-13: Replace the headers in domain/pkdb_force_merge.go lines 1-13
and domain/pkdb_force_merge_test.go lines 1-13 with the repository-standard TiDB
copyright and Apache 2.0 header copied from a nearby Go file; make no other
changes.
- Line 48: Call CampaignOwner on the manager returned by Domain.newOwnerManager
in the merge-empty-regions initialization before relying on it for
doMergeEmptyRegions. Use mergeEmptyRegionsOwnerKey for the campaign and preserve
the existing mergeEmptyRegionsOwnerPrompt setup.

In `@executor/insert_common.go`:
- Around line 1201-1207: Update the handle-key duplicate path in the surrounding
insert method to assign the boolean result from removeRow to skip, then exit or
bypass unique-key processing when skip is true before reaching addRecord.
Preserve the existing identical-row behavior for unique-key duplicates, and add
a regression case covering a default clustered primary key.

In `@owner/mock.go`:
- Around line 105-108: Update mockManager.RetireOwner to invoke the stored
retireHook callback before clearing owner, matching ownerManager.RetireOwner
behavior; preserve SetRetireOwnerHook’s callback storage.

In `@planner/core/hf1045_apply_prune_regression_test.go`:
- Line 1: Copy the standard TiDB copyright and Apache 2.0 license header from a
nearby Go source file and add it before the package declaration in the new test
file, leaving the existing package declaration and test code unchanged.

In `@planner/core/integration_test.go`:
- Around line 1933-1945: Update the test around the query with the
SEMI_JOIN_REWRITE hint to assert a stable EXPLAIN or optimizer-trace property
proving the semi-join rewrite was applied, rather than relying only on the
unchanged result row. Preserve the existing result assertion while adding the
rewrite-specific verification using the test’s established inspection mechanism.

In `@sessiontxn/staleread/externalts_test.go`:
- Around line 72-75: Update the insert assertion in the test to verify the error
message contains “only support read-only statement during read-only staleness
transactions” rather than merely checking that an error occurred, covering
validateStatementReadOnlyInStaleness while preserving the existing setup.

In `@store/gcworker/gc_worker.go`:
- Around line 733-740: Update the GC force-merge reporting flow around
doGCForceMergeRanges to disable further PD reporting after the first failure.
Declare forceMergeReportDisabled alongside gcForceMergeTableCache, skip the call
when it is true, and set it to true when doGCForceMergeRanges returns an error
while preserving the existing error log for the initial failure.

In `@util/printer/printer.go`:
- Line 171: Restore the `go:linkname` directive for `buildVersion` in
`util/printer/printer.go` so it is recognized by the linker, or update both
`PrintTiDBInfo` and `GetTiDBInfo` to use `runtime.Version()` consistently with
the non-Go-1.12-aware implementation. Ensure both functions report a populated
`GoVersion`.

---

Nitpick comments:
In `@config/config.go`:
- Line 506: Add Go doc comments for both exported symbols: in config/config.go
at lines 506-506, add a comment beginning with TiDBEnableStatsOwner that
describes the instance configuration state; in sessionctx/variable/tidb_vars.go
at lines 1220-1220, add a comment beginning with EnableDropTableForceMerge that
describes the process-level flag.

In `@ddl/ddl_running_jobs_test.go`:
- Around line 98-110: Extend the removal test around j.remove to cover a
nonterminal job state: remove a job before setting it to JobStateDone, assert it
is absent from allIDs(), and verify checkRunnable still rejects a conflicting
job. Then transition the original job to done or synced and assert the
conflicting job becomes runnable, preserving the existing terminal-removal
checks.

In `@ddl/delete_range.go`:
- Around line 275-293: The duplicated force-merge reporting logic must be
centralized. In ddl/delete_range.go:275-293, add an exported ddl helper such as
ReportForceMergeRangesForGCDeleteRange and have reportForceMergeRanges delegate
to it, preserving dbterror.ErrDDLJobNotFound for missing jobs. In
store/gcworker/gc_worker.go:766-784, remove doGCForceMergeRanges and update
deleteRanges to call the shared ddl helper.

In `@domain/infosync/pkdb_force_merge.go`:
- Around line 102-108: Replace the fmt.Errorf call in the respBody nil branch of
the force-merge request function with github.com/pingcap/errors.Errorf, then
remove the fmt import if it is no longer used. Preserve the existing error
message and logging behavior.
🪄 Autofix

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 Plus

Run ID: dbe784b4-25bc-416d-ae83-88a6d0919e8a

📥 Commits

Reviewing files that changed from the base of the PR and between a9fb0f0 and 50128a3.

📒 Files selected for processing (74)
  • br/pkg/streamhelper/BUILD.bazel
  • br/pkg/streamhelper/advancer.go
  • br/pkg/streamhelper/advancer_test.go
  • br/pkg/streamhelper/flush_subscriber.go
  • config/config.go
  • config/config_test.go
  • ddl/BUILD.bazel
  • ddl/backfill_metrics.go
  • ddl/backfill_metrics_test.go
  • ddl/column.go
  • ddl/db_partition_test.go
  • ddl/ddl.go
  • ddl/ddl_running_jobs.go
  • ddl/ddl_running_jobs_test.go
  • ddl/delete_range.go
  • ddl/index.go
  • ddl/index_merge_tmp.go
  • ddl/pkdb_force_merge.go
  • ddl/pkdb_force_merge_test.go
  • ddl/reorg.go
  • ddl/schema.go
  • ddl/table.go
  • ddl/util/event.go
  • distsql/request_builder.go
  • domain/BUILD.bazel
  • domain/domain.go
  • domain/domain_test.go
  • domain/infosync/BUILD.bazel
  • domain/infosync/info.go
  • domain/infosync/pkdb_force_merge.go
  • domain/infosync/pkdb_force_merge_test.go
  • domain/pkdb_force_merge.go
  • domain/pkdb_force_merge_test.go
  • executor/distsql.go
  • executor/executor_pkg_test.go
  • executor/insert_common.go
  • executor/update.go
  • executor/write_test.go
  • infoschema/builder.go
  • meta/meta.go
  • meta/meta_test.go
  • metrics/ddl.go
  • owner/manager.go
  • owner/mock.go
  • planner/core/expression_rewriter.go
  • planner/core/hf1045_apply_prune_regression_test.go
  • planner/core/integration_test.go
  • planner/core/logical_plan_trace_test.go
  • planner/core/optimizer_test.go
  • planner/core/planbuilder.go
  • planner/core/rule_build_key_info.go
  • planner/core/rule_column_pruning.go
  • planner/core/rule_max_min_eliminate.go
  • planner/core/rule_result_reorder.go
  • planner/core/testdata/integration_suite_out.json
  • planner/core/util.go
  • privilege/privileges/privileges_test.go
  • server/http_handler.go
  • server/http_handler_test.go
  • server/http_status.go
  • session/session.go
  • sessionctx/variable/BUILD.bazel
  • sessionctx/variable/pkdb_force_merge_test.go
  • sessionctx/variable/session.go
  • sessionctx/variable/sysvar.go
  • sessionctx/variable/tidb_vars.go
  • sessionctx/variable/varsutil.go
  • sessiontxn/staleread/externalts_test.go
  • statistics/handle/ddl.go
  • statistics/handle/ddl_test.go
  • statistics/handle/gc.go
  • store/gcworker/gc_worker.go
  • util/memory/tracker.go
  • util/printer/printer.go

Comment on lines +414 to +419
failpoint.Enable("github.com/pingcap/tidb/br/pkg/streamhelper/subscription.listenOver.aboutToSend", "pause")
failpoint.Enable("github.com/pingcap/tidb/br/pkg/streamhelper/FlushSubscriber.Clear.timeoutMs", "return(500)")
wg := new(sync.WaitGroup)
wg.Add(adv.TEST_registerCallbackForSubscriptions(wg.Done))
cancel()
failpoint.Disable("github.com/pingcap/tidb/br/pkg/streamhelper/subscription.listenOver.aboutToSend")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Check failpoint setup errors.

TestOwnershipLost and TestSubscriptionPanic do not validate failpoint.Enable/failpoint.Disable errors. Use assertions such as require.NoError(t, failpoint.Enable(...)) for setup; otherwise the test can pass without exercising the injected shutdown or panic paths.

📍 Affects 1 file
  • br/pkg/streamhelper/advancer_test.go#L414-L419 (this comment)
  • br/pkg/streamhelper/advancer_test.go#L436-L436
🤖 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 `@br/pkg/streamhelper/advancer_test.go` around lines 414 - 419, In
TestOwnershipLost and TestSubscriptionPanic, validate every failpoint.Enable and
failpoint.Disable call with require.NoError(t, ...), including the setup at
br/pkg/streamhelper/advancer_test.go lines 414-419 and the sibling call at lines
436-436. Ensure failures abort the tests before exercising paths that depend on
the failpoints.

Comment on lines +432 to +433
wg := new(sync.WaitGroup)
wg.Add(adv.TEST_registerCallbackForSubscriptions(wg.Done))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Register exit callbacks after the injected panics.

onDaemonExit runs after every listener exit. The 5*panic failpoint can call wg.Done more times than the initial subscription count. This causes a negative WaitGroup counter or a stuck final wg.Wait().

Move callback registration to immediately before cancellation. Assert that at least one current subscription was registered.

Proposed fix
 	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
 	env := &testEnv{fakeCluster: c, testCtx: t}
 	adv := streamhelper.NewCheckpointAdvancer(env)
 	adv.OnStart(ctx)
 	adv.OnBecomeOwner(ctx)
-	wg := new(sync.WaitGroup)
-	wg.Add(adv.TEST_registerCallbackForSubscriptions(wg.Done))
 
 	require.NoError(t, adv.OnTick(ctx))
-	failpoint.Enable("github.com/pingcap/tidb/br/pkg/streamhelper/subscription.listenOver.aboutToSend", "5*panic")
+	require.NoError(t, failpoint.Enable("github.com/pingcap/tidb/br/pkg/streamhelper/subscription.listenOver.aboutToSend", "5*panic"))
 	ckpt := c.advanceCheckpoints()
 	c.flushAll()
 	cnt := 0
@@
 			t.Fatalf("After 100 times, the progress cannot be advanced.")
 		}
 	}
+	wg := new(sync.WaitGroup)
+	subscriptionCount := adv.TEST_registerCallbackForSubscriptions(wg.Done)
+	if subscriptionCount == 0 {
+		t.Fatal("no subscription callback registered")
+	}
+	wg.Add(subscriptionCount)
 	cancel()
 	wg.Wait()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
wg := new(sync.WaitGroup)
wg.Add(adv.TEST_registerCallbackForSubscriptions(wg.Done))
wg := new(sync.WaitGroup)
subscriptionCount := adv.TEST_registerCallbackForSubscriptions(wg.Done)
if subscriptionCount == 0 {
t.Fatal("no subscription callback registered")
}
wg.Add(subscriptionCount)
cancel()
wg.Wait()
🤖 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 `@br/pkg/streamhelper/advancer_test.go` around lines 432 - 433, The
subscription exit callbacks are registered too early, allowing injected panics
to invoke wg.Done more times than the initial count. In the test setup around
TEST_registerCallbackForSubscriptions, inject the panic failpoints first, then
register callbacks immediately before cancellation, assert that at least one
current subscription was registered, and retain the final wg.Wait behavior.

Comment on lines +628 to +635
func (c *CheckpointAdvancer) TEST_registerCallbackForSubscriptions(f func()) int {
cnt := 0
for _, sub := range c.subscriber.subscriptions {
sub.onDaemonExit = f
cnt += 1
}
return cnt
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add a doc comment for the exported helper.

TEST_registerCallbackForSubscriptions is exported. Add a comment that starts with its identifier and states that it registers a callback on current subscriptions.

🤖 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 `@br/pkg/streamhelper/advancer.go` around lines 628 - 635, Add a Go doc comment
immediately above CheckpointAdvancer.TEST_registerCallbackForSubscriptions
stating that it registers a callback on the current subscriptions; ensure the
comment starts with TEST_registerCallbackForSubscriptions.

Source: Coding guidelines

Comment on lines +264 to +272
defer func() {
if s.onDaemonExit != nil {
s.onDaemonExit()
}

if pData := recover(); pData != nil {
log.Warn("Subscriber paniked.", zap.Uint64("store", storeID), zap.Any("panic-data", pData), zap.Stack("stack"))
s.emitError(errors.Annotatef(berrors.ErrUnknown, "panic during executing: %v", pData))
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '261,276p' br/pkg/streamhelper/flush_subscriber.go

Repository: pingcap/tidb

Length of output: 768


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '130,340p' br/pkg/streamhelper/flush_subscriber.go

Repository: pingcap/tidb

Length of output: 6188


🌐 Web query:

Go language specification defer recover panic order of deferred functions panic

💡 Result:

In Go, the interaction between defer, panic, and recover follows a predictable, well-defined sequence governed by the stack-unwinding process [1][2]. Execution Order of Deferred Functions Deferred functions are always executed in Last-In-First-Out (LIFO) order [1]. When a function executes a panic, its normal execution stops immediately [1][3]. The runtime then begins to unwind the stack for the current goroutine, executing all deferred functions associated with that function in reverse order of their registration [1][3]. This process continues up the call stack frame by frame, executing the deferred functions in each frame until the stack is fully unwound or a panic is recovered [1][3]. Role of Panic A panic interrupts the standard control flow [1][2]. When a function calls panic, it stops execution, runs its own deferred functions, and then returns to its caller [1][3]. To the caller, this return behaves as if the caller itself had called panic, triggering the caller's own deferred functions [1][3]. If no deferred function recovers the panic, this continues until the panic reaches the top level of the goroutine, causing the program to crash with a stack trace [1][4][2]. Role of Recover The recover built-in function is the only way to regain control of a panicking goroutine [1][2]. It is effective only when called directly within a deferred function [1][2][3]. 1. If called during normal execution, recover returns nil and has no effect [1][3]. 2. If the goroutine is panicking, a successful call to recover stops the unwinding process [1][2][3]. 3. Once recovered, the panic value is returned, and execution of the current function proceeds normally as if the deferred function had returned [2][3]. Key Implementation Detail For recover to be effective, it must be called directly within the deferred function [2][3]. If a deferred function calls another function that then calls recover, the recovery will not take effect because the "direct caller" requirement is not met [2][3]. [1], [2], [3]

Citations:


🌐 Web query:

Go language specification recover panicking value stored function call defers not panic recovered

💡 Result:

In Go, the built-in recover function is used to regain control of a panicking goroutine [1][2]. For recover to successfully stop a panic and retrieve the panicking value, it must be called directly within a deferred function [1][3]. The Go language specification and runtime enforce specific requirements for recover to be effective [4][3]: 1. Direct Invocation: The recover function must be called directly by the deferred function [3][5]. If recover is called within a function that is subsequently called by the deferred function, it will not be able to recover the panic and will return nil [1][6]. 2. Deferred Context: The call to recover must occur within the body of a deferred function [1][2]. If recover is called during normal execution (when the goroutine is not panicking), it has no effect and returns nil [1][2]. 3. Execution Scope: If the above conditions are met, recover stops the panicking sequence, restores normal execution, and returns the value that was originally passed to the panic function [1][7][2]. A common pitfall is using defer recover directly. In this case, recover is called when the defer statement is registered—not when the deferred function executes—or is treated as the deferred function itself, meaning it is not called directly by the deferred function in the required manner. Consequently, this specific usage returns nil and fails to stop the panic [3][8]. If a panic is not recovered, the panicking sequence continues to propagate up the call stack until all functions in the goroutine have returned, at which point the program terminates with a non-zero exit code and a stack trace [1][7][2].

Citations:


Recover callback panics before they escape.

In this deferred function, s.onDaemonExit() runs before recover() executes. If the callback panics, recover() runs in a deferred callback called from the first deferred function and cannot recover the original panic. Register onDaemonExit() and recover() in separate deferred functions; recover first if the callback panic should stop unwinding, or run the callback from the recovery delegate.

🤖 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 `@br/pkg/streamhelper/flush_subscriber.go` around lines 264 - 272, Separate the
recovery logic from the onDaemonExit callback in the deferred cleanup around the
subscriber execution. Ensure recover() handles the original panic before
invoking onDaemonExit, so a panic from the callback cannot prevent recovery;
preserve the existing warning and emitError handling through the recovery
delegate.

Comment thread ddl/ddl.go
Comment on lines +757 to +759
d.ownerManager.SetRetireOwnerHook(func() {
d.runningJobs = newRunningJobs()
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Reset the existing runningJobs object instead of replacing its pointer.

The hook runs before ownerManager.RetireOwner clears the election pointer. Workers can still access d.runningJobs while this assignment replaces it. wait4Switch also reads this field without a pointer lock. This creates a data race.

Add a locked runningJobs.reset method and call it from this hook. Register the hook before enabling DDL ownership so the lifecycle callback is installed before campaigning starts.

🤖 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 `@ddl/ddl.go` around lines 757 - 759, Update the runningJobs lifecycle in the
owner setup: add a locked runningJobs.reset method that clears the existing
object in place, and call it from the SetRetireOwnerHook callback instead of
replacing d.runningJobs. Ensure this hook is registered before DDL ownership or
campaigning is enabled, so the callback is installed before any ownership
transition can occur.

@@ -0,0 +1,73 @@
package core_test

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Add the required license header.

This new Go source file has no standard TiDB copyright and Apache 2.0 license header. Copy the header from a nearby Go file before package core_test.

As per coding guidelines, new Go source files must include the standard TiDB copyright and Apache 2.0 license header copied from a nearby file.

🤖 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 `@planner/core/hf1045_apply_prune_regression_test.go` at line 1, Copy the
standard TiDB copyright and Apache 2.0 license header from a nearby Go source
file and add it before the package declaration in the new test file, leaving the
existing package declaration and test code unchanged.

Source: Coding guidelines

Comment on lines +1933 to +1945
tk.MustQuery(`with c as (select * from t)
select max(t.a)
from t
where exists (
select /*+ SEMI_JOIN_REWRITE() */ 1
from c
where c.a < 1
)
and exists (
select 1
from c
where c.a < 2
)`).Check(testkit.Rows("1"))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert the semi-join rewrite result.

The query result remains 1 whether SEMI_JOIN_REWRITE() takes effect or not. Inspect a stable EXPLAIN or optimizer-trace property that proves the rewrite occurred. This test otherwise cannot detect a regression that silently ignores the hint.

🤖 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 `@planner/core/integration_test.go` around lines 1933 - 1945, Update the test
around the query with the SEMI_JOIN_REWRITE hint to assert a stable EXPLAIN or
optimizer-trace property proving the semi-join rewrite was applied, rather than
relying only on the unchanged result row. Preserve the existing result assertion
while adding the rewrite-specific verification using the test’s established
inspection mechanism.

Comment on lines +72 to 75
// with tidb_enable_external_ts_read enabled, this session will be readonly
tk.MustExec("set tidb_enable_external_ts_read=ON")
_, err := tk.Exec("insert into t values (0)")
require.Error(t, err)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== repo files =="
git ls-files | rg '(^|/)externalts_test\.go$|sessiontxn/staleread|validateStatementReadOnlyInStaleness' || true

echo "== target file context =="
target="$(git ls-files | rg '(^|/)externalts_test\.go$' | head -n1 || true)"
if [ -n "${target:-}" ]; then
  awk 'NR>=1 && NR<=130 {printf "%4d\t%s\n", NR, $0}' "$target"
fi

echo "== relevant searches =="
rg -n "validateStatementReadOnlyInStaleness|read-only staleness transactions|[eE]xternal_ts|tidb_enable_external_ts_read|only support read-only" .

Repository: pingcap/tidb

Length of output: 12004


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== session validation implementation =="
sed -n '2270,2325p' session/session.go

echo "== stale transaction error tests nearby =="
sed -n '560,605p' executor/stale_txn_test.go

Repository: pingcap/tidb

Length of output: 4107


Assert the expected read-only staleness error.

require.Error accepts any failure. Assert that the rejected insert contains only support read-only statement during read-only staleness transactions so the test covers validateStatementReadOnlyInStaleness.

Proposed test assertion
-	require.Error(t, err)
+	require.ErrorContains(t, err, "only support read-only statement during read-only staleness transactions")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// with tidb_enable_external_ts_read enabled, this session will be readonly
tk.MustExec("set tidb_enable_external_ts_read=ON")
_, err := tk.Exec("insert into t values (0)")
require.Error(t, err)
// with tidb_enable_external_ts_read enabled, this session will be readonly
tk.MustExec("set tidb_enable_external_ts_read=ON")
_, err := tk.Exec("insert into t values (0)")
require.ErrorContains(t, err, "only support read-only statement during read-only staleness transactions")
🤖 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 `@sessiontxn/staleread/externalts_test.go` around lines 72 - 75, Update the
insert assertion in the test to verify the error message contains “only support
read-only statement during read-only staleness transactions” rather than merely
checking that an error occurred, covering validateStatementReadOnlyInStaleness
while preserving the existing setup.

Comment on lines +733 to +740
if err := w.doGCForceMergeRanges(ctx, se, r, gcForceMergeTableCache); err != nil {
logutil.Logger(ctx).Error("[gc worker] report force merge ranges failed on range",
zap.String("uuid", w.uuid),
zap.Int64("jobID", r.JobID),
zap.Int64("elementID", r.ElementID),
zap.Error(err))
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

A PD outage can stall GC because every task pays the full force-merge timeout.

doGCForceMergeRanges runs a synchronous HTTP call to PD for each completed delete-range task. AddForceMergeRanges uses forceMergePDRequestTimeout (20s) per PD address, and it retries every configured address. If PD does not answer, deleteRanges adds that delay once per task and only logs the failure. A GC run with many pending ranges then takes far longer than before, which delays the remaining GC stages.

Short-circuit reporting for the rest of the run after the first failure, or count consecutive failures and stop calling PD.

🛡️ Proposed guard
-		if err := w.doGCForceMergeRanges(ctx, se, r, gcForceMergeTableCache); err != nil {
-			logutil.Logger(ctx).Error("[gc worker] report force merge ranges failed on range",
-				zap.String("uuid", w.uuid),
-				zap.Int64("jobID", r.JobID),
-				zap.Int64("elementID", r.ElementID),
-				zap.Error(err))
-		}
+		if !forceMergeReportDisabled {
+			if err := w.doGCForceMergeRanges(ctx, se, r, gcForceMergeTableCache); err != nil {
+				logutil.Logger(ctx).Error("[gc worker] report force merge ranges failed on range",
+					zap.String("uuid", w.uuid),
+					zap.Int64("jobID", r.JobID),
+					zap.Int64("elementID", r.ElementID),
+					zap.Error(err))
+				// Stop reporting for the remainder of this run so a PD outage
+				// does not add the PD request timeout to every task.
+				forceMergeReportDisabled = true
+			}
+		}

Declare forceMergeReportDisabled := false next to gcForceMergeTableCache.

🤖 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 `@store/gcworker/gc_worker.go` around lines 733 - 740, Update the GC
force-merge reporting flow around doGCForceMergeRanges to disable further PD
reporting after the first failure. Declare forceMergeReportDisabled alongside
gcForceMergeTableCache, skip the call when it is true, and set it to true when
doGCForceMergeRanges returns an error while preserving the existing error log
for the initial failure.

Comment thread util/printer/printer.go
}

//go:linkname buildVersion runtime.buildVersion
// go:linkname buildVersion runtime.buildVersion

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 4 '\bbuildVersion\b|go:linkname|runtime\.Version\(\)' --glob '*.go' .
rg -n 'buildVersion\s*=' --glob '*.go' . || true

Repository: pingcap/tidb

Length of output: 7746


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '--- util/printer/printer.go around buildVersion references ---\n'
sed -n '1,80p;160,176p' util/printer/printer.go

printf '\n--- all buildVersion references (not limited to go files) ---\n'
rg -n -C 3 '\bbuildVersion\b' . || true

printf '\n--- package-private variable assignment patterns for buildVersion ---\n'
rg -n '^\s*(\w+\s*)?buildVersion\b\s*[:=]|buildVersion\s*\+=' --glob '*.go' . || true

printf '\n--- go tool availability and directive behavior probe ---\n'
command -v go || true
if command -v go >/dev/null 2>&1; then
  go version
  tmpdir="$(mktemp -d)"
  cat > "$tmpdir/linkname.go" <<'EOF'
package main

//go:linkname buildVersion runtime.buildVersion
var buildVersion string

func main() {
	print(buildVersion)
}
EOF
  cat > "$tmpdir/lazymo" <<'EOF'
package main

// go:linkname buildVersion runtime.buildVersion
var buildVersion string

func main() {
	println(buildVersion, ":", buildVersion)
}
EOF
  printf 'linkname-variadic call:\n'
  go run -o /dev/null "$tmpdir/linkname.go" 2>&1 || true
  printf '\nlazymo:\n'
  go run -o /dev/null "$tmpdir/lazymo" 2>&1 || true
fi

Repository: pingcap/tidb

Length of output: 241


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- util/printer/printer.go around buildVersion references ---'
sed -n '1,80p;160,176p' util/printer/printer.go

printf '%s\n' ''
printf '%s\n' '--- all buildVersion references (not limited to go files) ---'
rg -n -C 3 '\bbuildVersion\b' . || true

printf '%s\n' ''
printf '%s\n' '--- package-private variable assignment patterns for buildVersion ---'
rg -n '^\s*(\w+\s*)?buildVersion\b\s*[:=]|buildVersion\s*\+=' --glob '*.go' . || true

printf '%s\n' ''
printf '%s\n' '--- go tool availability and directive behavior probe ---'
command -v go || true
if command -v go >/dev/null 2>&1; then
  go version
  tmpdir="$(mktemp -d)"
  cat > "$tmpdir/linkname.go" <<'EOF'
package main

//go:linkname buildVersion runtime.buildVersion
var buildVersion string

func main() {
	print(buildVersion)
}
EOF
  cat > "$tmpdir/lazymo" <<'EOF'
package main

// go:linkname buildVersion runtime.buildVersion
var buildVersion string

func main() {
	println(buildVersion, ":", buildVersion)
}
EOF
  printf '%s\n' 'linkname variadic call:'
  go run -o /dev/null "$tmpdir/linkname.go" 2>&1 || true
  printf '%s\n' ''
  printf '%s\n' 'lazy command:'
  go run -o /dev/null "$tmpdir/lazymo" 2>&1 || true
fi

Repository: pingcap/tidb

Length of output: 5038


🏁 Script executed:

#!/bin/bash
set -euo pipefail

tmpdir="$(mktemp -d)"

cat > "$tmpdir/linkname.go" <<'EOF'
package main

//go:linkname buildVersion runtime.buildVersion
var buildVersion string

func main() {
	println("valid:", buildVersion, ":", buildVersion)
}
EOF

cat > "$tmpdir/lazy.go" <<'EOF'
package main

// go:linkname runtime.buildVersion
var buildVersion string

func main() {
	println("lazy:", buildVersion, ":", buildVersion)
}
EOF

printf '%s\n' 'valid linkname:'
if go run "$tmpdir/linkname.go" >/tmp/linkname.stdout 2>/tmp/linkname.stderr; then
  cat /tmp/linkname.stdout
else
  cat /tmp/linkname.stderr
fi

printf '%s\n' ''
printf '%s\n' 'lazy directive:'
if go run "$tmpdir/lazy.go" >/tmp/lazy.stdout 2>/tmp/lazy.stderr; then
  cat /tmp/lazy.stdout
else
  cat /tmp/lazy.stderr
fi

Repository: pingcap/tidb

Length of output: 305


Restore the linker variable assignment.

// go:linkname buildVersion runtime.buildVersion is parsed as a normal comment. No other file assigns buildVersion, so both PrintTiDBInfo and GetTiDBInfo report an empty GoVersion. Restore the directive without the space, or replace the two call sites with runtime.Version() as the non-Go-1.12-aware util/printer.go already does.

🤖 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 `@util/printer/printer.go` at line 171, Restore the `go:linkname` directive for
`buildVersion` in `util/printer/printer.go` so it is recognized by the linker,
or update both `PrintTiDBInfo` and `GetTiDBInfo` to use `runtime.Version()`
consistently with the non-Go-1.12-aware implementation. Ensure both functions
report a populated `GoVersion`.

@Reminiscent

Copy link
Copy Markdown
Contributor

/ok-to-test

@ti-chi-bot ti-chi-bot Bot added ok-to-test Indicates a PR is ready to be tested. and removed needs-ok-to-test Indicates a PR created by contributors and need ORG member send '/ok-to-test' to start testing. labels Aug 7, 2026
@ti-chi-bot

ti-chi-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown

@lichunzhu: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
idc-jenkins-ci-tidb/check_dev 50128a3 link true /test check-dev
idc-jenkins-ci-tidb/mysql-test 50128a3 link true /test mysql-test
idc-jenkins-ci-tidb/build 50128a3 link true /test build
idc-jenkins-ci-tidb/check_dev_2 50128a3 link true /test check-dev2
idc-jenkins-ci-tidb/unit-test 50128a3 link true /test unit-test

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contribution This PR is from a community contributor. do-not-merge/invalid-title ok-to-test Indicates a PR is ready to be tested. release-note-none Denotes a PR that doesn't merit a release note. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.