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 4ab81d2a2e2 HDDS-16126. Fence quota repair deltas by bucket objectID
(#11309)
4ab81d2a2e2 is described below
commit 4ab81d2a2e2746a4fe87b423b4478f10dd53eea8
Author: Priyesh Karatha <[email protected]>
AuthorDate: Fri Sep 25 03:29:54 2026 +0530
HDDS-16126. Fence quota repair deltas by bucket objectID (#11309)
---
.../src/main/proto/OmClientProtocol.proto | 4 ++
.../om/request/volume/OMQuotaRepairRequest.java | 11 +++++
.../hadoop/ozone/om/service/QuotaRepairTask.java | 4 ++
.../request/volume/TestOMQuotaRepairRequest.java | 55 ++++++++++++++++++++++
4 files changed, 74 insertions(+)
diff --git
a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
index 75aedd475ea..9af165bbcd0 100644
--- a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
+++ b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
@@ -2482,6 +2482,10 @@ message BucketQuotaCount {
required bool supportOldQuota = 5 [default=false];
optional int64 diffSnapshotUsedBytes = 6;
optional int64 diffSnapshotUsedNamespace = 7;
+ // objectID of the bucket the delta was computed against, so the apply can
+ // reject a stale delta if the bucket was deleted and recreated under the
+ // same name during the repair window. Optional for backward compatibility.
+ optional uint64 bucketObjectID = 8;
}
message QuotaRepairResponse {
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 60902753dd5..3094de9eb34 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
@@ -122,6 +122,17 @@ private void updateBucketInfo(
// bucket might be deleted when running repair count parallel
return;
}
+ if (bucketCountInfo.hasBucketObjectID()
+ && bucketCountInfo.getBucketObjectID() != bucketInfo.getObjectID()) {
+ // The bucket was deleted and recreated under the same name after the
+ // repair scan captured its counts. Applying the stale delta would
+ // corrupt the counters of the unrelated recreated bucket, so drop it.
+ LOG.warn("Skipping quota repair delta for bucket {}/{}: scanned
objectID {} does not match "
+ + "current objectID {} (bucket recreated during repair)",
+ bucketCountInfo.getVolName(), bucketCountInfo.getBucketName(),
+ bucketCountInfo.getBucketObjectID(), bucketInfo.getObjectID());
+ return;
+ }
bucketInfo.incrUsedBytes(bucketCountInfo.getDiffUsedBytes());
bucketInfo.incrUsedNamespace(bucketCountInfo.getDiffUsedNamespace());
if (bucketCountInfo.hasDiffSnapshotUsedBytes()) {
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/QuotaRepairTask.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/QuotaRepairTask.java
index 443b997340a..45e41e4dc34 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/QuotaRepairTask.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/QuotaRepairTask.java
@@ -190,6 +190,10 @@ private void repairActiveDb(
= OzoneManagerProtocolProtos.BucketQuotaCount.newBuilder();
bucketCountBuilder.setVolName(updatedBuckedInfo.getVolumeName());
bucketCountBuilder.setBucketName(updatedBuckedInfo.getBucketName());
+ // Carry the scanned bucket identity so the apply can drop this delta if
+ // the bucket is deleted and recreated under the same name before the
+ // repair transaction commits.
+ bucketCountBuilder.setBucketObjectID(updatedBuckedInfo.getObjectID());
bucketCountBuilder.setDiffUsedBytes(updatedBuckedInfo.getUsedBytes() -
oriBucketInfo.getUsedBytes());
bucketCountBuilder.setDiffUsedNamespace(
updatedBuckedInfo.getUsedNamespace() -
oriBucketInfo.getUsedNamespace());
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
index b01143a30d1..49b3213b30c 100644
---
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
@@ -34,6 +34,7 @@
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.apache.hadoop.util.Time;
import org.junit.jupiter.api.Test;
/**
@@ -92,4 +93,58 @@ public void
testRepairDurableWriteNotAffectedByLaterBucketCacheMutation() throws
OmBucketInfo durableBucket =
omMetadataManager.getBucketTable().getSkipCache(bucketKey);
assertThat(durableBucket.getUsedBytes()).isEqualTo(0);
}
+
+ @Test
+ public void testStaleDeltaSkippedWhenBucketRecreatedUnderSameName() 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 originalBucket =
omMetadataManager.getBucketTable().get(bucketKey);
+ long staleObjectID = originalBucket.getObjectID();
+
+ // Simulate the bucket being deleted and recreated under the same name
after the
+ // repair scan captured staleObjectID, but before the repair transaction
commits.
+ OmBucketInfo recreatedBucket = OmBucketInfo.newBuilder()
+ .setVolumeName(volumeName)
+ .setBucketName(bucketName)
+ .setBucketLayout(originalBucket.getBucketLayout())
+ .setCreationTime(Time.now())
+ .setObjectID(staleObjectID + 1)
+ .setUsedBytes(0)
+ .setUsedNamespace(0)
+ .build();
+ omMetadataManager.getBucketTable().put(bucketKey, recreatedBucket);
+ omMetadataManager.getBucketTable().addCacheEntry(
+ new CacheKey<>(bucketKey), CacheValue.get(1L, recreatedBucket));
+
+ OMRequest omRequest = OMRequest.newBuilder()
+ .setClientId("test-client")
+ .setCmdType(Type.QuotaRepair)
+ .setQuotaRepairRequest(QuotaRepairRequest.newBuilder()
+ .addBucketCount(BucketQuotaCount.newBuilder()
+ .setVolName(volumeName)
+ .setBucketName(bucketName)
+ .setBucketObjectID(staleObjectID)
+ .setDiffUsedBytes(-1000)
+ .setDiffUsedNamespace(-1)
+ .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.getObjectID()).isEqualTo(staleObjectID + 1);
+ assertThat(cachedBucket.getUsedBytes()).isEqualTo(0);
+ assertThat(cachedBucket.getUsedNamespace()).isEqualTo(0);
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]