Skip to content

[adapters] Have output endpoints report their own checkpoint totals - #6789

Merged
ryzhyk merged 1 commit into
mainfrom
fix-checkpoint-output-stats-double-count
Aug 2, 2026
Merged

[adapters] Have output endpoints report their own checkpoint totals#6789
ryzhyk merged 1 commit into
mainfrom
fix-checkpoint-output-stats-double-count

Conversation

@ryzhyk

@ryzhyk ryzhyk commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

A checkpoint needs each output endpoint's transmitted_records as of the moment the endpoint has transmitted the output the checkpoint covers, since that is the state the pipeline resumes from. It cannot read that itself: the circuit thread takes the checkpoint while the endpoints are still working, and it must not block waiting for them. So it guessed using this formula:

            transmitted_records: snapshot.transmitted_records
                + snapshot.buffered_records
                + snapshot.queued_records,

There are several issues with this:

  1. The second and third terms are the number of records output by the circuit, not the number of records send by the connector. They can have non-unit multiplicities and canceling out weights, making them an approximation to what the connector will output by the time the checkpoint completes
  2. There was a window of double counting when the same records were accounted by both queued_records and transmitted_records. The endpoint thread raises transmitted_records from inside push_batch_to_encoder, while the batch those records came from stays in queued_records until output_batch releases it afterwards.
  3. This aside, each counter is implemented as a separate atomic variable, meaning that they can be in an inconsistent state for short periods of time.

The second issue above caused the suspend_barrier4 test to fail.

Having tried several solutions, I concluded that the only correct way to do this is to have the endpoint report the actual transmitted number of records when it's finished processing records associated with the checkpoint, which is what this commit implements.

As a bonums, transmitted_bytes can now be tracked as well, and no longer has to be left out of the checkpoint.

Describe Manual Test Plan

Checklist

  • Unit tests added/updated
  • Integration tests added/updated
  • Documentation updated
  • Changelog updated

Breaking Changes?

Mark if you think the answer is yes for any of these components:

Describe Incompatible Changes

@ryzhyk
ryzhyk requested a review from blp August 2, 2026 08:46
@ryzhyk ryzhyk added ft Fault tolerant, distributed, and scale-out implementation connectors Issues related to the adapters/connectors crate labels Aug 2, 2026

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

Clean fix. Moving the reading from an approximation (transmitted + buffered + queued, which double-counted while the endpoint thread bumped transmitted_records before releasing the batch) to a latch armed by the circuit thread and populated by the endpoint the moment it crosses the threshold is the right shape for this. The idle-endpoint arming-time shortcut and the removed-endpoint no-report path are exactly the edge cases I would have asked about, and the concurrency test that walks the arm point across 16 offsets over 400 batches is convincing. Approving.

One doc-comment typo noted inline.

Comment thread crates/adapters/src/controller/test.rs Outdated
A checkpoint needs each output endpoint's `transmitted_records` as of the
moment the endpoint has transmitted the output the checkpoint covers, since
that is the state the pipeline resumes from. It cannot read that itself: the
circuit thread takes the checkpoint while the endpoints are still working, and
it must not block waiting for them. So it guessed using this formula:

```rust
            transmitted_records: snapshot.transmitted_records
                + snapshot.buffered_records
                + snapshot.queued_records,
```

There are several issues with this:
1. The second and third terms are the number of records output by the circuit,
   not the number of records send by the connector. They can have non-unit
   multiplicities and canceling out weights, making them an approximation
   to what the connector will output by the time the checkpoint completes
2. There was a window of double counting when the same records were accounted
   by both `queued_records` and `transmitted_records`. The endpoint thread
   raises `transmitted_records` from inside `push_batch_to_encoder`, while
   the batch those records came from stays in `queued_records` until `output_batch`
   releases it afterwards.
3. This aside, each counter is implemented as a separate atomic variable,
   meaning that they can be in an inconsistent state for short periods of time.

The second issue above caused the suspend_barrier4 test to fail.

Having tried several solutions, I concluded that the only correct way to do this
is to have the endpoint report the actual transmitted number of records when
it's finished processing records associated with the checkpoint, which is what
this commit implements.

As a bonums, `transmitted_bytes` can now be tracked as well, and no longer has
to be left out of the checkpoint.

Signed-off-by: Leonid Ryzhyk <ryzhyk@gmail.com>
@ryzhyk
ryzhyk force-pushed the fix-checkpoint-output-stats-double-count branch from 68cef71 to 4cd9584 Compare August 2, 2026 16:07

@blp blp left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I really don't like how complicated everything is getting. It's at the point where I can't see bugs because things are so complicated.

I don't see a bug in this.

Thanks for the fix.

@ryzhyk
ryzhyk added this pull request to the merge queue Aug 2, 2026
Merged via the queue into main with commit ebb97aa Aug 2, 2026
1 check passed
@ryzhyk
ryzhyk deleted the fix-checkpoint-output-stats-double-count branch August 2, 2026 22:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

connectors Issues related to the adapters/connectors crate ft Fault tolerant, distributed, and scale-out implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants