Skip to content

sink: add before field for avro protocol - #5154

Merged
ti-chi-bot[bot] merged 10 commits into
pingcap:masterfrom
wk989898:avro-before
Aug 12, 2026
Merged

sink: add before field for avro protocol#5154
ti-chi-bot[bot] merged 10 commits into
pingcap:masterfrom
wk989898:avro-before

Conversation

@wk989898

@wk989898 wk989898 commented May 29, 2026

Copy link
Copy Markdown
Collaborator

What problem does this PR solve?

Issue Number: close #5153

What is changed and how it works?

This change adds the avro-include-before-value option to include the previous row in Avro messages.
When enabled:

  • Insert: top-level fields contain the new row, and _ticdc_before is null.
  • Update: top-level fields contain the new row, and _ticdc_before contains the old row.
  • Delete: top-level fields and _ticdc_before contain the old row.
  • _tidb_op is included to distinguish insert (c), update (u), and delete (d), even when enable-tidb-extension is disabled.

The decoder reads _tidb_op from the message instead of relying on its local configuration and reconstructs the corresponding insert, update, or delete event. The change also adds API/TOML configuration support and related unit and integration tests.

Event type Top-level columns _ticdc_before _tidb_op
Insert new row null c
Update new row old row u
Delete old row old row d

Check List

Tests

  • Unit test
  • Integration test
  • Manual test (add detailed scripts or steps below)

Questions

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

Release note

Add `before` field for Avro protocol

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Added an Avro option to include previous row values in change events.
    • Configure the option through API settings, configuration files, or Kafka sink URI parameters.
    • Avro delete events now preserve previous checksums and support decoding rows from before-images.
  • Bug Fixes

    • Improved Avro delete-event handling, schema compatibility, namespace parsing, and checksum validation.
  • Tests

    • Added coverage for configuration, API conversion, and Avro insert, update, and delete scenarios.

wk989898 added 2 commits May 29, 2026 09:00
Signed-off-by: wk989898 <nhsmwk@gmail.com>
Signed-off-by: wk989898 <nhsmwk@gmail.com>
@ti-chi-bot ti-chi-bot Bot added the release-note Denotes a PR that will be considered when it comes time to generate release notes. label May 29, 2026
@coderabbitai

coderabbitai Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds optional Avro before-value support for insert, update, and delete events. The option propagates through API and internal configuration. The encoder writes ticdcBefore data, and the decoder reconstructs before-image rows.

Changes

Avro Before-Value Feature

Layer / File(s) Summary
Configuration contract and wiring
api/v2/model.go, api/v2/model_test.go, api/v2/changefeed_toml_test.go, pkg/config/sink.go, pkg/sink/codec/common/config.go
Adds AvroIncludeBeforeValue to configuration models, conversion paths, TOML output, and Kafka URI handling.
Avro before-value encoding
pkg/sink/codec/avro/helper.go, pkg/sink/codec/avro/arvo.go
Encodes before rows for enabled events. Adds the nullable ticdcBefore union and delete operation metadata. Uses Checksum.Previous for deletes.
Avro before-value decoding
pkg/sink/codec/avro/decoder.go
Distinguishes legacy deletes from value-carrying events. Decodes before-image data and assembles DML rows with type-specific checksums.
Unit and integration validation
pkg/sink/codec/avro/avro_test.go, pkg/sink/codec/common/config_test.go, tests/integration_tests/avro_basic/data/data.sql, tests/integration_tests/avro_basic/run.sh
Tests configuration, checksums, round-trip encoding, namespace parsing, and insert/update/delete integration events.

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

Sequence Diagram(s)

sequenceDiagram
  participant SinkConfig
  participant AvroEncoder
  participant Kafka
  participant AvroDecoder
  SinkConfig->>AvroEncoder: enable AvroIncludeBeforeValue
  AvroEncoder->>Kafka: publish event with ticdcBefore
  Kafka->>AvroDecoder: deliver Avro event
  AvroDecoder->>AvroDecoder: decode before image and assemble DML event
Loading

Possibly related PRs

  • pingcap/ticdc#5475: Adds a separate Debezium-Avro protocol while also changing Avro configuration and before-value handling.
  • pingcap/ticdc#5590: Modifies the Avro decoder and DML event assembly paths.

Suggested reviewers: lidezhu, 3aceshowhand

Poem

A rabbit checks the Avro stream,
Before-values fill the schema dream.
Deletes keep their former row,
Checksums mark the past they know.
ticdcBefore hops along! 🐰

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR removes unrelated tests and a deprecation notice from DrainableChann, which are outside issue #5153. Revert the unrelated DrainableChann change and restore removed tests unless they are required by a separate, documented objective.
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes implement Avro before-state support requested by issue #5153, including encoding, decoding, configuration, and tests.
Title check ✅ Passed The title clearly and concisely describes the main change: adding before values to the Avro protocol.
Description check ✅ Passed The description includes the issue, implementation details, tests, compatibility questions, documentation questions, and release note.
✨ Finishing Touches 💡 2
⚔️ Resolve merge conflicts 💡
  • Resolve merge conflict in branch avro-before
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 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 May 29, 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 the AvroIncludeBeforeValue configuration option, allowing Avro-encoded update and delete events to include their pre-row ('before') values under the _ticdc_before field. The changes span across configuration definitions, the Avro encoder/decoder implementations, and integration tests. Feedback on the changes highlights two key issues in the decoder: first, a suggestion to dynamically check the _tidb_op field in the decoded map to determine delete events rather than relying on the decoder's static configuration; second, a potential out-of-bounds panic when splitting the schema namespace if it does not contain a dot.

