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

Siyao Meng updated HDDS-16763:
------------------------------
    Attachment: TestBugMC2FailedMpuOrphanDir.java

> A failed FSO CompleteMultipartUpload leaves missing parent directories in the 
> cache, so later acknowledged creates become orphans
> ---------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: HDDS-16763
>                 URL: https://issues.apache.org/jira/browse/HDDS-16763
>             Project: Apache Ozone
>          Issue Type: Bug
>            Reporter: Siyao Meng
>            Priority: Critical
>         Attachments: 
> MC-2-withdraw-cache-entries-of-failed-fso-multipart-complete.patch, 
> TestBugMC2FailedMpuOrphanDir.java
>
>
> h3. Mechanism
> {{S3MultipartUploadCompleteRequest.validateAndUpdateCache}} adds the missing 
> FSO parent directories 
> ({{S3MultipartUploadCompleteRequestWithFSO.addMissingParentsToCache}}) and a 
> synthesized open file entry to the table cache before checks that can still 
> fail ({{NOT_A_FILE}}, {{NO_SUCH_MULTIPART_UPLOAD_ERROR}}, the part list 
> checks, {{QUOTA_EXCEEDED}} for the key). The error response writes nothing to 
> RocksDB, and nothing removes those cache entries until the epoch is evicted 
> after flush.
> {{OzoneManagerStateMachine.applyTransaction}} does not wait for the double 
> buffer flush, so a later request can be applied while the failed request's 
> directories are still visible in the cache.
> h3. Trigger
> On an FSO bucket, a {{CompleteMultipartUpload}} that fails (for example an 
> unknown upload ID) for a key whose parent directories do not exist, followed 
> by a mkdir or key create and commit under those parents, applied before the 
> failed request's epoch is flushed and evicted.
> h3. Impact
> The later request is acknowledged OK and persists a directory or file row 
> whose parent directory never reaches RocksDB. After eviction the acknowledged 
> directory or key is unreachable ({{FILE_NOT_FOUND}} / {{KEY_NOT_FOUND}}), 
> stays unreachable after OM restart, and its row and namespace charge remain 
> as an orphan. The outcome also depends on each OM's flush timing: an OM that 
> applies the later create after its own eviction creates the parents itself, 
> so {{directoryTable}} and {{usedNamespace}} can differ between OMs (argued, 
> not run).
> h3. Reproduction
> PASS. [^TestBugMC2FailedMpuOrphanDir.java] 
> ({{hadoop-ozone/integration-test}}), uninstrumented jars, single OM mini 
> cluster. With two racing client threads and no hooks, 4 of 300 acknowledged 
> mkdirs were lost. Holding the flush with 
> {{OzoneManagerDoubleBuffer.pause/unpause}} makes it deterministic. The cross 
> OM consequence is argued, not run.
> h3. Suggested fix
> Withdraw the directory and open file cache entries when the complete fails, 
> under the bucket lock, or restructure the method so that it publishes them 
> only on success. A plain move of {{addMissingParentsToCache}} and 
> {{addMultiPartToCache}} below the validation does not work, because the 
> method resolves the key through those cache entries in between (the complete 
> after parent deletion case of HDDS-11784 would start failing). HDDS-16117 
> fixed the bucket quota side of this site only.
> h3. Patch
> [^MC-2-withdraw-cache-entries-of-failed-fso-multipart-complete.patch], 
> against 20e6a1c0f6039248373efd3eb1d7f2afcf7f1535. It also applies to master 
> at 9c6bee807c8.
> {{addMissingParentsToCache}} returns the directory table keys it added, and 
> the existing {{catch}} block calls a new hook, 
> {{removeMissingEntriesFromCache}}, which the FSO request implements by 
> replacing those entries and the synthesized open key entry with entries 
> without a value at the same transaction index, while the bucket lock is still 
> held. The keys were verified absent under that lock before they were added, 
> so this restores the state before the request, and a later request creates 
> the parents itself on every OM. The success path is untouched. Publishing 
> only on success would be the cleaner rule but needs the key resolution on the 
> success path reworked; that is a reviewer's call.
> Covered by {{testFailedCompleteDoesNotLeaveMissingParentsInCache}} in the 
> existing {{TestS3MultipartUploadCompleteRequestWithFSO}} and 
> {{testDirectoryCreatedAfterFailedCompleteIsPersistedWithItsParent}} in the 
> existing {{TestOzoneClientMultipartUploadWithFSO}} (double buffer pause and 
> unpause on the shared cluster). Both fail without the change. The multipart 
> request and response unit suites (127 tests) and all of 
> {{TestOzoneClientMultipartUploadWithFSO}} (33 tests, including the HDDS-16117 
> and HDDS-11784 cases) pass, checkstyle is clean.
> 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