suvodeep-pyne opened a new pull request, #19740:
URL: https://github.com/apache/pinot/pull/19740
## Summary
On pauseless tables, a commit start whose IdealState update fails leaves the
segment COMMITTING. Every later attempt of the commit then failed until
`RealtimeSegmentValidationManager` repaired the partition after
`max.segment.completion.time.millis`. With this PR, the next attempt of the
commit start resumes the earlier one, so the server's own retry commits the
segment.
## Motivation
The pauseless commit start has three steps:
1. Move the segment ZK metadata from IN_PROGRESS to COMMITTING and set its
end offset.
2. Create the ZK metadata of the next segment.
3. Update the IdealState: the committing segment ONLINE, the new segment
CONSUMING.
A pauseless REALTIME table had ~550K segments (IdealState ~5 MB compressed).
While other controllers were deleting segments, each IdealState update attempt
took 6–11 s, and three group-commit batches lost all 10 attempts with `Version
changed while updating ideal state`.
- Each commit in those batches stayed COMMITTING.
- Every retry by the servers failed with `Segment status for segment: …
should be IN_PROGRESS, found: COMMITTING`.
- 18 partitions stopped consuming for 31 to 73 minutes, until the validation
manager repaired them (`max.segment.completion.time.millis` = 30 min).
A controller that stops between step 1 and step 3 leaves the same state.
## Changes
A commit start for a segment that is already COMMITTING with the same end
offset resumes the earlier attempt from step 2. This only applies before the
max segment completion time; after that, the validation manager still owns the
repair. Steps 2 and 3 are made idempotent, so all attempts of a commit start
converge, including attempts on two controllers around a lead change:
- **Same new segment for every attempt.** A resumed attempt reuses the new
segment of an earlier attempt, if there is one. LLC names carry the creation
time with minute granularity, and the new segment was created between step 1
and now, a window bounded by the max segment completion time. So the resumed
attempt probes the ZK path for each minute's name in that window, with one
minute of slack on each side.
- If there is none, it creates the new segment with the current time, as
the first attempt does. Segment names are never backdated, which matters
because brokers treat a segment as new based on the creation time in its name.
- New segment ZK metadata is created atomically, only if absent, and is
never overwritten, because the segment might already be consuming or committed.
- **Idempotent IdealState update.** The updater in
`updateIdealStateOnSegmentCompletion` skips an update that is already applied
(all replicas of the committing segment ONLINE and the new segment present).
Previously, a retry after a write that succeeded but was reported as failed
failed every remaining attempt on `Failed to find instance in CONSUMING state`,
and with group commit it failed every update batched with it. This also applies
to non-pauseless commits.
- **Failure handling after step 3.**
- The controller re-reads the IdealState and proceeds if the update was
applied.
- Otherwise it keeps the new segment's ZK metadata, for the next attempt
or for the validation manager, which already adds such a segment ("ZK metadata
but not in IdealState", the same as after a controller stop between steps 2 and
3).
- It removes the metadata only when the new segment is absent from the
IdealState and the committing segment is no longer CONSUMING. That is the only
state in which no attempt can still add it: adding requires the committing
segment to be CONSUMING, and the IdealState version check rejects a write based
on an older IdealState.
- **Duplicate-sequence segments in the validation manager.** Two new
segments with the same sequence number can still appear in two cases: attempts
on two controllers in different minutes, or a kept new segment racing a
validation repair that started before the segment was created. When several
segments of a partition have the highest sequence number,
`RealtimeSegmentValidationManager` now takes the one in the IdealState as the
latest segment, and logs a warning. Before, it took whichever was listed first,
and could fail every run with `Segment … is a duplicate of existing segment …`.
This also covers duplicates left behind by older code paths.
No ZK metadata is rolled back, so the IdealState version check of step 3
stays the only fence against a concurrent repair by the validation manager. A
retry with a different end offset still fails as before.
Cost: no change on a successful first attempt. A resumed attempt makes one
existence check per minute since step 1 (at most the max segment completion
time in minutes, plus 3). The failure path adds one IdealState read; step 2
already reads the IdealState on every commit.
## Testing
New tests in `PinotLLCRealtimeSegmentManagerTest`:
- Resume after an IdealState update failure. The retry is 2 minutes later
and uses the same new segment, unchanged.
- A first attempt that fails before step 2. The resume 6 minutes later
creates the new segment with its own creation time, and the next resume reuses
it.
- An update that was applied but reported as failed.
- A retry after a completed commit start does not overwrite the new segment.
- Another controller completes the commit start between step 1 and step 2.
The new segment, already committed, is not overwritten.
- Another controller adds the new segment while this attempt's IdealState
update fails. Its ZK metadata is kept.
- The validation manager repairs the partition with another segment. This
attempt's new segment is removed, and the IdealState is unchanged.
- No resume with a different end offset, or after the max segment completion
time.
- The production updater, through group commit and single commit, with a
write that is applied but reported as failed. It retries once and does not
write again.
- A commit start keeps its new segment while a concurrent repair adds
another one with the same sequence number. The validation manager then keeps
the IdealState segment as the latest, whichever order the segments are listed
in.
- The production atomic create, when another attempt creates the segment
between the existence check and the create.
I checked each of the main tests by removing the corresponding part of the
change and confirming the test fails: the updater no-op, the earlier-attempt
probe, create-if-absent, keeping the new segment, and the duplicate-sequence
tie-break.
Existing tests pass: `PinotLLCRealtimeSegmentManagerTest`,
`SegmentCompletionTest`, `SegmentCompletionFSMFactoryTest`,
`RealtimeSegmentValidationManagerTest`, and
`PauselessRealtimeIngestionIntegrationTest`. The integration test injects
failures before steps 2 and 3, and its scenarios still recover.
Related to #<PR2> (validation repair after a failed IdealState write) and
#<PR3> (cheaper IdealState update attempts).
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]