Skip to content

Commit 039724d

Browse files
committed
fix: simplify removeObjects retry by retrying full set on transient failure
Replace byName index, retryNames set, and toDelete rebuild loop with a single anyTransient boolean flag. Retry the full object list on transient errors rather than narrowing to failing names — already-deleted objects are silently ignored by S3 and MinioAsyncClient filters NoSuchVersion.
1 parent d6ed5e8 commit 039724d

1 file changed

Lines changed: 11 additions & 26 deletions

File tree

functional/TestMinioClient.java

Lines changed: 11 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,17 +1041,12 @@ public List<ObjectWriteResponse> createObjects(String bucketName, int count, int
10411041
}
10421042

10431043
public void removeObjects(String bucketName, List<ObjectWriteResponse> results) throws Exception {
1044-
// DeleteResult.Error has no versionId; keyed by name to rebuild versioned retry batches.
1045-
Map<String, List<ObjectWriteResponse>> byName = new HashMap<>();
1046-
for (ObjectWriteResponse res : results) {
1047-
byName.computeIfAbsent(res.object(), k -> new ArrayList<>()).add(res);
1048-
}
1049-
List<DeleteRequest.Object> toDelete =
1044+
List<DeleteRequest.Object> objects =
10501045
results.stream()
10511046
.map(r -> new DeleteRequest.Object(r.object(), r.versionId()))
10521047
.collect(Collectors.toList());
1053-
Set<String> failedNames = Collections.emptySet();
1054-
for (int attempt = 0; attempt < MAX_DELETE_ATTEMPTS && !toDelete.isEmpty(); attempt++) {
1048+
boolean anyTransient = false;
1049+
for (int attempt = 0; attempt < MAX_DELETE_ATTEMPTS; attempt++) {
10551050
if (attempt > 0) {
10561051
try {
10571052
Thread.sleep(500L << attempt); // 1s / 2s / 4s / 8s
@@ -1060,11 +1055,11 @@ public void removeObjects(String bucketName, List<ObjectWriteResponse> results)
10601055
throw ie;
10611056
}
10621057
}
1063-
Set<String> retryNames = new HashSet<>();
1058+
anyTransient = false;
10641059
IOException nonTransientErr = null;
1065-
for (int i = 0; i < toDelete.size(); i += DELETE_BATCH_SIZE) {
1060+
for (int i = 0; i < objects.size(); i += DELETE_BATCH_SIZE) {
10661061
List<DeleteRequest.Object> chunk =
1067-
toDelete.subList(i, Math.min(i + DELETE_BATCH_SIZE, toDelete.size()));
1062+
objects.subList(i, Math.min(i + DELETE_BATCH_SIZE, objects.size()));
10681063
for (Result<DeleteResult.Error> r :
10691064
client.removeObjects(
10701065
RemoveObjectsArgs.builder().bucket(bucketName).objects(chunk).build())) {
@@ -1085,29 +1080,19 @@ public void removeObjects(String bucketName, List<ObjectWriteResponse> results)
10851080
}
10861081
continue; // drain current chunk's response before throwing
10871082
}
1088-
retryNames.add(err.objectName());
1083+
anyTransient = true;
10891084
}
10901085
if (nonTransientErr != null) throw nonTransientErr;
10911086
}
1092-
// All versions re-queued because DeleteResult.Error lacks versionId;
1093-
// already-deleted versions return NoSuchVersion, filtered upstream by MinioAsyncClient.
1094-
failedNames = retryNames;
1095-
toDelete = new ArrayList<>();
1096-
for (String name : retryNames) {
1097-
for (ObjectWriteResponse res : byName.getOrDefault(name, Collections.emptyList())) {
1098-
toDelete.add(new DeleteRequest.Object(res.object(), res.versionId()));
1099-
}
1100-
}
1087+
if (!anyTransient) break;
11011088
}
1102-
if (!toDelete.isEmpty()) {
1089+
if (anyTransient) {
11031090
throw new IOException(
1104-
toDelete.size()
1091+
results.size()
11051092
+ " object(s) not deleted after "
11061093
+ MAX_DELETE_ATTEMPTS
11071094
+ " attempts in bucket "
1108-
+ bucketName
1109-
+ "; sample: "
1110-
+ failedNames.stream().limit(5).collect(Collectors.toList()));
1095+
+ bucketName);
11111096
}
11121097
}
11131098

0 commit comments

Comments
 (0)