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

Siyao Meng updated HDDS-16764:
------------------------------
    Attachment: TestBugMC7ExpiredOpenKeyHsyncRace.java

> DeleteOpenKeys removes a key hsync'ed after the cleanup scan and queues its 
> blocks for deletion, and the next overwrite commit terminates the OM
> ------------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: HDDS-16764
>                 URL: https://issues.apache.org/jira/browse/HDDS-16764
>             Project: Apache Ozone
>          Issue Type: Bug
>            Reporter: Siyao Meng
>            Priority: Critical
>         Attachments: 
> MC-7-keep-open-key-hsynced-after-cleanup-selection.patch, 
> TestBugMC7ExpiredOpenKeyHsyncRace.java
>
>
> h3. Mechanism
> {{OmMetadataManagerImpl.getExpiredOpenKeys}} reads hsync state from RocksDB 
> only, and {{OMOpenKeysDeleteRequest.updateOpenKeyTableCache}} rechecks only 
> existence and {{updateID}}. A first hsync that lands between the cleanup scan 
> and the {{DeleteOpenKeys}} request therefore loses its open entry while the 
> {{fileTable}} entry keeps {{HSYNC_CLIENT_ID}}.
> {{OMOpenKeysDeleteResponse}} also moves every block of the deleted open key 
> to the deleted table, including the blocks the hsync'ed key table entry 
> references.
> The commit requests ({{OMKeyCommitRequestWithFSO.java:206}}, 
> {{OMKeyCommitRequest.java:284}}) then dereference the missing open entry 
> ({{openKeyToDelete.toBuilder()}}) without a null check when another client 
> commits over that key. {{OMOpenKeysDeleteRequest}} is shared by all bucket 
> layouts, so this is not limited to FSO.
> h3. Trigger
> # c1 creates a file and keeps it open past 
> {{ozone.om.open.key.expire.threshold}} without hsync.
> # c2 opens the same path (overwrite of an hsync'ed file is allowed).
> # The cleanup scan selects c1's open key.
> # c1's first hsync is applied before {{DeleteOpenKeys}}.
> # c2 commits.
> h3. Impact
> c1's hsync is acknowledged but its open entry is deleted and the blocks of 
> the hsync'ed data are queued for deletion, with no second writer needed 
> (verified up to the deleted table entry; the physical block deletion was not 
> run). c2's commit then throws {{NullPointerException}} in apply and 
> {{OzoneManagerStateMachine.runCommand}} terminates the OM. The entry is 
> already in the Raft log, so the other OMs and a restart would hit it again 
> (argued from the deterministic apply path, not run).
> h3. Reproduction
> PASS, 3 of 3 runs. [^TestBugMC7ExpiredOpenKeyHsyncRace.java] 
> ({{hadoop-ozone/ozone-manager}}) uses only client calls against one real OM 
> with its real {{OpenKeyCleanupService}}, with the service interval and expiry 
> threshold shortened by configuration. With defaults the window is 
> milliseconds, once per service run, on a file open for seven days.
> h3. Suggested fix
> * Close the race in {{OMOpenKeysDeleteRequest.updateOpenKeyTableCache}}: 
> never delete an open key that a committed key still points to through 
> {{HSYNC_CLIENT_ID}}.
> * Null check {{openKeyToDelete}} in both commit requests. This removes the 
> termination and lets a cluster already in this state recover.
> HDDS-16732 reports the same cleanup site enqueueing a live key's blocks on a 
> versioned bucket; different trigger, same missing key table check.
> h3. Patch
> [^MC-7-keep-open-key-hsynced-after-cleanup-selection.patch], against 
> 20e6a1c0f6039248373efd3eb1d7f2afcf7f1535. It also applies to master at 
> 9c6bee807c8.
> Two changes:
> * {{OMOpenKeysDeleteRequest}}: under the bucket lock, an open key whose own 
> client ID is in its {{HSYNC_CLIENT_ID}} is looked up in the key table and 
> skipped when the committed key still carries that client ID. A deleted key 
> has no entry and an overwritten key carries another writer's ID or none, so 
> both are still deleted. The extra read only happens for open keys that are 
> hsync'ed, which the scan normally never submits.
> * {{OMKeyCommitRequest}} and {{OMKeyCommitRequestWithFSO}}: the 
> {{OVERWRITTEN_HSYNC_KEY}} marking is skipped when the open entry is missing, 
> so an OM that already holds such a key no longer terminates on the next 
> overwrite commit.
> Covered by {{testDeleteHsyncedKeys}} in the existing 
> {{TestOMOpenKeysDeleteRequest}} (both layouts) and 
> {{testOverwriteHsyncKeyWithoutOpenKey}} in {{TestOMKeyCommitRequest}} 
> (inherited by the FSO variant). Without the change the first fails because 
> the hsync'ed open key is gone, and the second with the 
> {{NullPointerException}} on {{openKeyToDelete}}. The open key delete, key 
> commit and cleanup service unit suites (82 tests) and {{TestHSync}} (42 
> tests) pass, checkstyle is clean. The cross OM and restart behaviour is 
> argued from the apply path, not run.
> Found by TLA+ model checking and code review of the OM FSO namespace mutation 
> paths under HDDS-15926, on commit 20e6a1c0f6039248373efd3eb1d7f2afcf7f1535. 
> 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
(v8.20.10#820010)

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

Reply via email to