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]

Reply via email to