Repository navigation
Conversation
k-morozov
self-requested a review
October 13, 2026 09:34
filimonov
marked this pull request as draft
October 15, 2026 09:47
The plane already carries the claim and the remount re-anchor, and the background renewal moves onto it next; "farewell" names one of its users. Signed-off-by: Mikhail Filimonov <mfilimonov@altinity.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`Retry::untilDefinitive` has no window and no lease bound. Its reissues wait a draw from [0.8, 1.2] of 1000 ms minus what the failed attempt took (`Retry::pauseAfterAttempt`) instead of the growing backoff, so the first good second after an outage ends a retry series. Existing policies are unchanged. Signed-off-by: Mikhail Filimonov <mfilimonov@altinity.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The background renewal gave up at the lease deadline, fenced the mount and remounted under a fresh epoch, although the store had not answered and nothing had touched the slot. It now keeps one tuple and retries it on the lease plane under `Retry::untilDefinitive`: - a refusal waits one renewal period and sends the same body again; - a refused precondition whose read failed repeats only the read; - a commit, a slot that moved, a local failure, a stop or a park ends the series. A stop between engine calls, after a refusal or a read that found the slot unchanged, leaves the renewer active so the farewell still runs; a stop during a call that sent an attempt, or while the reads repeat, is terminal and classified as cancelled. A committed deadline is published in `DriverLease::finish`, under the driver mutex, so a remount cannot arm a new epoch between a commit and its deadline. The lease plane sleeps interruptibly on a stop or a park, like the mount plane. The startup and remount re-anchors stay bounded by the lease, and so does a runtime with `bounded_background_renewal`. Closes: #2431 Signed-off-by: Mikhail Filimonov <mfilimonov@altinity.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The decommission tool opens its pool with the background renewal. An admin claim that cannot renew should end at its lease rather than pause, so `Pool::openForDecommission` sets `bounded_background_renewal`. Signed-off-by: Mikhail Filimonov <mfilimonov@altinity.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Writes stop being admitted once the lease has less than two attempt envelopes plus the safety margin left. `system.cas_mounts` now shows `not_live` / `lease_expired` from that same moment, computed by the predicate admission uses, and one WARNING per pause names the writer epoch and the last renewal error. The refusal texts a write meets during a pause say that writes resume once the renewal is confirmed. A clean shutdown during a pause skips the farewell, which has no lease room left, and leaves the slot for GC to observe. Signed-off-by: Mikhail Filimonov <mfilimonov@altinity.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Shared fixtures for the renewal series (`CASHeartbeatUntilDefinitive`, `BackgroundRenewal`) and tests for every way a series ends, the refusal pause, stop and park, the late commit against GC, the pause report and the teardown during a pause. Three runtime tests that relied on a transient fault ending the background renewal fence the slot instead. The integration test checks that a mount PUT outage longer than the lease is a pause under the same `writer_epoch`. Signed-off-by: Mikhail Filimonov <mfilimonov@altinity.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Mikhail Filimonov <mfilimonov@altinity.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
filimonov
force-pushed
the
fix/antalya-26.6/cas-mount-renewal-until-definitive
branch
from
October 16, 2026 04:34
2f650d9 to
e3588e3
Compare
filimonov
marked this pull request as ready for review
October 16, 2026 05:37
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The background CAS mount lease renewal used to give up when it got no definitive answer from the object store inside its budget. It then tripped the fence and started a remount under a fresh epoch. A short object-store outage (tens of seconds) cost about 40 s without writes, restarted merges and counted a
CASMountLeaseLost, although nothing had touched the slot and the holder still had its lease on its own clock. Now the renewal retries until the store gives a definitive answer. While the lease cannot cover a write, writes pause and resume under the same epoch; the mount is no longer lost.The branch is rebased on
antalya-26.6-20261008, which already contains #2509 and #2513. It is not stacked any more. Read it commit by commit.Rollout
cas_mount_lease_ttl_ms.How it works
cas_mount_renew_period_msthe renewal thread builds one tuple and keeps it for the whole series of attempts: key, body bytes, the expected ETag of the last confirmed body,write_attempt_id, andstart, taken before the first request.PUTruns on the lease plane underRetry::untilDefinitive, which has no deadline. After an unclear attempt, the next one waits a uniform draw in [0.8, 1.2] of 1000 ms minus what the attempt took (Retry::pauseAfterAttempt). There is no growing backoff, so the first good second after an outage ends the series.AccessDenied,MalformedXML, …) waits one renewal period, then a new engine call sends the same tuple. A refused read waits the same period. A clean412whose read failed repeats only the read. A refusal after an unclear attempt is settled inside the call.DriverLease::finishpublishes the deadlinestart + leaseunderdriver_mutex, before the driver leaves the call, so a remount cannot arm a new epoch in between. The store is unconditional; it is monotonic because a renewal starts only after the previous one finished, and the renewer cannot be replaced during a call.gc_fenced, a deleted slot, or our token over other bytes. This goes to the existing loss handling.NotAttempted: nothing of ours is in flight, and the farewell still hands the slot back.cancelled: the request may still land, or the slot may have moved. No farewell runs.2 × envelope + cas_lease_safety_margin_msleft. This rule is unchanged.system.cas_mountsshowslifecycle = 'not_live'andlifecycle_reason = 'lease_expired', withlifecycle_since= when writes paused.WARNINGper pause. It names thewriter_epochand the last renewal error:CAS mount lease of '<srid>' under writer_epoch <E> has too little time left for a write … Last renewal error: ….INFO, and leaves the slot for GC to observe.bounded_background_renewal).expires_at_msalready in the past. GC does not fence the slot for it, because GC fences only a token it watched unchanged for its whole threshold.Settings (no new ones)
cas_mount_lease_ttl_ms: the length of the right to write from each confirmed renewal.cas_mount_renew_period_ms: the interval between renewal starts, and the wait after a refusal.cas_attempt_timeout_ms: the budget of one attempt, hence the admission envelope.cas_lease_safety_margin_ms: unchanged.Risks / notes
CASMountRenewalDeadlineExceedednow counts only bounded renewals: the startup and remount re-anchors, and a decommission's background renewal. An outage of a normal mount no longer moves it orCASMountLeaseLost; alert onsystem.cas_mounts.lifecycle_reason = 'lease_expired'instead.Livewhile admission is closed). Tracked as backlog task CAS-256.mounts-and-leases.md,debugging.md,monitoring.md,troubleshooting.md,metrics_and_events.md,cas_mounts.md.Testing
CASRetrySpacing.*andCASRequestsSpacing.*: no deadline, spaced attempts, the standard backoff unchanged.CASHeartbeatUntilDefinitive.*, one tuple past the lease and the refusal pause:RetriesOneTuplePastTheLease,ARefusedRenewalIsSentAgainAfterTheRefusalPause,AfterACleanPreconditionRefusalOnlyTheReadRepeats.CASHeartbeatUntilDefinitive.*, every way a series ends after a refused precondition:AReadThatFindsAForeignHolderEndsTheSeries,AReadThatFindsOurSlotFencedEndsTheSeries,AReadThatFindsTheSlotDeletedEndsTheSeries,OurTokenOverOtherBytesEndsTheSeries.CASHeartbeatUntilDefinitive.*, stops and liveness:AStopBetweenCallsEndsTheSeriesAsCancelled,AStopDuringTheReadsEndsTheSeriesWithoutAFarewell,ALostLivenessDuringTheReadsEndsTheSeriesAsALoss.CASHeartbeatUntilDefinitive.ALateCommitRestartsTheGcObservation: a late commit against GC.CASMountRuntime.*: a long outage is a pause under the same epoch; an old epoch's renewal does not move the new deadline; a late commit reports a true reason; a remount request ends a series.CASMountRuntime.*, stop and park: they end the refusal wait at once, and the farewell survives a stop.CASMountRuntime.*, the rest: one refusal waits one period; the decommission renewal ends inside its lease; the pause is logged once with the last error; a clean shutdown during a pause leaves the slot.CASLifecycleSnapshot.*: the row isnot_livefrom the admission edge.CASHeartbeat.CancellationAfterSendIsTerminalAndForbidsReleasenow also asserts classificationcancelled.test_long_mount_put_outage_pauses_under_the_same_epoch;test_cas_mount_renewal_retry6 passed.CAS*gate: 2670 passed (release), 2674 passed (ASan, no error).models/mount-lease-series-v2@1e4f3222015, all batteries green. Pause safetyResumedEpochNeverWritesAfterGcActedholds inCaRenewalDriver.Closes: #2431
Related: #2509
Related: #2513
Related: #2516
Changelog category (leave one):
Changelog entry (a user-readable short description of the changes that goes to CHANGELOG.md):
A CAS mount lease renewal retries until the object store gives a definitive answer instead of giving up at a deadline. While the lease is too short to admit a write, writes pause and resume under the same epoch once a renewal is confirmed, instead of losing the mount and remounting.
Documentation entry for user-facing changes
CI/CD Options
Exclude tests:
Regression jobs to run: