This is an automated email from the ASF dual-hosted git repository.
smengcl pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/master by this push:
new 7f68eb6f36d HDDS-16125. Copy bucket snapshot in quota repair response
to fix cache aliasing (#11004)
7f68eb6f36d is described below
commit 7f68eb6f36d02c421352bdc28298ee05ba5e1706
Author: Jason O'Sullivan <[email protected]>
AuthorDate: Wed Aug 12 22:13:48 2026 +0100
HDDS-16125. Copy bucket snapshot in quota repair response to fix cache
aliasing (#11004)
---
.../om/request/volume/OMQuotaRepairRequest.java | 9 +-
.../request/volume/TestOMQuotaRepairRequest.java | 95 ++++++++++++++++++++++
2 files changed, 103 insertions(+), 1 deletion(-)
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/OMQuotaRepairRequest.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/OMQuotaRepairRequest.java
index a82382e9c11..60902753dd5 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/OMQuotaRepairRequest.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/OMQuotaRepairRequest.java
@@ -143,7 +143,14 @@ private void updateBucketInfo(
omMetadataManager.getBucketTable().addCacheEntry(
new CacheKey<>(bucketKey), CacheValue.get(transactionLogIndex,
bucketInfo));
- bucketMap.put(Pair.of(bucketCountInfo.getVolName(),
bucketCountInfo.getBucketName()), bucketInfo);
+
+ // Store an immutable snapshot in the response map so the double buffer
+ // serializes the repair result, not a value later mutated in place by a
+ // concurrent key commit that reads the same live cached OmBucketInfo.
+ // Every other mutating request copies its response bucket for the same
+ // reason (see OMKeyCommitRequest#validateAndUpdateCache).
+ bucketMap.put(Pair.of(bucketCountInfo.getVolName(),
bucketCountInfo.getBucketName()),
+ bucketInfo.copyObject());
} finally {
if (acquiredBucketLock) {
mergeOmLockDetails(omMetadataManager.getLock()
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/volume/TestOMQuotaRepairRequest.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/volume/TestOMQuotaRepairRequest.java
new file mode 100644
index 00000000000..b01143a30d1
--- /dev/null
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/volume/TestOMQuotaRepairRequest.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.ozone.om.request.volume;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.UUID;
+import org.apache.hadoop.hdds.utils.db.BatchOperation;
+import org.apache.hadoop.hdds.utils.db.cache.CacheKey;
+import org.apache.hadoop.hdds.utils.db.cache.CacheValue;
+import org.apache.hadoop.ozone.om.helpers.BucketLayout;
+import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
+import org.apache.hadoop.ozone.om.request.OMRequestTestUtils;
+import org.apache.hadoop.ozone.om.request.key.OMKeyRequest;
+import org.apache.hadoop.ozone.om.response.OMClientResponse;
+import org.apache.hadoop.ozone.om.response.volume.OMQuotaRepairResponse;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.BucketQuotaCount;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.QuotaRepairRequest;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Status;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests quota repair request.
+ */
+public class TestOMQuotaRepairRequest extends OMVolumeRequestTests {
+
+ @Test
+ public void testRepairDurableWriteNotAffectedByLaterBucketCacheMutation()
throws Exception {
+ String volumeName = UUID.randomUUID().toString();
+ String bucketName = "bucket1";
+ OMRequestTestUtils.addVolumeAndBucketToDB(volumeName, bucketName,
+ omMetadataManager, BucketLayout.OBJECT_STORE);
+
+ String bucketKey = omMetadataManager.getBucketKey(volumeName, bucketName);
+ OmBucketInfo driftedBucket =
omMetadataManager.getBucketTable().get(bucketKey)
+ .toBuilder()
+ .setUsedBytes(1)
+ .build();
+ omMetadataManager.getBucketTable().put(bucketKey, driftedBucket);
+ omMetadataManager.getBucketTable().addCacheEntry(
+ new CacheKey<>(bucketKey), CacheValue.get(1L, driftedBucket));
+
+ OMRequest omRequest = OMRequest.newBuilder()
+ .setClientId("test-client")
+ .setCmdType(Type.QuotaRepair)
+ .setQuotaRepairRequest(QuotaRepairRequest.newBuilder()
+ .addBucketCount(BucketQuotaCount.newBuilder()
+ .setVolName(volumeName)
+ .setBucketName(bucketName)
+ .setDiffUsedBytes(-1)
+ .setDiffUsedNamespace(0)
+ .setSupportOldQuota(false)
+ .build())
+ .setSupportVolumeOldQuota(false)
+ .build())
+ .build();
+
+ OMQuotaRepairRequest omQuotaRepairRequest = new
OMQuotaRepairRequest(omRequest);
+ OMClientResponse omClientResponse =
+ omQuotaRepairRequest.validateAndUpdateCache(ozoneManager, 2L);
+
assertThat(omClientResponse.getOMResponse().getStatus()).isEqualTo(Status.OK);
+
+ OmBucketInfo cachedBucket =
+ OMKeyRequest.getBucketInfo(omMetadataManager, volumeName, bucketName);
+ assertThat(cachedBucket).isNotNull();
+ assertThat(cachedBucket.getUsedBytes()).isEqualTo(0);
+
+ cachedBucket.incrUsedBytes(1);
+ assertThat(cachedBucket.getUsedBytes()).isEqualTo(1);
+
+ BatchOperation batchOperation =
omMetadataManager.getStore().initBatchOperation();
+ ((OMQuotaRepairResponse) omClientResponse).addToDBBatch(omMetadataManager,
batchOperation);
+ omMetadataManager.getStore().commitBatchOperation(batchOperation);
+
+ OmBucketInfo durableBucket =
omMetadataManager.getBucketTable().getSkipCache(bucketKey);
+ assertThat(durableBucket.getUsedBytes()).isEqualTo(0);
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]