Copilot commented on code in PR #11216:
URL: https://github.com/apache/ozone/pull/11216#discussion_r3951322534


##########
hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCreateRequest.java:
##########
@@ -247,7 +247,7 @@ public OMClientResponse validateAndUpdateCache(OzoneManager 
ozoneManager, Execut
       keyArgs = validateAndRewriteIfMatchAsExpectedGeneration(keyArgs, 
dbKeyInfo);
 
       OmBucketInfo bucketInfo =
-          getBucketInfo(omMetadataManager, volumeName, bucketName);
+          getBucketInfoForUpdate(omMetadataManager, volumeName, bucketName);

Review Comment:
   When key-path locking is used (no missing parents), this path appears to 
only read bucket info and never publishes it (because `numMissingParents` stays 
0). In that case, `getBucketInfoForUpdate()` still creates an unnecessary copy. 
If feasible, fetch read-only bucket info first and only switch to 
`getBucketInfoForUpdate()` (copy + later publish) in the branch where missing 
parents are actually created and charged.



##########
hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMDirectoriesPurgeRequestWithFSO.java:
##########
@@ -269,6 +278,18 @@ public OMClientResponse 
validateAndUpdateCache(OzoneManager ozoneManager, Execut
         getBucketLayout(), volBucketInfoMap, fromSnapshotInfo, openKeyInfoMap);
   }
 
