Repository navigation
storage: only clear a volume's attachment if it is still on the detac… - #8
Open
dloszewski-cni wants to merge 1 commit into
Open
dloszewski-cni wants to merge 1 commit into
dloszewski-cni wants to merge 1 commit into
Conversation
…hing VM The execution-time skip added in this branch reads volume.getInstanceId() at the top of orchestrateDetachVolumeFromVM, but the attachment row is not cleared until after the agent round-trip returns. On a busy host that gap was 2-3 minutes in the environment reported in apache#14214, and an attach that lands inside it is still cleared by the straggler, so the race is narrowed rather than closed. Make the final clear conditional as well: - VolumeDao.detachVolume(volumeId, vmId) puts both id and instance_id in the search criteria and reports whether a row actually changed, so a volume that moved while the detach was in flight is left alone. This is the same shape as VolumeDaoImpl.updateState and VMInstanceDaoImpl.updateState, which already guard their updates on the state they expect to find. - The caller logs which VM the volume now belongs to, re-reads it, and skips the rest of the success block, since revoking access or publishing a detach event would assert something that is no longer true. This closes the database-write half of the race. It does not close hypervisor-side divergence: the DettachCommand has already succeeded by this point, so on a losing update the disk may be unplugged while the row says attached. Leaving the newer attachment intact is still strictly better than clearing it, and the warning names the volume and both VMs so the inconsistency can be reconciled. Tests cover both halves: the DAO update asserting that instance_id is in the where clause and that both ids are bound, and the service path on the branch that actually performs the agent round-trip, asserting that a skipped stale detach performs no disk statistics collection and publishes no usage event. Refs apache#14214, apache#14401 Signed-off-by: Dave Loszewski <dloszewski@centripetalnetworks.com>
dloszewski-cni
force-pushed
the
fix-14214-dao-cas
branch
from
October 27, 2026 16:24
de40ad9 to
7675371
Compare
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.
Follow-up to apache#14401, as you suggested there — this is the branch I mentioned, rebased onto
fix-stale-detach-volumeso the tests come with it.Your execution-time skip is right, and
shouldDetachBeSkippedis kept here as-is. What thisadds is the second half. The skip reads
volume.getInstanceId()at the top oforchestrateDetachVolumeFromVM, but the attachment row is not cleared until after the agentround-trip returns. In my environment that round-trip ran 2-3 minutes on a busy host, and an
attach that lands inside that window is still cleared by the straggler. So the race is
narrowed rather than closed.
This makes the final clear conditional as well:
VolumeDao.detachVolume(volumeId, vmId)puts bothidandinstance_idin the searchcriteria and returns whether a row actually changed. A volume that moved while the detach
was in flight is left alone. It is the same shape as
VolumeDaoImpl.updateStateandVMInstanceDaoImpl.updateState, which already guard their updates on the state theyexpect to find.
What this does and does not close. It closes the database-write half. It does not close
hypervisor-side divergence: by the time the update runs, the
DettachCommandhas alreadysucceeded, so on a losing update the disk may be unplugged while the row still says attached.
Not clearing is still strictly better than clearing, and the warning now names the volume and
both VMs so the inconsistency can be found, but I did not want to overstate it.
One thing I deliberately did not decide, because it is your branch. On the losing path the
early return also skips the
answer.getContextParamhandling —datastoreNametopoolId/poolType,volumePathtopath,chainInfo. SkippingrevokeAccess,provideVMInfoand the usage event is clearly right: they would assert an ownership that isno longer true. But those three context params record state the hypervisor actually changed,
and they are not attachment columns, so skipping them can leave
path/chain_infostale fora volume that now belongs to the other VM. Hoisting them above the conditional update would
fix that, but it widens the change and it is a storage call I would rather you made. Happy to
do it either way.
Tests, on top of the four already in this branch:
instance_idandthat both ids are bound — I wrote the first version of these without that assertion and
they passed with the guard deleted, so the assertion on the where clause is the point.
There is also one for the ROOT to DATADISK conversion, which was otherwise uncovered.
round-trip, which is the only path the race exists on; the existing tests here all use a
stopped VM, so they never enter it.
testDetachVolumeSkipped*tests but assert more: noagent round-trip, no
collectVmDiskStatistics, nofindClusterAndHostIdForVm, no detachusage event. Drop whichever pair you prefer — your branch, your call.
Verified on this branch:
VolumeDaoImplTest12/12 andVolumeApiServiceImplTest168/168.As a control I reverted each half separately and re-ran. Removing the
instance_idconditionfrom the DAO fails the where-clause test; reverting the caller to the unconditional clear
fails three service tests, including the round-trip one.
The attach-side case (occurrence 4 in apache#14214) is still not addressed by either patch, and I
have not root-caused it.