Skip to content

sink: add column selector for storage sink#5595

Open
wk989898 wants to merge 6 commits into
pingcap:masterfrom
wk989898:column-selector
Open

sink: add column selector for storage sink#5595
wk989898 wants to merge 6 commits into
pingcap:masterfrom
wk989898:column-selector

Conversation

@wk989898

@wk989898 wk989898 commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

What problem does this PR solve?

Issue Number: close #5592

What is changed and how it works?

The column selector logic was generalized from a Kafka-only path into a shared
column_selector flow that storage sink can also use.

Storage keeps PostEnqueue and PostFlush as separate lifecycle events. PostEnqueue remains
attached to the storage task and is triggered by the buffer/spool enqueue path. PostFlush
is attached to the encoded message callback and runs after the encoded storage message is
flushed.

About callback

For storage, the callback is intentionally different from Kafka.

Kafka produces row-level messages. It uses a row callback counter: each row callback
increments the count, and PostFlush runs only after all rows in the transaction have been
flushed.

Storage transaction encoders build a batch/transaction message. The encoder attaches only
the last row callback to the built batch message, so the callback is triggered once per
encoded storage message, not once per row. If storage used kafka's row-counting callback
for a multi-row transaction, the counter would never reach the row count and PostFlush
could hang forever.

That is why storage directly passes event.PostFlush as the row callback. The encoded
storage batch message calls it once when the message is flushed, which matches storage's
actual callback granularity.

Check List

Tests

  • Unit test
  • Integration test

Questions

Will it cause performance regression or break compatibility?
Do you need to update user documentation, design documentation or monitoring documentation?

Release note

support column selector for storage sink

Summary by CodeRabbit

  • New Features

    • Added column selector support for cloud storage, Kafka, Pulsar, and CSV/JSON encoding paths.
    • Only selected columns are now written to outputs, improving control over exported data.
    • Added support for more consistent row-level callback handling during DML processing.
  • Bug Fixes

    • Fixed callback handling so post-enqueue actions run correctly and only when present.
    • Improved encoding behavior for transactions built from row events.
  • Tests

    • Added and updated coverage for column selection, callback behavior, and sink output filtering.

wk989898 added 2 commits July 7, 2026 03:45
Signed-off-by: wk989898 <nhsmwk@gmail.com>
Signed-off-by: wk989898 <nhsmwk@gmail.com>
@ti-chi-bot

ti-chi-bot Bot commented Jul 7, 2026

Copy link
Copy Markdown

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@ti-chi-bot ti-chi-bot Bot added do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. release-note Denotes a PR that will be considered when it comes time to generate release notes. labels Jul 7, 2026
@ti-chi-bot

ti-chi-bot Bot commented Jul 7, 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 charlescheung96 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

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds column-selector support to the cloud storage sink and refactors the DML row-event/callback pipeline. Shared helpers now build RowEvent/MQRowEvent slices with selector filtering, reused by Kafka, Pulsar, redo sinks, and canal/CSV encoders, whose TxnEventEncoder interface now accepts pre-built row events instead of DMLEvent.

Changes

Column selector and row-event refactor

