Skip to content

HDDS-16117. Failed FSO multipart complete leaks bucket namespace quota - #10984

Draft
smengcl wants to merge 2 commits into
apache:masterfrom
smengcl:HDDS-16117
Draft

HDDS-16117. Failed FSO multipart complete leaks bucket namespace quota#10984
smengcl wants to merge 2 commits into
apache:masterfrom
smengcl:HDDS-16117

Conversation

@smengcl

@smengcl smengcl commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Generated-by: Claude Code (Opus 4.8)

What changes were proposed in this pull request?

A multipart upload complete on an FSO bucket can leak the bucket usedNamespace value in the cache.

The cause is as follows:

  1. validateAndUpdateCache gets the bucket with getBucketInfo. getBucketInfo returns the cached OmBucketInfo by reference.
  2. For FSO, addMissingParentsToCache makes a missing parent directory again. It calls incrUsedNamespace(...) before it validates the parts. This call changes the cached bucket in place.
  3. The complete then fails. For example, it fails with INVALID_PART.
  4. The failure path makes an error response. It does not call the success only updateCache. Thus the OM does not correct the change.
  5. The cache cleanup removes the new parent directory, but the usedNamespace change stays.

The result: the cached bucket shows one namespace object that does not exist. The durable bucket stays correct. A client can send this failed complete many times. This can fill the namespace quota of the bucket with no real objects. An OM restart, a failover, or a quota repair clears the cache.

HDDS-11784 corrected the abort path. It did not correct the failed complete path.

Fix: use a copy of the cached OmBucketInfo in validateAndUpdateCache, and publish it with updateCache only when the complete is successful. If the complete fails, the OM does not use the copy, and the cache stays correct. This is the same copyObject() method as the abort path. A note on getBucketInfo tells callers to copy the bucket before they change it.

(TLA+ formal verification with Specula found this bug. Trace validation on a real trace broke the QuotaExactness invariant. An independent model check broke the FailedOperationIsolation invariant. Both point to the failed complete path.)

What is the link to the Apache JIRA

https://issues.apache.org/jira/browse/HDDS-16117

How was this patch tested?

  • New test TestOzoneClientMultipartUploadWithFSO#testFailedCompleteAfterParentDeletionDoesNotLeakNamespaceQuota: start an FSO MPU below a parent directory, upload a part, delete the parent, then complete with a wrong ETag and get INVALID_PART. The cached and durable bucket usedNamespace must both be 0. The test fails on master (cached value is 1) and passes with this patch.

Work on a copy of the cached OmBucketInfo in
S3MultipartUploadCompleteRequest.validateAndUpdateCache so that the
namespace charge for recreated missing parent directories is published
to the cache and DB only on the success path. On the failure path
(for example INVALID_PART) the copy is discarded, so a failed complete
no longer leaves the in-place usedNamespace increment orphaned in the
cached bucket. This mirrors the copyObject() usage on the abort path.

Add an integration test in TestOzoneClientMultipartUploadWithFSO that
fails before the fix (cached usedNamespace is 1) and passes after.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 10, 2026 15:28
@smengcl smengcl added the bug Something isn't working label Aug 10, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a bucket namespace quota leak in Ozone Manager’s FSO multipart-upload complete path where a failed complete could mutate the cached OmBucketInfo.usedNamespace in-place (eg, on INVALID_PART) without publishing a corresponding corrective cache update.

Changes:

  • In S3MultipartUploadCompleteRequest#validateAndUpdateCache, work with a copyObject() of the cached OmBucketInfo so quota mutations are only published via updateCache on success.
  • Document OMKeyRequest#getBucketInfo behavior as returning the live cached bucket instance by reference, and warn callers to copy before mutating in failure-prone paths.
  • Add an integration test reproducing the “delete parent dir then failed complete” scenario and asserting cached and durable usedNamespace remain consistent.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/multipart/S3MultipartUploadCompleteRequest.java Copies cached bucket info before any quota-affecting cache work so failed completes don’t leak namespace usage into the bucket cache.
hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyRequest.java Clarifies that getBucketInfo returns the cached OmBucketInfo instance by reference and callers must copy before mutating prior to a possible failure.
hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestOzoneClientMultipartUploadWithFSO.java Adds regression coverage ensuring a failed FSO MPU complete after parent deletion does not corrupt cached bucket namespace quota.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@smengcl smengcl added the AI-gen label Aug 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI-gen bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants