[
https://issues.apache.org/jira/browse/HDDS-17746?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Siyao Meng updated HDDS-17746:
------------------------------
Attachment: TestBugCR2SignedObjectIdMergeJoin.java
> Optimized snapshot diff merge join compares objectIds as signed longs while
> the lists are in unsigned byte order
> ----------------------------------------------------------------------------------------------------------------
>
> Key: HDDS-17746
> URL: https://issues.apache.org/jira/browse/HDDS-17746
> Project: Apache Ozone
> Issue Type: Bug
> Affects Versions: 2.3.0
> Reporter: Siyao Meng
> Priority: Minor
> Attachments: CR-2-compare-object-ids-unsigned-in-merge-join.patch,
> TestBugCR2SignedObjectIdMergeJoin.java
>
>
> h3. Mechanism
> {{SnapDiffJobStore}} keys the new and old list column families by the
> objectId as 8 big endian bytes, and the default bytewise comparator returns
> them in unsigned order. {{MergeJoinSnapDiffWriter.classifyMergeJoin}}
> advances through the two lists with signed {{<}} and {{>}}. The orders differ
> only when the lists hold objectIds of both signs. Current OMs always use
> epoch 2, so new objectIds are negative as signed longs. Older objectIds can
> be positive:
> * Ozone 1.0.0 and earlier built objectIds as the transaction index shifted
> left by 8.
> * Ozone 1.1.0 to 1.4.1 used epoch 1 when {{ozone.om.ratis.enable}} was false
> (the default was true).
> ObjectIds are never rewritten, so a bucket holding keys written on 1.0.0
> (LEGACY layout after the upgrade), or keys written by a non Ratis OM on 1.1.0
> to 1.4.1, can hold both after an upgrade. The merge then loses step: matching
> entries fall through to the CREATE and DELETE branches separately.
> h3. Trigger
> A bucket that holds a positive (legacy) objectId and current objectIds,
> {{ozone.om.snapshot.diff.optimized.enabled=true}}. Take snapshot s1, delete
> the legacy key (with several, the one with the highest objectId; a lower one
> is matched correctly) and optionally modify a current key, take snapshot s2,
> and request the diff s1 to s2, ordered or unordered, for an OBS, LEGACY or
> FSO bucket. The merge join was added by HDDS-15391 and is not in any release
> yet (the optimized diff is off by default).
> h3. Impact
> In a full diff, once the legacy key with the highest objectId is deleted,
> every current key in the bucket is reported: unchanged ones as DELETE,
> modified ones as DELETE plus CREATE. A consumer that replays the report
> deletes them all. In a DAG diff the same happens to every changed current
> key. The report is a persisted DONE report. Once the new list's head is a
> current (negative) id while the old list's head is still the deleted positive
> id, every remaining new entry is taken as a CREATE (present markers emit
> nothing) and every remaining old entry as a DELETE. A unit run of the full
> diff shape (legacy1 kept, legacy2 deleted, four unchanged and one modified
> current key) gave {{[- ./legacy2, - ./cur1, - ./cur2, - ./cur3, - ./cur4, -
> ./cur5, + ./cur5]}} on the unfixed code and {{[- ./legacy2, M ./cur5]}} with
> the patch; deleting legacy1 instead gave {{[- ./legacy1, M ./cur5]}} on both.
> h3. Reproduction
> [^TestBugCR2SignedObjectIdMergeJoin.java] ({{hadoop-ozone/ozone-manager}})
> opens its own RocksDB in a temporary directory, writes the list rows the
> readers would write for one legacy positive id and two current ids, and runs
> the real {{MergeJoinSnapDiffWriter.writeReport}}, for OBS and FSO. The mixed
> sign case fails on the unfixed code with {{Expecting actual: [- ./older, -
> ./same, - ./modified, + ./modified] to contain exactly in any order: [-
> ./older, M ./modified]}}; a control with current ids only passes. With the
> patch all four cases pass. The ids are written directly because a current OM
> cannot create a positive objectId; the upgrade path itself was not run.
> h3. Patch
> [^CR-2-compare-object-ids-unsigned-in-merge-join.patch], against
> d3b75c75bf9ad475551202477c3a21a3f4b968b7. It also applies to master at
> bbc8505e00d.
> The two comparisons in {{classifyMergeJoin}} use {{Long.compareUnsigned}},
> matching the column family order. For ids of one sign, which is every bucket
> created on 2.x, nothing changes.
> Covered by {{testClassificationWithObjectIdsOfBothSigns}} in the existing
> {{TestMergeJoinSnapDiffWriter}}, for OBS and FSO. Without the change both
> fail as above. With it the snapshot diff unit suites and
> {{TestSnapshotDiffManager}} (193 tests) pass, and checkstyle is clean.
> Found by code review of the OM optimized snapshot diff paths, as part of the
> TLA+ verification effort 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]