Layer / File(s) Summary
Shared row-event helpers
downstreamadapter/sink/helper/mq_row_event.go, downstreamadapter/sink/columnselector/column_selector.go
New NewRowEvents/NewMQRowEvents build row events with selector/callback wiring; ColumnSelectors.GetForTableInfo looks up a selector from table info.
Cloud storage task model refactor
downstreamadapter/sink/cloudstorage/task.go
task now stores postEnqueue and precomputed rowEvents instead of the raw DMLEvent and txnCallbacks; newDMLTask accepts a selector and removes replacePostFlushCallbacks.
Buffer manager / encoder group wiring and tests
downstreamadapter/sink/cloudstorage/buffer_manager.go, encoder_group.go, *_test.go
handleDMLTask/runEncoder use task.postEnqueue/task.rowEvents; tests updated for the new newDMLTask signature and callback flow.
Cloud storage sink column-selector wiring
downstreamadapter/sink/cloudstorage/dml_writers.go, sink.go, sink_test.go
dmlWriters/sink Verify/New construct and pass columnSelectors; a new test verifies column-filtered CSV output.
Kafka/Pulsar/redo sink refactor
downstreamadapter/sink/kafka/sink.go, pulsar/sink.go, redo/sink.go, helper/row_callback*.go
calculateKeyPartitions uses GetForTableInfo + helper.NewMQRowEvents; NewTxnPostFlushRowCallback renamed to NewPostFlushRowCallback.
TxnEventEncoder interface and canal/CSV encoders
pkg/sink/codec/common/encoder.go, canal/canal_json_txn_encoder*.go, csv/csv_encoder*.go, csv/csv_message.go
AppendTxnEvent now takes []*RowEvent; encoders filter columns via a selector-aware shouldEncodeColumn helper.
Column selector integration tests
tests/integration_tests/column_selector/*, kafka_column_selector/data.sql, run_heavy_it_in_ci.sh
New column_selector test suite supporting Kafka and storage flows; CI group lists updated accordingly.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • pingcap/ticdc#4263: Both PRs update the DML enqueue/flush callback lifecycle, wiring postEnqueue semantics into the cloud storage task pipeline.
  • pingcap/ticdc#4364: Both PRs touch cloudstorage task/encoder-group representation and post-flush/post-enqueue callback flow.
  • pingcap/ticdc#5275: Both PRs refactor cloudstorage callback/task wiring across buffer_manager.go, task.go, and encoder_group.go.

Suggested labels: lgtm, approved

Suggested reviewers: asddongmen, nongfushanquan

Poem

A rabbit hops through columns tall,
Selecting just the ones that call,
No more "filtered" hiding low—
Only "keep" values in the row! 🐇
Through Kafka, storage, redo too,
One helper hops the whole way through. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR also changes Kafka, Pulsar, CSV, Canal, Redo, and shared codec paths, which go beyond the storage-sink issue scope. If these shared refactors are required, document them in the issue; otherwise split non-storage-sink changes into separate PRs.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes implement storage sink column-selector support as requested in #5592, including setup, wiring, and tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding storage sink column selector support.
Description check ✅ Passed It follows the template with issue number, change summary, tests, questions, and release note, though the question answers are left blank.
✨ 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.

@ti-chi-bot ti-chi-bot Bot added the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label Jul 7, 2026

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces column selector support to the cloud storage sink, enabling column filtering for CSV and Canal-JSON encoders, and refactors MQ row event generation. The review feedback highlights two critical layering violations where utility packages in pkg/ depend on downstreamadapter/, which should be resolved by allowing the column selector to be nil by default. Additionally, it is recommended to replace the variadic parameter in newDMLTask with a single optional selector to avoid Go API design anti-patterns.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread pkg/sink/codec/csv/csv_encoder.go Outdated
Comment thread pkg/sink/codec/canal/canal_json_txn_encoder.go Outdated
Comment thread downstreamadapter/sink/cloudstorage/task.go
@wk989898

wk989898 commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator Author

/test storage

wk989898 added 3 commits July 7, 2026 07:41
Signed-off-by: wk989898 <nhsmwk@gmail.com>
.
Signed-off-by: wk989898 <nhsmwk@gmail.com>
Signed-off-by: wk989898 <nhsmwk@gmail.com>
@wk989898

wk989898 commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator Author

/test storage

Signed-off-by: wk989898 <nhsmwk@gmail.com>
@wk989898 wk989898 marked this pull request as ready for review July 7, 2026 09:27
@ti-chi-bot ti-chi-bot Bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jul 7, 2026
@wk989898

wk989898 commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator Author

/test all

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🧹 Nitpick comments (2)
downstreamadapter/sink/helper/row_callback_test.go (1)

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

Test name still references old NewTxnPostFlushRowCallback.

TestTxnPostFlushRowCallback wasn't renamed alongside the NewPostFlushRowCallback rename at Line 32, leaving a stale name.

✏️ Suggested rename
-func TestTxnPostFlushRowCallback(t *testing.T) {
+func TestPostFlushRowCallback(t *testing.T) {

Also applies to: 32-32

🤖 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 `@downstreamadapter/sink/helper/row_callback_test.go` at line 24, The test name
is stale after the callback rename, so update the test identifier in
TestTxnPostFlushRowCallback to match the new NewPostFlushRowCallback naming used
in the helper code. Make sure any related references in row_callback_test.go
that still mention the old Txn/PostFlush name are renamed consistently so the
test suite and symbols align with the current API.
downstreamadapter/sink/helper/mq_row_event.go (1)

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

Solid refactor; consider adding GoDoc comments.

NewMQRowEvents/NewRowEvents are exported but lack doc comments describing behavior (rewind semantics, default selector fallback). Minor polish only.

🤖 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 `@downstreamadapter/sink/helper/mq_row_event.go` around lines 52 - 81, The
exported constructors NewRowEvents and NewMQRowEvents should have GoDoc
comments. Add brief doc comments above these functions in mq_row_event.go that
describe their behavior, including the default selector fallback when selector
is nil and that NewRowEvents rewinds the DMLEvent after iterating through rows.
Keep the comments concise and directly tied to the function names so they
satisfy exported symbol documentation.
🤖 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 `@tests/integration_tests/column_selector/run.sh`:
- Around line 12-20: Quote the variable expansions in prepare_cluster so shell
word-splitting and pathname expansion cannot alter the commands; this is
especially important for the rm -rf target. Update the calls in prepare_cluster
that use WORK_DIR, UP_PD_HOST_1, UP_PD_PORT_1, and CDC_BINARY so they are safely
passed as single arguments. Keep the fix localized to prepare_cluster in run.sh
and preserve the existing behavior.

---

Nitpick comments:
In `@downstreamadapter/sink/helper/mq_row_event.go`:
- Around line 52-81: The exported constructors NewRowEvents and NewMQRowEvents
should have GoDoc comments. Add brief doc comments above these functions in
mq_row_event.go that describe their behavior, including the default selector
fallback when selector is nil and that NewRowEvents rewinds the DMLEvent after
iterating through rows. Keep the comments concise and directly tied to the
function names so they satisfy exported symbol documentation.

In `@downstreamadapter/sink/helper/row_callback_test.go`:
- Line 24: The test name is stale after the callback rename, so update the test
identifier in TestTxnPostFlushRowCallback to match the new
NewPostFlushRowCallback naming used in the helper code. Make sure any related
references in row_callback_test.go that still mention the old Txn/PostFlush name
are renamed consistently so the test suite and symbols align with the current
API.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1c2c26d7-fc5f-4a8e-b277-c8c59eb1925d

📥 Commits

Reviewing files that changed from the base of the PR and between 2258270 and 5102f18.

📒 Files selected for processing (28)
  • downstreamadapter/sink/cloudstorage/buffer_manager.go
  • downstreamadapter/sink/cloudstorage/buffer_manager_test.go
  • downstreamadapter/sink/cloudstorage/dml_writers.go
  • downstreamadapter/sink/cloudstorage/encoder_group.go
  • downstreamadapter/sink/cloudstorage/encoder_group_test.go
  • downstreamadapter/sink/cloudstorage/sink.go
  • downstreamadapter/sink/cloudstorage/sink_test.go
  • downstreamadapter/sink/cloudstorage/task.go
  • downstreamadapter/sink/cloudstorage/task_test.go
  • downstreamadapter/sink/cloudstorage/writer_test.go
  • downstreamadapter/sink/columnselector/column_selector.go
  • downstreamadapter/sink/helper/mq_row_event.go
  • downstreamadapter/sink/helper/row_callback.go
  • downstreamadapter/sink/helper/row_callback_test.go
  • downstreamadapter/sink/kafka/sink.go
  • downstreamadapter/sink/pulsar/sink.go
  • downstreamadapter/sink/redo/sink.go
  • pkg/sink/codec/canal/canal_json_txn_encoder.go
  • pkg/sink/codec/canal/canal_json_txn_encoder_test.go
  • pkg/sink/codec/common/encoder.go
  • pkg/sink/codec/csv/csv_encoder.go
  • pkg/sink/codec/csv/csv_encoder_test.go
  • pkg/sink/codec/csv/csv_message.go
  • tests/integration_tests/column_selector/conf/changefeed.toml
  • tests/integration_tests/column_selector/data/data.sql
  • tests/integration_tests/column_selector/run.sh
  • tests/integration_tests/kafka_column_selector/data/data.sql
  • tests/integration_tests/run_heavy_it_in_ci.sh
💤 Files with no reviewable changes (2)
  • tests/integration_tests/kafka_column_selector/data/data.sql
  • downstreamadapter/sink/cloudstorage/task_test.go

Comment on lines +12 to +20
function prepare_cluster() {
rm -rf $WORK_DIR && mkdir -p $WORK_DIR
start_tidb_cluster --workdir $WORK_DIR

# record tso before we create tables to skip the system table DDLs
# Record TSO before creating test tables to skip system table DDLs.
start_ts=$(run_cdc_cli_tso_query $UP_PD_HOST_1 $UP_PD_PORT_1)

run_cdc_server --workdir $WORK_DIR --binary $CDC_BINARY
}

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.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Quote variable expansions in prepare_cluster, especially the rm -rf target.

rm -rf $WORK_DIR and the other $WORK_DIR/$UP_PD_HOST_1/$CDC_BINARY usages here are unquoted. Static analysis flags the rm -rf case specifically as risky if the variable is ever empty or contains glob/whitespace characters (word-splitting/pathname-expansion could target unintended paths).

🔒 Proposed fix
 function prepare_cluster() {
-	rm -rf $WORK_DIR && mkdir -p $WORK_DIR
-	start_tidb_cluster --workdir $WORK_DIR
+	rm -rf -- "${WORK_DIR:?WORK_DIR is unset}" && mkdir -p "$WORK_DIR"
+	start_tidb_cluster --workdir "$WORK_DIR"

 	# Record TSO before creating test tables to skip system table DDLs.
-	start_ts=$(run_cdc_cli_tso_query $UP_PD_HOST_1 $UP_PD_PORT_1)
+	start_ts=$(run_cdc_cli_tso_query "$UP_PD_HOST_1" "$UP_PD_PORT_1")

-	run_cdc_server --workdir $WORK_DIR --binary $CDC_BINARY
+	run_cdc_server --workdir "$WORK_DIR" --binary "$CDC_BINARY"
 }
📝 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
function prepare_cluster() {
rm -rf $WORK_DIR && mkdir -p $WORK_DIR
start_tidb_cluster --workdir $WORK_DIR
# record tso before we create tables to skip the system table DDLs
# Record TSO before creating test tables to skip system table DDLs.
start_ts=$(run_cdc_cli_tso_query $UP_PD_HOST_1 $UP_PD_PORT_1)
run_cdc_server --workdir $WORK_DIR --binary $CDC_BINARY
}
function prepare_cluster() {
rm -rf -- "${WORK_DIR:?WORK_DIR is unset}" && mkdir -p "$WORK_DIR"
start_tidb_cluster --workdir "$WORK_DIR"
# Record TSO before creating test tables to skip system table DDLs.
start_ts=$(run_cdc_cli_tso_query "$UP_PD_HOST_1" "$UP_PD_PORT_1")
run_cdc_server --workdir "$WORK_DIR" --binary "$CDC_BINARY"
}
🧰 Tools
🪛 ast-grep (0.44.1)

[error] 12-12: Recursive rm is given an unquoted variable expansion as a target. If the variable is empty, contains whitespace, or holds glob characters, word splitting and pathname expansion can make rm delete unintended paths (e.g. rm -rf $dir with dir="" or dir="/ tmp"). Always double-quote the expansion and guard against empty values: rm -rf -- "${dir:?dir is unset}".
Context: $WORK_DIR
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(rm-rf-unquoted-variable-bash)

🪛 Shellcheck (0.11.0)

[info] 13-13: Double quote to prevent globbing and word splitting.

(SC2086)


[info] 13-13: Double quote to prevent globbing and word splitting.

(SC2086)


[info] 14-14: Double quote to prevent globbing and word splitting.

(SC2086)


[info] 17-17: Double quote to prevent globbing and word splitting.

(SC2086)


[info] 17-17: Double quote to prevent globbing and word splitting.

(SC2086)


[info] 19-19: Double quote to prevent globbing and word splitting.

(SC2086)

🤖 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 `@tests/integration_tests/column_selector/run.sh` around lines 12 - 20, Quote
the variable expansions in prepare_cluster so shell word-splitting and pathname
expansion cannot alter the commands; this is especially important for the rm -rf
target. Update the calls in prepare_cluster that use WORK_DIR, UP_PD_HOST_1,
UP_PD_PORT_1, and CDC_BINARY so they are safely passed as single arguments. Keep
the fix localized to prepare_cluster in run.sh and preserve the existing
behavior.

Source: Linters/SAST tools

@wk989898

wk989898 commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator Author

/retest

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

Labels

release-note Denotes a PR that will be considered when it comes time to generate release notes. 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.

support column selector in storage sink

1 participant