Siyao Meng created HDDS-16852:
---------------------------------

             Summary: Reserve the OM owned hsync key metadata names at the 
request boundary and tolerate an invalid stored hsync client id in its readers
                 Key: HDDS-16852
                 URL: https://issues.apache.org/jira/browse/HDDS-16852
             Project: Apache Ozone
          Issue Type: Bug
            Reporter: Siyao Meng
         Attachments: 
CR-7-reserve-hsync-metadata-names-and-tolerate-invalid-values.patch

h3. Mechanism
The OM records the hsync writer of a key in a key metadata entry 
({{OzoneConsts.HSYNC_CLIENT_ID}}), alongside the other OM owned names 
{{OzoneConsts.LEASE_RECOVERY}}, {{OzoneConsts.DELETED_HSYNC_KEY}} and 
{{OzoneConsts.OVERWRITTEN_HSYNC_KEY}}. These names are set by the OM itself. 
One request type already strips them from the key metadata it receives; other 
request types do not reserve them.

The readers of the stored writer id then parse it with {{Long.parseLong}} and 
assume the derived open key exists. 
{{OMKeyCommitRequest.validateAndUpdateCache}} and 
{{OMKeyCommitRequestWithFSO.prepareCommit}} parse it on the recovery path, and 
on the overwrite path both of them parse the id of the key being overwritten, 
build the open key name from it and read that open key entry to add 
{{OVERWRITTEN_HSYNC_KEY}} to it. {{OMRecoverLeaseRequest.doWork}} parses it to 
build the open file name it recovers.

A stored value that is not a valid long, or a valid long with no matching open 
key row, makes these paths fail with an unchecked exception instead of an 
{{OMException}}, and nothing in them checks the value before using it.

h3. Trigger
# A key table row carries an {{HSYNC_CLIENT_ID}} metadata entry whose value is 
stale (the previous writer's own id, kept on the key after that writer 
committed, so the open key row is gone) or is not parseable as a long.
# A commit of the same key arrives on the overwrite path, or a recovery commit 
or a lease recovery runs against that key.

Both bucket layouts are affected: the overwrite path exists in 
{{OMKeyCommitRequest}} and in {{OMKeyCommitRequestWithFSO}}, and both recovery 
commit paths parse the same stored value.

h3. Impact
* A commit that overwrites a key whose stored writer id is stale or does not 
parse, and a recovery commit or lease recovery of such a key, fail with an 
unchecked exception instead of an {{OMException}} with a request status. With 
the patch the overwrite completes as a plain overwrite and the recovery paths 
return {{KEY_NOT_FOUND}}.
* No key and no data is lost by the defect itself, and the stored value stays 
on the key until a later commit replaces it.

h3. Reproduction
There is no standalone reproduction. The regression tests in the attached patch 
set the state internally and fail against the unmodified main sources:
* {{TestOMKeyCommitRequest.testOverwriteKeyWithStaleHsyncClientId}} (also in 
the inherited {{...WithFSO}}): a stored writer id that is stale and one that is 
not parseable, overwritten by a plain commit from another client. The commit 
must succeed and the new key must not carry the id.
* {{TestOMKeyCommitRequest.testRecoveryCommitWithInvalidHsyncClientId}}: a 
recovery commit against a key whose stored id is not parseable must return 
{{KEY_NOT_FOUND}}, and the stored value must stay on the key.
* {{TestOMRecoverLeaseRequest.testRecoverFileWithInvalidHsyncClientId}}: a 
lease recovery of a file whose stored id is not parseable must return 
{{KEY_NOT_FOUND}} and must not mark the open file with {{LEASE_RECOVERY}}.
* {{TestOMKeyCommitRequest.testPreExecuteStripsReservedMetadata}} and 
{{TestS3InitiateMultipartUploadRequest.testPreExecuteStripsReservedMetadata}}: 
the four reserved names must be removed in {{preExecute}} while a custom name 
is retained, and the hsync commit must still record the writer's own client id 
on the key.

h3. Patch
[^CR-7-reserve-hsync-metadata-names-and-tolerate-invalid-values.patch], against 
a6b7bdb937109ba2893688b41a89470bc95c88cf. It also applies to master at 
b0aa6475b78, where none of the touched files differ.

{{OMKeyRequest}} gains two protected helpers: {{stripReservedMetadata}}, which 
filters the four OM owned names out of a {{KeyArgs}} metadata list and returns 
the same object when nothing was removed, and {{parseHsyncClientId}}, which 
returns null for an absent or unparseable value instead of throwing. 
{{OMKeyCommitRequest.preExecute}} and 
{{S3InitiateMultipartUploadRequest.preExecute}} run the incoming {{KeyArgs}} 
through the strip, so the names are reserved at the request boundary for these 
two request types as well.

Every reader of the stored writer id goes through the tolerant parse. The two 
recovery commit paths, {{OMKeyCommitRequest.validateAndUpdateCache}} and 
{{OMKeyCommitRequestWithFSO.prepareCommit}}, and 
{{OMRecoverLeaseRequest.doWork}} fail the request with an {{OMException}} 
carrying {{KEY_NOT_FOUND}} when the value does not parse. The two overwrite 
paths look up the open key only when the id parses, and when either the parse 
or the lookup yields nothing they log a warning with the existing "Potentially 
inconsistent DB state" wording, clear the open key name they were going to mark 
and commit as a plain overwrite. In 
{{OMKeyCommitRequestWithFSO.applyKeyCommit}} the deferred cache write for the 
overwritten open key is now guarded by the prepared open key info being present.

There is no version gate. The strip runs in {{preExecute}} before replication, 
and the tolerant readers replace an unchecked failure with an error response or 
a plain overwrite, so a follower applying an already replicated request sees no 
behaviour change for a well formed stored value.

With the patch the following suites pass: {{TestOMKeyCommitRequest}} (25), 
{{TestOMKeyCommitRequestWithFSO}} (25), {{TestOMRecoverLeaseRequest}} (12), 
{{TestS3InitiateMultipartUploadRequest}} (10) and {{...WithFSO}} (10), 
{{TestS3MultipartUploadCompleteRequest}} (9) and {{...WithFSO}} (9), 
{{TestS3MultipartUploadCommitPartRequest}} (19) and {{...WithFSO}} (19), 
{{TestOMKeyCreateRequest}} (83), {{TestOMKeyCreateRequestWithFSO}} (87, one 
existing skip), {{TestOpenKeyCleanupService}} (14). Checkstyle is clean.

Affected versions: present at the pinned commit. Earlier releases were not 
checked.

Found during 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. The attached patch is a proposal for review. Generated with 
Specula (Claude Opus 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