[ 
https://issues.apache.org/jira/browse/HDDS-17604?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Siyao Meng updated HDDS-17604:
------------------------------
    Attachment: MC-1-skip-purge-of-snapshot-not-deleted.patch

> A duplicate snapshot purge removes a new ACTIVE snapshot that was created 
> with the purged snapshot's name
> ---------------------------------------------------------------------------------------------------------
>
>                 Key: HDDS-17604
>                 URL: https://issues.apache.org/jira/browse/HDDS-17604
>             Project: Apache Ozone
>          Issue Type: Bug
>    Affects Versions: 1.4.0, 2.0.0, 1.4.1, 2.1.0, 2.2.0, 2.1.1, 2.1.2, 2.2.1
>            Reporter: Siyao Meng
>            Priority: Major
>         Attachments: MC-1-skip-purge-of-snapshot-not-deleted.patch, 
> TestBugMC1DuplicatePurgeRecreatedSnapshot.java
>
>
> h3. Mechanism
> A {{SnapshotPurgeRequest}} carries only snapshot table keys 
> ({{/volume/bucket/name}}). {{OMSnapshotPurgeRequest.validateAndUpdateCache}} 
> purges whatever row the key resolves to when the entry is applied. It does 
> not check that the row is still the snapshot {{SnapshotDeletingService}} 
> selected, or that it is still {{SNAPSHOT_DELETED}}. The only guard, added by 
> HDDS-10408, skips a key whose row is already gone. 
> {{OMSnapshotPurgeResponse.addToDBBatch}} then reads the row by key from the 
> DB and deletes it together with its checkpoint directory, also for keys that 
> the request skipped.
> So if a second purge for a key is applied after a client created a new 
> snapshot with the same name, the new ACTIVE snapshot is removed from the 
> snapshot chain, the snapshot table and the disk on every OM.
> h3. Trigger
> # Create snapshot {{s1}} in a bucket, then delete it.
> # {{SnapshotDeletingService}} on the leader submits a purge for {{s1}}. The 
> entry commits, then leadership moves to another OM before that OM has applied 
> it.
> # The new leader reports ready as soon as Ratis dispatches its startup entry 
> to the state machine ({{LeaderStateImpl.checkReady}} from 
> {{RaftServerImpl.applyLogToStateMachine}}), while OM still has earlier 
> entries queued on its single apply executor, so the purge can still be queued 
> (the leader readiness gap is HDDS-17579). {{SnapshotDeletingService}} checks 
> only {{OzoneManager.isLeaderReady}} and {{shouldIgnoreSnapshot}} (status 
> DELETED and changes flushed) and keeps no record of submitted purges, so it 
> can build a second purge for {{s1}}.
> # A client creates a snapshot named {{s1}} again, and the create is ordered 
> after the first purge and before the second. It succeeds with a new snapshot 
> ID, because the first purge's cache tombstone makes {{isExist}} return false.
> # The second purge resolves the key to the new ACTIVE snapshot and purges it.
> Steps 2 to 4 need a leader change while the first purge is unapplied on the 
> new leader, a {{SnapshotDeletingService}} run (default interval 30s) inside 
> that apply backlog, and a create with the same name submitted in the same 
> window. The window is narrow. The readiness gap of step 3 is shown on a 3 OM 
> mini cluster in HDDS-17579; the duplicate purge on top of it was not run on a 
> cluster. HDDS-16795 is the same pattern in {{KeyDeletingService}}. This issue 
> is not a duplicate of either: it is a different consequence, and the purge 
> needs its own check even after HDDS-17579 is fixed.
> On 1.4.0 and 1.4.1 the duplicate does not need a leader change: 
> {{SnapshotDeletingService}} selected snapshots by iterating the on disk 
> snapshot table, so a run between the first purge's apply and its flush could 
> build it on a single leader.
> h3. Impact
> The client's create returned success, but afterwards the snapshot is not 
> found. Its row is deleted from the snapshot table, its chain entry is 
> removed, so a chain rebuilt from the table on restart does not have it 
> either, and its checkpoint directory is deleted. The deep clean flags of the 
> following snapshots are reset as for a normal purge. Snapshot create moves 
> the bucket's pending deletes ({{deletedTable}}, {{deletedDirTable}}, 
> {{snapshotRenamedTable}} entries) from the active DB into the new snapshot, 
> and the purge does not move them on first, so they are lost and their blocks 
> are never reclaimed (argued, not run). The loss is replicated and permanent.
> h3. Reproduction
> PASS, deterministic, unmodified source. 
> [^TestBugMC1DuplicatePurgeRecreatedSnapshot.java] 
> ({{hadoop-ozone/ozone-manager}}) uses the request level fixture of the 
> snapshot request tests (real metadata manager, snapshot chain manager, 
> snapshot manager and checkpoint directories, mocked {{OzoneManager}}). It 
> runs create, delete, purge, create with the same name and the same purge 
> again through {{preExecute}}, {{validateAndUpdateCache}} and the response DB 
> update. After the second purge the new snapshot's row is gone from the cache 
> and the DB, a chain rebuilt from the table does not have it, its checkpoint 
> directory is deleted, and {{SnapshotUtils.getSnapshotInfo}} reports it as not 
> found. A passing test means the defect is present. The test supplies the 
> second purge; how it arises on a cluster (Trigger, steps 2 and 3) is argued 
> from the code, not run.
> h3. Suggested fix
> The patch makes the apply side skip a key whose row is not 
> {{SNAPSHOT_DELETED}} and passes only the purged keys to the response. It 
> fixes the reported case without a protocol change. It does not cover a 
> snapshot recreated with the same name and deleted again before the duplicate 
> purge is applied: that row is DELETED and is still purged before 
> {{SnapshotDeletingService}} has moved its pending deletes, which are then 
> lost as above. Carrying the snapshot IDs that {{SnapshotDeletingService}} 
> selected in {{SnapshotPurgeRequest}} and comparing them at apply would cover 
> that too, but needs a new request field behind a layout feature.
> h3. Patch
> [^MC-1-skip-purge-of-snapshot-not-deleted.patch], against 
> 284fad307bfd129fca3f4966d854ac45ea3b0d11. It also applies to master at 
> 6135e81a09ac6d618dc0ad4d220dd8cf254586b6.
> {{OMSnapshotPurgeRequest.validateAndUpdateCache}} skips, with a warning, a 
> key whose current row is not {{SNAPSHOT_DELETED}}, and gives 
> {{OMSnapshotPurgeResponse}} only the keys it purged, so the response no 
> longer deletes the row or checkpoint of a skipped key. A skipped row is not 
> rewritten, unless the same request updated it as the next snapshot of a 
> purged one. {{NumSnapshotDeleted}} is decremented by the number of purged 
> keys, which now are all DELETED.
> On a mixed version ring during a rolling upgrade, in exactly the bug case an 
> upgraded OM keeps the recreated snapshot and an old one purges it; every 
> other purge behaves the same on both versions.
> Covered by two new tests in the existing 
> {{TestOMSnapshotPurgeRequestAndResponse}}, next to 
> {{testDuplicateSnapshotPurge}} from HDDS-11997: 
> {{testDuplicateSnapshotPurgeKeepsRecreatedSnapshot}} (the recreated snapshot 
> is unchanged in the cache, the DB, the chain and on disk after the duplicate 
> purge) and {{testSkippedSnapshotNextToPurgedSnapshotIsUpdated}}, run with the 
> skipped key first and with the purged key first (a skipped snapshot that 
> follows a purged one keeps its row and checkpoint, and gets its deep clean 
> flags and previous snapshot IDs updated in the cache and the DB). Without the 
> change all three cases fail because the recreated snapshot is purged. Four 
> existing tests in the suite purged ACTIVE snapshots directly; they now mark 
> them deleted first.
> Found by TLA+ model checking and code review of the OM snapshot purge, set 
> property and double buffer apply paths under HDDS-15926, on commit 
> 284fad307bfd129fca3f4966d854ac45ea3b0d11. Checked against HDDS issues and 
> apache/ozone pull requests for duplicates before filing. The attached patch 
> is a proposal for review. Generated with Specula (Claude Opus 5.5).



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to