HDDS-15390. Utility to generate dependency ordered snapdiff report.#10778
HDDS-15390. Utility to generate dependency ordered snapdiff report.#10778SaketaChalamchala wants to merge 4 commits into
Conversation
…encyGraph The dependency graph indexed multiple non-delete nodes per objectId (e.g. RENAME + MODIFY) but never added an edge between them, so topological sort could emit RENAME before a MODIFY reported at the from-snapshot source path. Add an intra-object edge oriented by which path the entry carries, plus a reproduction test. Co-authored-by: Cursor <cursoragent@cursor.com> Change-Id: Ib7ebd867f58b864f17ec28f61843390a34cf0705
Potential issue: same-object RENAME/MODIFY are not ordered
Concrete exampleObject No edge links the two nodes, so both have Note the existing Reproduction test (fails on current code)@Test
void testModifyAtSourcePathOrderedBeforeRename() {
List<SnapDiffDependencyEntry> entries = Arrays.asList(
entry(2L, 1L, RENAME, "parent/a.txt", "parent/b.txt"),
entry(2L, 1L, MODIFY, "parent/a.txt"));
List<DiffType> orderedTypes = toDiffTypes(sort(entries));
assertEquals(Arrays.asList(MODIFY, RENAME), orderedTypes);
}Suggested fixAdd an intra-object edge oriented by which path the entry carries: an entry at the RENAME source path must precede the RENAME; the RENAME must precede an entry at its target path. With that edge, the reproduction test and all existing I pushed a candidate fix + the reproduction test to a branch for reference: Found via automated review (Cursor Bugbot). |
smengcl
left a comment
There was a problem hiding this comment.
Thanks @SaketaChalamchala for the patch.
|
|
||
| addPathConflictEdges(deleteNodesByPath, createNodesByPath, | ||
| renameNodesByTargetPath); | ||
| addRenameBeforeCreateEdges(renameNodesBySourcePath, createNodesByPath); |
There was a problem hiding this comment.
Renames also need path dependencies on other renames. For A -> B and B -> C, B -> C must run first to free B. Currently only RENAME -> CREATE is covered, so input order [A -> B, B -> C] is returned unchanged and the first rename cannot be replayed. Please add the corresponding rename-to-rename edge, with chain and cycle tests.
| public SnapDiffDependencyEntry(long objectId, long parentObjectId, | ||
| DiffReportEntry reportEntry) { |
There was a problem hiding this comment.
A cross-parent rename needs both parent IDs. For A/B -> C/B with DELETE A and CREATE C, C must be created before the rename, while A must remain until after it. A single parentObjectId can enforce only one of these dependencies. Please carry the source and target parent IDs, or equivalent explicit dependencies.
| if (entry.isDelete()) { | ||
| if (parentDeleteNodeId != null) { | ||
| addEdge(nodeId, parentDeleteNodeId); | ||
| } |
There was a problem hiding this comment.
The DELETE branch ignores a parent RENAME. For [RENAME A -> B, DELETE A/child], the input order remains unchanged and the delete then addresses a path that has moved. Please add a child DELETE -> parent RENAME edge and a test for this case.
| orderedEntries.add(nodes.get(nodeId)); | ||
| for (int dependentNodeId : adjacencyList.get(nodeId)) { | ||
| int updatedInDegree = inDegree.get(dependentNodeId) - 1; | ||
| inDegree.put(dependentNodeId, updatedInDegree); |
There was a problem hiding this comment.
getOrderedEntries() mutates the graph’s stored inDegree. After one call, a second call can enqueue every node and return input order instead of dependency order. Please sort using a local copy of the indegrees or cache the result, and add a repeated-call test.
| adjacencyList.put(nodeId, new HashSet<>()); | ||
| inDegree.put(nodeId, 0); |
There was a problem hiding this comment.
Each node allocates an empty HashSet plus boxed entries in two HashMaps, before the temporary path and object indexes. The default changed-key limit is one billion, so this representation can exhaust OM heap far below the configured limit. Please consider primitive, lazy, or batched graph state and add scale coverage.
What changes were proposed in this pull request?
Developed with the help of Cursor AI.
This PR is intended as the foundation for a more efficient snapshot diff (HDDS-9154).
Baseline snapshot diff reports order entries by diff type (
DELETEs first, thenRENAME/CREATE/MODIFY). That ordering is not always safe to replay. For example, ifA/Bis renamed toC/Band directoryAis deleted, replaying theDELETEbefore theRENAMEfails on because the rename source no longer exists.This PR adds isolated utilities for dependency-ordered snapshot diff report generation.
SnapDiffDependencyEntry
SnapDiffDependencyGraph
What is the link to the Apache JIRA
https://issues.apache.org/jira/browse/HDDS-15390
How was this patch tested?
Unit Test.