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

Siyao Meng updated HDDS-17744:
------------------------------
    Attachment: MC-1-report-move-into-deleted-dir-as-delete.patch

> Optimized snapshot diff omits a file or directory moved into a directory that 
> is deleted before its children are purged
> -----------------------------------------------------------------------------------------------------------------------
>
>                 Key: HDDS-17744
>                 URL: https://issues.apache.org/jira/browse/HDDS-17744
>             Project: Apache Ozone
>          Issue Type: Bug
>    Affects Versions: 2.3.0
>            Reporter: Siyao Meng
>            Priority: Major
>         Attachments: MC-1-report-move-into-deleted-dir-as-delete.patch, 
> TestBugMC1RenameIntoDeletedDir.java
>
>
> h3. Mechanism
> A file or directory moved under a directory that is then deleted keeps its 
> row in {{fileTable}} or {{directoryTable}} until the directory deep clean 
> purges the children, so a snapshot taken in between holds it under a parent 
> that no longer exists in {{directoryTable}}. The merge join sees the same 
> objectId on both sides and classifies it as RENAME. In 
> {{MergeJoinSnapDiffWriter.resolveReportEntries}} the target path cannot be 
> resolved, so the entry becomes null, and {{writeReportEntriesForRows}} drops 
> it with a DEBUG log. Nothing else in the report removes it. The legacy diff 
> ({{SnapshotDiffManager.generateDiffReport}}) handles the same shape in its 
> branch for an old path that resolves and a new path that does not, and 
> reports a DELETE of the old path.
> h3. Trigger
> FSO bucket, {{ozone.om.snapshot.diff.optimized.enabled=true}} (default false; 
> the optimized diff was added by HDDS-15391 and is not in any release yet):
> # Create file {{/a}} and directory {{/b}}, take snapshot snap1.
> # {{mv /a /b/a}}, then {{rm -r /b}}.
> # Take snapshot snap2 before the directory deleting service has purged the 
> children of {{b}} (it runs on an interval).
> # Request the snapshot diff snap1 to snap2, ordered or unordered.
> h3. Impact
> The DONE report is {{[DELETE b]}} instead of {{[DELETE a, DELETE b]}}. 
> Replaying it onto snap1 keeps {{/a}}, which does not exist in snap2. The 
> report is persisted and returned for every later read of the pair. The legacy 
> diff of an identical pair on the same OM reports both deletes. If the moved 
> object is a directory, its whole subtree stays on replay: moving a directory 
> into a trash directory and then deleting the trash directory recursively is a 
> common pattern.
> h3. Reproduction
> [^TestBugMC1RenameIntoDeletedDir.java] ({{hadoop-ozone/integration-test}}) 
> runs the steps above through the FileSystem and snapshot APIs on a mini 
> cluster, with forced full diff and native diff disabled so the native library 
> is not needed. The base class keeps the KeyManager background services 
> stopped, which holds the window open. It first computes the legacy report of 
> an identical pair (both deletes), then asserts the optimized unordered and 
> ordered reports. On the unfixed code it fails with {{Expecting actual: [- 
> ./b] ... could not find the following elements: [- ./a]}}; with the patch it 
> passes.
> h3. Patch
> [^MC-1-report-move-into-deleted-dir-as-delete.patch], against 
> d3b75c75bf9ad475551202477c3a21a3f4b968b7. It also applies to master at 
> bbc8505e00d.
> In the RENAME branch of {{MergeJoinSnapDiffWriter.resolveReportEntries}}, 
> when the source path resolves and the target path does not, the writer now 
> emits DELETE of the source path, the same rule as the legacy diff. Entries 
> where neither path resolves are still dropped. The dependency ordered report 
> needs no extra handling, since the graph takes the entry type from the report 
> entry.
> Covered by {{testRenameIntoDeletedDirectoryReportsDeleteOfSource}} in the 
> existing {{TestMergeJoinSnapDiffWriter}}, for both report orderings. Without 
> the change it fails because only {{DELETE b}} is reported. With it the 
> snapshot diff unit suites and {{TestSnapshotDiffManager}} (193 tests) and 
> {{TestOptimizedSnapshotDiff}} with the native library pass, and checkstyle is 
> clean.
> One previously correct report changes: if the source's parent is deleted as 
> well ({{mv /c/a /b/a}}, {{rm -r /b}}, {{rm -r /c}}), the report gains a 
> redundant but harmless {{DELETE c/a}} next to {{DELETE c}}, ordered before 
> it; the legacy diff emits it too.
> Not changed: if the moved file was also modified, a MODIFY of the old path is 
> still emitted next to the DELETE (the legacy diff emits only the DELETE).
> Found by TLA+ model checking and code review of the OM optimized snapshot 
> diff paths under HDDS-15926, on commit 
> d3b75c75bf9ad475551202477c3a21a3f4b968b7. 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