-
Notifications
You must be signed in to change notification settings - Fork 53
sink: add metrics for blackhole sink #5042
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,18 +19,22 @@ | |
| "github.com/pingcap/log" | ||
| "github.com/pingcap/ticdc/pkg/common" | ||
| commonEvent "github.com/pingcap/ticdc/pkg/common/event" | ||
| "github.com/pingcap/ticdc/pkg/metrics" | ||
| "github.com/pingcap/ticdc/utils/chann" | ||
| "go.uber.org/zap" | ||
| ) | ||
|
|
||
| // sink is responsible for writing data to blackhole. | ||
| // Including DDL and DML. | ||
| type sink struct { | ||
| eventCh chan *commonEvent.DMLEvent | ||
| eventCh *chann.UnlimitedChannel[*commonEvent.DMLEvent, any] | ||
| statistics *metrics.Statistics | ||
| } | ||
|
|
||
| func New() (*sink, error) { | ||
| func New(changefeedID common.ChangeFeedID) (*sink, error) { | ||
|
Check failure on line 34 in downstreamadapter/sink/blackhole/sink.go
|
||
| return &sink{ | ||
| eventCh: make(chan *commonEvent.DMLEvent, 4096), | ||
| eventCh: chann.NewUnlimitedChannelDefault[*commonEvent.DMLEvent](), | ||
| statistics: metrics.NewStatistics(changefeedID, "sink"), | ||
| }, nil | ||
| } | ||
|
|
||
|
|
@@ -50,7 +54,7 @@ | |
| // ref: https://github.com/pingcap/ticdc/blob/da834db76e0662ff15ef12645d1f37bfa6506d83/tests/integration_tests/lossy_ddl/run.sh#L23 | ||
| // Use zap.Stringer to call String() method which applies log redaction | ||
| log.Debug("BlackHoleSink: WriteEvents", zap.Stringer("dml", event)) | ||
| s.eventCh <- event | ||
| s.eventCh.Push(event) | ||
| } | ||
|
|
||
| func (s *sink) FlushDMLBeforeBlock(_ commonEvent.BlockEvent) error { | ||
|
|
@@ -64,34 +68,48 @@ | |
| // NOTE: don't change the log, integration test `lossy_ddl` depends on it. | ||
| // ref: https://github.com/pingcap/ticdc/blob/da834db76e0662ff15ef12645d1f37bfa6506d83/tests/integration_tests/lossy_ddl/run.sh#L17 | ||
| log.Debug("BlackHoleSink: DDL Event", zap.Any("ddl", e)) | ||
| ddlType := e.GetDDLType().String() | ||
| s.statistics.RecordDDLExecution(func() (string, error) { | ||
|
Check failure on line 72 in downstreamadapter/sink/blackhole/sink.go
|
||
| return ddlType, nil | ||
| }) | ||
| case commonEvent.TypeSyncPointEvent: | ||
| default: | ||
| log.Error("unknown event type", | ||
| zap.Any("event", event)) | ||
| } | ||
| event.PostFlush() | ||
| return nil | ||
| } | ||
|
|
||
| func (s *sink) AddCheckpointTs(ts uint64) { | ||
| log.Debug("BlackHoleSink: Checkpoint Ts Event", zap.Uint64("ts", ts)) | ||
| } | ||
|
|
||
| func (s *sink) Close() {} | ||
| func (s *sink) Close() { | ||
| s.eventCh.Close() | ||
| s.statistics.Close() | ||
| } | ||
|
|
||
| func (s *sink) Run(ctx context.Context) error { | ||
| for { | ||
| select { | ||
| case <-ctx.Done(): | ||
| return nil | ||
| case event := <-s.eventCh: | ||
| default: | ||
| event, ok := s.eventCh.Get() | ||
| if !ok { | ||
| log.Info("blackhole sink event channel closed") | ||
| return nil | ||
| } | ||
| s.statistics.RecordBatchExecution(func() (int, int64, error) { | ||
|
Check failure on line 103 in downstreamadapter/sink/blackhole/sink.go
|
||
| return int(event.Len()), event.GetSize(), nil | ||
| }) | ||
|
Comment on lines
+103
to
+105
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Handle the error return from The error returned by 🛡️ Proposed fix included in Run loop refactoring aboveSee the previous comment on lines 97-106 for the combined fix that addresses both the busy-wait issue and error handling. As per coding guidelines, use predefined repository errors; see docs/agents/error-handling.md before changing error creation, wrapping, or propagation. 🧰 Tools🪛 GitHub Check: Check[failure] 103-103: 🤖 Prompt for AI Agents |
||
| event.PostFlush() | ||
|
Comment on lines
+97
to
106
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Description: Check UnlimitedChannel API for context-aware methods
# Search for UnlimitedChannel method signatures
ast-grep --pattern $'type UnlimitedChannel[$_, $_] struct {
$$$
}'
ast-grep --pattern $'func ($_ *UnlimitedChannel[$_, $_]) GetWithContext($$$) $$$'Repository: pingcap/ticdc Length of output: 435 🏁 Script executed: # Check the UnlimitedChannel implementation to understand Get() behavior
cat -n utils/chann/unlimited_chann.go | head -120 | tail -80Repository: pingcap/ticdc Length of output: 2758 🏁 Script executed: # Look at the actual sink.go file to see the full Run() method context
cat -n downstreamadapter/sink/blackhole/sink.go | sed -n '80,120p'Repository: pingcap/ticdc Length of output: 1013 🏁 Script executed: # Check for other patterns of UnlimitedChannel usage in the codebase
rg -A 3 "\.Get\(\)" --type go | grep -A 3 "select"Repository: pingcap/ticdc Length of output: 39 🏁 Script executed: # View the complete getWithContext implementation
cat -n utils/chann/unlimited_chann.go | sed -n '106,150p'Repository: pingcap/ticdc Length of output: 1217 🏁 Script executed: # Search for similar patterns in other sink implementations
fd -e go -path "*sink*.go" | xargs grep -l "\.Get()" | head -5Repository: pingcap/ticdc Length of output: 226 🏁 Script executed: # Find other implementations using the same sink pattern
rg "\.Run\(ctx.*context\.Context\)" --type go -A 15 | grep -A 15 "select"Repository: pingcap/ticdc Length of output: 39 🏁 Script executed: # Look for other uses of GetWithContext to understand idiomatic pattern
rg "GetWithContext" --type go -B 2 -A 5Repository: pingcap/ticdc Length of output: 3359 🏁 Script executed: # Get the full context of the cloudstorage pattern
cat -n downstreamadapter/sink/cloudstorage/dml_writers.go | sed -n '80,120p'Repository: pingcap/ticdc Length of output: 1194 🏁 Script executed: # Check if there are other sinks that use GetWithContext properly
rg "GetWithContext" --type go -B 5 | grep -A 5 "for {" | head -30Repository: pingcap/ticdc Length of output: 39 Use The current pattern blocks on Proposed fix func (s *sink) Run(ctx context.Context) error {
for {
- select {
- case <-ctx.Done():
- return nil
- default:
- event, ok := s.eventCh.Get()
- if !ok {
- log.Info("blackhole sink event channel closed")
- return nil
- }
- s.statistics.RecordBatchExecution(func() (int, int64, error) {
- return int(event.Len()), event.GetSize(), nil
- })
- event.PostFlush()
- }
+ event, ok, err := s.eventCh.GetWithContext(ctx)
+ if err != nil {
+ return nil
+ }
+ if !ok {
+ log.Info("blackhole sink event channel closed")
+ return nil
+ }
+ s.statistics.RecordBatchExecution(func() (int, int64, error) {
+ return int(event.Len()), event.GetSize(), nil
+ })
+ event.PostFlush()
}
}🧰 Tools🪛 GitHub Check: Check[failure] 103-103: 🤖 Prompt for AI Agents |
||
| } | ||
|
Comment on lines
94
to
107
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The current implementation of the event, ok, err := s.eventCh.GetWithContext(ctx)
if err != nil {
return nil
}
if !ok {
log.Info("blackhole sink event channel closed")
return nil
}
event.PostFlush() |
||
| } | ||
| } | ||
|
|
||
| func (s *sink) BatchCount() int { | ||
| return 4096 | ||
| return s.eventCh.Len() | ||
| } | ||
|
|
||
| func (s *sink) BatchBytes() int { | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -19,13 +19,14 @@ import ( | |||||
| "testing" | ||||||
| "time" | ||||||
|
|
||||||
| "github.com/pingcap/ticdc/pkg/common" | ||||||
| commonEvent "github.com/pingcap/ticdc/pkg/common/event" | ||||||
| "github.com/stretchr/testify/require" | ||||||
| ) | ||||||
|
|
||||||
| // Test callback and tableProgress works as expected after AddDMLEvent | ||||||
| func TestBlacHoleSinkBasicFunctionality(t *testing.T) { | ||||||
| sink, err := New() | ||||||
| sink, err := New(common.NewChangefeedID(common.DefaultKeyspaceName)) | ||||||
| ctx, cancel := context.WithCancel(context.Background()) | ||||||
| defer cancel() | ||||||
| go sink.Run(ctx) | ||||||
|
|
@@ -90,7 +91,7 @@ func TestBlacHoleSinkBasicFunctionality(t *testing.T) { | |||||
| } | ||||||
|
|
||||||
| func TestBlackHoleSinkBatchConfig(t *testing.T) { | ||||||
| sink, err := New() | ||||||
| sink, err := New(common.NewChangefeedID(common.DefaultKeyspaceName)) | ||||||
| require.NoError(t, err) | ||||||
| require.Equal(t, 4096, sink.BatchCount()) | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update test expectation to match new BatchCount semantics. The test expects 🧪 Proposed fix to match new semanticsOption 1: Assert the correct initial value func TestBlackHoleSinkBatchConfig(t *testing.T) {
sink, err := New(common.NewChangefeedID(common.DefaultKeyspaceName))
require.NoError(t, err)
- require.Equal(t, 4096, sink.BatchCount())
+ require.Equal(t, 0, sink.BatchCount())
require.Zero(t, sink.BatchBytes())
}Option 2: Test after adding events func TestBlackHoleSinkBatchConfig(t *testing.T) {
sink, err := New(common.NewChangefeedID(common.DefaultKeyspaceName))
require.NoError(t, err)
+
+ // Add some test events
+ helper := commonEvent.NewEventTestHelper(t)
+ defer helper.Close()
+ helper.Tk().MustExec("use test")
+ dmlEvent := helper.DML2Event("test", "t", "insert into t values (1, 'test')")
+ sink.AddDMLEvent(dmlEvent)
+
- require.Equal(t, 4096, sink.BatchCount())
+ require.Equal(t, 1, sink.BatchCount())
require.Zero(t, sink.BatchBytes())
}📝 Committable suggestion
Suggested change
🧰 Tools🪛 GitHub Actions: PR Build and Unit Test / 0_Next Gen Unit Tests.txt[error] 96-96: downstreamadapter/sink/blackhole TestBlackHoleSinkBatchConfig failed: Not equal (expected: 4096, actual: 0). 🪛 GitHub Actions: PR Build and Unit Test / 4_Classic Unit Tests.txt[error] 96-96: TestBlackHoleSinkBatchConfig failed: Not equal (expected: 4096, actual: 0). 🤖 Prompt for AI Agents |
||||||
| require.Zero(t, sink.BatchBytes()) | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handle the error return from
RecordDDLExecution.The error returned by
RecordDDLExecutionis silently ignored, which violates error-handling best practices and is flagged by the pipeline. If the metrics recording fails, the sink should log the error or propagate it appropriately.🛡️ Proposed fix to check the error
As per coding guidelines, use predefined repository errors; see docs/agents/error-handling.md before changing error creation, wrapping, or propagation.
📝 Committable suggestion
🧰 Tools
🪛 GitHub Actions: PR Build and Unit Test / 1_Check.txt
[error] 72-72: golangci-lint (errcheck): Error return value of
s.statistics.RecordDDLExecutionis not checked.🪛 GitHub Check: Check
[failure] 72-72:
Error return value of
s.statistics.RecordDDLExecutionis not checked (errcheck)🤖 Prompt for AI Agents