Comment thread pkg/sink/codec/avro/decoder.go Outdated
Comment on lines +147 to +149
if d.config.AvroIncludeBeforeValue {
isDelete = valueMap[tidbOp] == deleteOperation
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

Instead of relying on the decoder's local configuration d.config.AvroIncludeBeforeValue to determine if the event is a delete, it is much more robust to dynamically check for the presence of the _tidb_op field in the decoded valueMap. This prevents decoding failures or mismatches if the decoder's configuration does not perfectly align with the producer's configuration.

Suggested change
if d.config.AvroIncludeBeforeValue {
isDelete = valueMap[tidbOp] == deleteOperation
}
if op, ok := valueMap[tidbOp].(string); ok {
isDelete = op == deleteOperation
}

Comment thread pkg/sink/codec/avro/decoder.go Outdated
Comment on lines +247 to +248
namespace := schema["namespace"].(string)
schemaName := strings.Split(namespace, ".")[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.

medium

If the namespace string does not contain a dot (e.g., if the schema or keyspace is empty), strings.Split(namespace, ".")[1] will panic with an out-of-bounds index. It is safer to check the length of the split parts before accessing the index.

namespace := schema["namespace"].(string)
	parts := strings.Split(namespace, ".")
	var schemaName string
	if len(parts) > 1 {
		schemaName = parts[1]
	} else {
		schemaName = namespace
	}

Signed-off-by: wk989898 <nhsmwk@gmail.com>
Signed-off-by: wk989898 <nhsmwk@gmail.com>
Signed-off-by: wk989898 <nhsmwk@gmail.com>
Signed-off-by: wk989898 <nhsmwk@gmail.com>
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/sink/codec/avro/decoder.go (1)

118-132: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Set the outer message commit timestamp for value-bearing deletes.

For a delete with tidbOp == deleteOperation, hasValue is true and deleteCommitTs is zero. Lines 120-123 then skip tidbCommitTs because isDelete is true. common.NewDMLMessage receives commit timestamp zero, although assembleEvent sets the correct timestamp later. This can break message ordering and downstream timestamp handling for Avro deletes with before data.

Use hasValue to decide when to read tidbCommitTs.

Proposed fix
-	if commitTs == 0 && !isDelete {
+	if commitTs == 0 && hasValue {
 		commitTs = uint64(valueMap[tidbCommitTs].(int64))
 	}
🤖 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/sink/codec/avro/decoder.go` around lines 118 - 132, Update the commit
timestamp selection in the decoder flow around decodeDMLPayload and
NewDMLMessage to read valueMap[tidbCommitTs] whenever hasValue is true and
deleteCommitTs is zero, including value-bearing deletes. Preserve deleteCommitTs
when it is present, and ensure the corrected commitTs is passed to
common.NewDMLMessage.
🤖 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.

Outside diff comments:
In `@pkg/sink/codec/avro/decoder.go`:
- Around line 118-132: Update the commit timestamp selection in the decoder flow
around decodeDMLPayload and NewDMLMessage to read valueMap[tidbCommitTs]
whenever hasValue is true and deleteCommitTs is zero, including value-bearing
deletes. Preserve deleteCommitTs when it is present, and ensure the corrected
commitTs is passed to common.NewDMLMessage.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ea545c8e-7404-4e4c-b784-12b7b156c715

📥 Commits

Reviewing files that changed from the base of the PR and between af33cc1 and 140b23b.

📒 Files selected for processing (11)
  • api/v2/model.go
  • api/v2/model_test.go
  • pkg/config/sink.go
  • pkg/sink/codec/avro/arvo.go
  • pkg/sink/codec/avro/avro_test.go
  • pkg/sink/codec/avro/decoder.go
  • pkg/sink/codec/avro/helper.go
  • pkg/sink/codec/common/config.go
  • pkg/sink/codec/common/config_test.go
  • tests/integration_tests/avro_basic/data/data.sql
  • tests/integration_tests/avro_basic/run.sh
🚧 Files skipped from review as they are similar to previous changes (8)
  • pkg/sink/codec/avro/helper.go
  • pkg/config/sink.go
  • api/v2/model_test.go
  • tests/integration_tests/avro_basic/data/data.sql
  • tests/integration_tests/avro_basic/run.sh
  • api/v2/model.go
  • pkg/sink/codec/common/config.go
  • pkg/sink/codec/avro/arvo.go

Signed-off-by: wk989898 <nhsmwk@gmail.com>
Signed-off-by: wk989898 <nhsmwk@gmail.com>
Signed-off-by: wk989898 <nhsmwk@gmail.com>
@ti-chi-bot ti-chi-bot Bot added the needs-1-more-lgtm Indicates a PR needs 1 more LGTM. label Aug 12, 2026
@3AceShowHand

Copy link
Copy Markdown
Collaborator

/test pull-error-log-review

@ti-chi-bot ti-chi-bot Bot added the lgtm label Aug 12, 2026
@ti-chi-bot

ti-chi-bot Bot commented Aug 12, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: 3AceShowHand, lidezhu

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

The pull request process is described 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 approved and removed needs-1-more-lgtm Indicates a PR needs 1 more LGTM. labels Aug 12, 2026
@ti-chi-bot

ti-chi-bot Bot commented Aug 12, 2026

Copy link
Copy Markdown

[LGTM Timeline notifier]

Timeline:

  • 2026-08-12 07:14:45.292266657 +0000 UTC m=+3203471.328361713: ☑️ agreed by 3AceShowHand.
  • 2026-08-12 07:55:51.94875404 +0000 UTC m=+3205937.984849106: ☑️ agreed by lidezhu.

@wk989898

Copy link
Copy Markdown
Collaborator Author

/retest

@ti-chi-bot
ti-chi-bot Bot merged commit 95ab232 into pingcap:master Aug 12, 2026
40 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved lgtm 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.

TiCDC Avro Protocol Supports "Before" State

3 participants