[
https://issues.apache.org/jira/browse/HDDS-16850?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Siyao Meng updated HDDS-16850:
------------------------------
Attachment: TestBugMC5RenameRecreateAutoCommit.java
> After an OBS or LEGACY rename and recreate of an hsync'ed key, the hard lease
> auto commit empties the new key and deletes blocks still in use
> ---------------------------------------------------------------------------------------------------------------------------------------------
>
> Key: HDDS-16850
> URL: https://issues.apache.org/jira/browse/HDDS-16850
> Project: Apache Ozone
> Issue Type: Bug
> Reporter: Siyao Meng
> Priority: Critical
> Attachments:
> MC-5-reject-close-of-hsync-key-replaced-without-marker.patch,
> TestBugMC5RenameRecreateAutoCommit.java
>
>
> h3. Mechanism
> {{OmMetadataManagerImpl.getExpiredOpenKeys}} treats an open key as hsync'ed
> when its own {{HSYNC_CLIENT_ID}} matches its client id, then builds the auto
> commit from the committed key entry with the same name, without checking that
> this entry is the one that client hsync'ed.
> {{OMKeyCommitRequest.validateAndUpdateCache}} does not check it either: it
> rejects the commit only when the open key carries {{DELETED_HSYNC_KEY}} or
> {{OVERWRITTEN_HSYNC_KEY}}.
> {{OMKeyRenameRequest}} (OBJECT_STORE and LEGACY) has no open file check,
> unlike {{OMKeyRenameRequestWithFSO}} (HDDS-8545), and does not touch the
> writer's open key. A key later created at the old name finds no existing
> entry at commit time, so it sets no marker either. The auto commit then
> commits the abandoned open key with the new key's length and block list:
> {{OmKeyInfo.updateLocationInfoList}} drops the new key's block as unknown,
> the abandoned writer's own block is queued as uncommitted, and the new key is
> queued as an old version.
> The defect also applies to FILE_SYSTEM_OPTIMIZED buckets. There a rename of
> an open hsync'ed file is rejected, but the open key can still be left
> unmarked while another key takes the name, and the auto commit then pairs
> them the same way.
> h3. Trigger
> {{ozone.fs.hsync.enabled}} and {{ozone.hbase.enhancements.allowed}} are true
> (both default false), OBJECT_STORE or LEGACY bucket.
> # Writer 1 writes {{k1}} and hsyncs, then stops writing without closing.
> # {{k1}} is renamed to {{k2}}.
> # Writer 2 creates a new {{k1}} and closes it.
> # Writer 1's open key reaches {{ozone.om.lease.hard.limit}} (default 7d) and
> the next cleanup run auto commits it.
> h3. Impact
> * Writer 2's committed {{k1}} is replaced by an entry built from writer 1's
> open key, with writer 2's length and no blocks, and writer 2's block is
> queued in {{deletedTable}}.
> * The renamed {{k2}} still references writer 1's block, which is queued in
> {{deletedTable}} too, so {{KeyDeletingService}} sends it to SCM for deletion
> while {{k2}} points at it.
> * No client gets an error. Nothing restores the blocks.
> h3. Reproduction
> PASS, deterministic, unmodified source, for OBJECT_STORE and LEGACY buckets.
> [^TestBugMC5RenameRecreateAutoCommit.java] ({{hadoop-ozone/ozone-manager}})
> runs one real OM through {{OzoneManagerProtocol}} with a 200 ms hard lease
> limit, uses only public write requests ({{openKey}}, {{allocateBlock}},
> {{hsyncKey}}, {{renameKey}}, {{commitKey}}) and then calls the real
> {{OpenKeyCleanupTask}} of a second, never started {{OpenKeyCleanupService}}
> once. Output on the OBS bucket: before the cleanup "k1 length 500 blocks
> [13046326171], k2 length 1000 blocks [13046326021], deleted blocks []", after
> it "k1 length 500 blocks [], k2 length 1000 blocks [13046326021], deleted
> blocks [13046326171, 13046326021]". A passing test means the defect is
> present. Physical deletion on datanodes was not run.
> h3. Patch
> [^MC-5-reject-close-of-hsync-key-replaced-without-marker.patch], against
> a6b7bdb937109ba2893688b41a89470bc95c88cf. It also applies to master at
> b0aa6475b78.
> A commit that is not a recovery commit is rejected with {{KEY_NOT_FOUND}}
> when the open key carries the committing client's own {{HSYNC_CLIENT_ID}} and
> the committed entry at its name is not the key that client hsync'ed (or there
> is none). This holds for hsync commits as well as for the close, as for the
> existing {{DELETED_HSYNC_KEY}} and {{OVERWRITTEN_HSYNC_KEY}} markers, and
> uses the same result code. The first hsync of an open key is not affected,
> because the open key gets {{HSYNC_CLIENT_ID}} only in that commit. The check
> compares the client's own id, as {{getExpiredOpenKeys}} does, so an open key
> that carries another client's {{HSYNC_CLIENT_ID}} copied with the metadata of
> an open hsync'ed key (S3 {{CopyObject}}, {{ozone sh key cp}}) still commits.
> The auto commit can then no longer commit another key's data, and nothing is
> queued for deletion. A writer whose hsync'ed key was renamed away now gets
> {{KEY_NOT_FOUND}} on its next hsync or close, as it already does after a
> delete or an overwrite, so it can no longer put its blocks back at the old
> name while the renamed key still references them. An open key that was never
> hsync'ed can still overwrite the name. {{OMKeyCommitRequestWithFSO}} gets the
> same check. No request field is added.
> The check changes what the apply writes, so it is enabled by a new
> {{OzoneManagerVersion.HSYNC_COMMIT_VALIDATION}} (101) through
> {{OMVersionManager.isAllowed}}. Until the cluster is finalized to that
> version every OM applies the commit as before, so OMs on different software
> versions never apply the same log entry differently, and the defect remains
> until finalization. HDDS-16848 adds the same {{HSYNC_COMMIT_VALIDATION}}
> constant for a related commit check, so whichever lands second drops its
> copy; the number itself is a placeholder to be agreed at merge.
> Side effects: the abandoned open key is never cleaned. Every cleanup run
> selects it again, uses one slot of
> {{ozone.om.open.key.cleanup.limit.per.task}} for it and logs the rejected
> commit as an ERROR with a stack trace. No admin command clears it:
> {{recoverLease}} on the old name returns {{KEY_ALREADY_CLOSED}} or
> {{KEY_NOT_FOUND}}. Deleting it instead would send the renamed key's blocks
> for deletion, so cleaning it is left to a follow up, either a scan side skip
> or a removal that does not queue its blocks. Rejecting the rename of an
> hsync'ed key in OBJECT_STORE and LEGACY buckets removes this trigger for new
> renames and is proposed separately in HDDS-16849, which also covers a rename
> without a recreate (the scan then fails with a {{NullPointerException}}
> before this check is reached); this check also covers keys renamed before
> such a change. The scan hunk in the patch attached to HDDS-16768 would send
> such a leftover open key row (no key table entry) to {{DeleteOpenKeys}},
> which on OBJECT_STORE and LEGACY buckets queues the renamed key's blocks for
> deletion; limiting that hunk to FSO buckets, or skipping the row instead of
> deleting it, avoids that.
> Covered by {{testCommitWhenHsyncedKeyIsReplacedWithoutMarker}} in the
> existing {{TestOMKeyCommitRequest}}, inherited by
> {{TestOMKeyCommitRequestWithFSO}}. With the version finalized it checks that
> the close and a later hsync of the hsync'ed client are rejected and that a
> client whose open key carries a copied {{HSYNC_CLIENT_ID}} can still
> overwrite the name; before finalization it checks that the close is applied
> as before. Without the change the finalized case fails for both layouts with
> "expected: <KEY_NOT_FOUND> but was: <OK>". With it the commit request, commit
> response, recover lease, key rename, key delete, metadata manager, open key
> cleanup, OM storage, OM version and related request and response suites pass
> (248 tests), {{TestHSync}} passes on a mini cluster (42 tests, with both
> patches), and checkstyle is clean. With the patch the reproduction fails
> because {{k1}} keeps its block and nothing is queued for deletion.
> Found by TLA+ model checking and code review of the OM open key cleanup and
> hsync lease recovery paths under HDDS-15926, on commit
> a6b7bdb937109ba2893688b41a89470bc95c88cf. Checked against HDDS issues and
> apache/ozone pull requests for duplicates before filing; related but
> different are HDDS-10631 (block any open key rename) and HDDS-10770
> (overwrite of an hsync'ed key, which added {{OVERWRITTEN_HSYNC_KEY}};
> HDDS-10736 was closed as its duplicate). 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]