+  /**
+   * Return the copy this request accumulates deltas on, fetching it on first 
use. All three purge
+   * paths can touch the same bucket, so they must share one copy or earlier 
deltas are lost.
+   */
+  private OmBucketInfo accumulatedBucketInfo(Map<Pair<String, String>, 
OmBucketInfo> volBucketInfoMap,
+      OMMetadataManager omMetadataManager, String volumeName, String 
bucketName) {
+    OmBucketInfo omBucketInfo = volBucketInfoMap.get(Pair.of(volumeName, 
bucketName));
+
+    return omBucketInfo != null ? omBucketInfo
+        : getBucketInfoForUpdate(omMetadataManager, volumeName, bucketName);

Review Comment:
   This helper never inserts the newly fetched copy back into 
`volBucketInfoMap`. As a result, subsequent calls for the same bucket will get 
a fresh copy and earlier deltas can be lost; additionally, the publish loop 
over `volBucketInfoMap.entrySet()` may publish nothing. Use `computeIfAbsent` 
(or explicitly `put`) so the first fetched copy is retained and reused for all 
purge paths.



##########
hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCreateRequest.java:
##########
@@ -333,6 +333,11 @@ public OMClientResponse 
validateAndUpdateCache(OzoneManager ozoneManager, Execut
         OMFileRequest.addKeyTableCacheEntries(omMetadataManager, volumeName,
             bucketName, bucketInfo.getBucketLayout(),
             null, missingParentInfos, trxnLogIndex);
+
+        // Parent directory creation holds the bucket write lock; key path 
locking leaves
+        // numMissingParents at 0.
+        omMetadataManager.getBucketTable().addCacheEntry(
+            omMetadataManager.getBucketKey(volumeName, bucketName), 
bucketInfo, trxnLogIndex);

Review Comment:
   When key-path locking is used (no missing parents), this path appears to 
only read bucket info and never publishes it (because `numMissingParents` stays 
0). In that case, `getBucketInfoForUpdate()` still creates an unnecessary copy. 
If feasible, fetch read-only bucket info first and only switch to 
`getBucketInfoForUpdate()` (copy + later publish) in the branch where missing 
parents are actually created and charged.



##########
hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/multipart/S3ExpiredMultipartUploadsAbortRequest.java:
##########
@@ -106,18 +108,44 @@ public OMClientResponse 
validateAndUpdateCache(OzoneManager ozoneManager, Execut
     Result result = null;
     Map<OmBucketInfo, List<OmMultipartAbortInfo>>
         abortedMultipartUploads = new HashMap<>();
+    // One accumulated copy per bucket, so a bucket listed more than once 
keeps a single entry.
+    Map<Pair<String, String>, OmBucketInfo> bucketInfoMap = new HashMap<>();
+
+    OMMetadataManager omMetadataManager = ozoneManager.getMetadataManager();
+    List<String[]> bucketLockKeys = submittedExpiredMPUsPerBucket.stream()
+        .map(mpuByBucket -> Pair.of(mpuByBucket.getVolumeName(), 
mpuByBucket.getBucketName()))
+        .distinct()
+        .map(volBucketPair -> new String[]{volBucketPair.getLeft(), 
volBucketPair.getRight()})
+        .collect(Collectors.toList());
+    boolean acquiredLocks = false;

Review Comment:
   The lock acquisition order is currently derived from request order. If 
`acquireWriteLocks` does not internally enforce a deterministic ordering, 
acquiring multiple bucket locks in varying orders can deadlock with concurrent 
operations acquiring overlapping sets. Consider sorting `bucketLockKeys` (eg, 
by volume then bucket) before acquiring to guarantee a consistent lock order.



##########
hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/key/TestOMKeyPurgeRequestAndResponse.java:
##########
@@ -137,6 +141,67 @@ private OMRequest preExecute(OMRequest originalOmRequest) 
throws IOException {
     return modifiedOmRequest;
   }
 
+  @Test
+  public void testPurgedSizesReachCacheAndDb() throws Exception {
+    Pair<List<String>, List<String>> deleteKeysAndRenamedEntry =
+        createAndDeleteKeysAndRenamedEntry(1, null);
+
+    String bucketKey = omMetadataManager.getBucketKey(volumeName, bucketName);
+    OmBucketInfo bucketInfo = omMetadataManager.getBucketTable()
+        .getCacheValue(new CacheKey<>(bucketKey)).getCacheValue();
+    bucketInfo.incrSnapshotUsedBytes(500L);
+    bucketInfo.incrSnapshotUsedNamespace(5L);

Review Comment:
   This test mutates the cached `OmBucketInfo` instance in-place to set up 
state. Since this PR’s intent is to prevent in-place cache mutations, this 
setup is a bit at odds with the new contract and may become brittle if bucket 
table caching behavior changes. Prefer setting the initial bucket state via a 
cache publication (`addCacheEntry`) or DB write so the test doesn’t rely on 
mutating a shared cached instance.



##########
hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/multipart/S3ExpiredMultipartUploadsAbortRequest.java:
##########
@@ -106,18 +108,44 @@ public OMClientResponse 
validateAndUpdateCache(OzoneManager ozoneManager, Execut
     Result result = null;
     Map<OmBucketInfo, List<OmMultipartAbortInfo>>
         abortedMultipartUploads = new HashMap<>();
+    // One accumulated copy per bucket, so a bucket listed more than once 
keeps a single entry.
+    Map<Pair<String, String>, OmBucketInfo> bucketInfoMap = new HashMap<>();
+
+    OMMetadataManager omMetadataManager = ozoneManager.getMetadataManager();
+    List<String[]> bucketLockKeys = submittedExpiredMPUsPerBucket.stream()
+        .map(mpuByBucket -> Pair.of(mpuByBucket.getVolumeName(), 
mpuByBucket.getBucketName()))
+        .distinct()
+        .map(volBucketPair -> new String[]{volBucketPair.getLeft(), 
volBucketPair.getRight()})
+        .collect(Collectors.toList());
+    boolean acquiredLocks = false;
 
     try {
+      // Hold every bucket lock for the whole request, so the accumulated 
copies can be published
+      // once all buckets have been processed. A later bucket failing turns 
the whole request into
+      // an error response, which persists nothing.
+      
mergeOmLockDetails(omMetadataManager.getLock().acquireWriteLocks(BUCKET_LOCK, 
bucketLockKeys));

Review Comment:
   The lock acquisition order is currently derived from request order. If 
`acquireWriteLocks` does not internally enforce a deterministic ordering, 
acquiring multiple bucket locks in varying orders can deadlock with concurrent 
operations acquiring overlapping sets. Consider sorting `bucketLockKeys` (eg, 
by volume then bucket) before acquiring to guarantee a consistent lock order.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to