This is an automated email from the ASF dual-hosted git repository.
aryangupta1998 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 524660937a5 HDDS-12865. Handle automatic container cache refresh for
replica verification. (#11044)
524660937a5 is described below
commit 524660937a57b173e29c20220eb18e4abc578912
Author: Aryan Gupta <[email protected]>
AuthorDate: Wed Aug 26 11:34:08 2026 +0530
HDDS-12865. Handle automatic container cache refresh for replica
verification. (#11044)
---
.../debug/replicas/BlockExistenceVerifier.java | 6 +
.../debug/replicas/BlockVerificationResult.java | 15 ++
.../ozone/debug/replicas/ChecksumVerifier.java | 18 ++
.../ozone/debug/replicas/ReplicasVerify.java | 117 +++++++++--
.../ozone/debug/replicas/TestReplicasVerify.java | 227 ++++++++++++++++++++-
5 files changed, 366 insertions(+), 17 deletions(-)
diff --git
a/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/replicas/BlockExistenceVerifier.java
b/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/replicas/BlockExistenceVerifier.java
index dde79989d02..5cae3453321 100644
---
a/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/replicas/BlockExistenceVerifier.java
+++
b/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/replicas/BlockExistenceVerifier.java
@@ -24,6 +24,7 @@
import org.apache.hadoop.hdds.scm.XceiverClientManager;
import org.apache.hadoop.hdds.scm.XceiverClientSpi;
import org.apache.hadoop.hdds.scm.cli.ContainerOperationClient;
+import
org.apache.hadoop.hdds.scm.container.common.helpers.StorageContainerException;
import org.apache.hadoop.hdds.scm.pipeline.Pipeline;
import org.apache.hadoop.hdds.scm.storage.ContainerProtocolCalls;
import org.apache.hadoop.ozone.om.helpers.OmKeyLocationInfo;
@@ -67,6 +68,11 @@ public BlockVerificationResult verifyBlock(DatanodeDetails
datanode, OmKeyLocati
} else {
return BlockVerificationResult.failCheck("Block does not exist on this
replica");
}
+ } catch (StorageContainerException e) {
+ if (e.getResult() == ContainerProtos.Result.NO_SUCH_BLOCK) {
+ return
BlockVerificationResult.failCheckAndRefreshKeyLocation(e.getMessage());
+ }
+ return BlockVerificationResult.failIncomplete(e.getMessage());
} catch (IOException e) {
return BlockVerificationResult.failIncomplete(e.getMessage());
} finally {
diff --git
a/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/replicas/BlockVerificationResult.java
b/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/replicas/BlockVerificationResult.java
index c73635ba475..e94e45e2497 100644
---
a/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/replicas/BlockVerificationResult.java
+++
b/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/replicas/BlockVerificationResult.java
@@ -28,11 +28,18 @@ public class BlockVerificationResult {
private final boolean completed;
private final boolean pass;
private final List<String> failures;
+ private final boolean refreshKeyLocation;
public BlockVerificationResult(boolean completed, boolean pass, List<String>
failures) {
+ this(completed, pass, failures, false);
+ }
+
+ public BlockVerificationResult(boolean completed, boolean pass, List<String>
failures,
+ boolean refreshKeyLocation) {
this.completed = completed;
this.pass = pass;
this.failures = failures;
+ this.refreshKeyLocation = refreshKeyLocation;
}
public static BlockVerificationResult pass() {
@@ -43,6 +50,10 @@ public static BlockVerificationResult failCheck(String
message) {
return new BlockVerificationResult(true, false,
Collections.singletonList(message));
}
+ public static BlockVerificationResult failCheckAndRefreshKeyLocation(String
message) {
+ return new BlockVerificationResult(true, false,
Collections.singletonList(message), true);
+ }
+
public static BlockVerificationResult failIncomplete(String message) {
return new BlockVerificationResult(false, false,
Collections.singletonList(message));
}
@@ -59,4 +70,8 @@ public List<String> getFailures() {
return failures;
}
+ public boolean shouldRefreshKeyLocation() {
+ return refreshKeyLocation;
+ }
+
}
diff --git
a/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/replicas/ChecksumVerifier.java
b/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/replicas/ChecksumVerifier.java
index 96f8218526d..2acc514481a 100644
---
a/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/replicas/ChecksumVerifier.java
+++
b/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/replicas/ChecksumVerifier.java
@@ -23,9 +23,11 @@
import org.apache.commons.io.output.NullOutputStream;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
+import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos;
import org.apache.hadoop.hdds.scm.OzoneClientConfig;
import org.apache.hadoop.hdds.scm.XceiverClientManager;
import org.apache.hadoop.hdds.scm.cli.ContainerOperationClient;
+import
org.apache.hadoop.hdds.scm.container.common.helpers.StorageContainerException;
import org.apache.hadoop.hdds.scm.pipeline.Pipeline;
import org.apache.hadoop.ozone.client.io.BlockInputStreamFactoryImpl;
import org.apache.hadoop.ozone.common.OzoneChecksumException;
@@ -68,6 +70,11 @@ public BlockVerificationResult verifyBlock(DatanodeDetails
datanode, OmKeyLocati
return BlockVerificationResult.pass();
} catch (IOException e) {
Throwable cause = e.getCause() != null ? e.getCause() : e;
+ StorageContainerException storageContainerException =
findStorageContainerException(e);
+ if (storageContainerException != null
+ && storageContainerException.getResult() ==
ContainerProtos.Result.NO_SUCH_BLOCK) {
+ return
BlockVerificationResult.failCheckAndRefreshKeyLocation(storageContainerException.getMessage());
+ }
if (cause instanceof OzoneChecksumException) {
return BlockVerificationResult.failCheck(cause.getMessage());
} else {
@@ -75,4 +82,15 @@ public BlockVerificationResult verifyBlock(DatanodeDetails
datanode, OmKeyLocati
}
}
}
+
+ private static StorageContainerException
findStorageContainerException(Throwable throwable) {
+ Throwable current = throwable;
+ while (current != null) {
+ if (current instanceof StorageContainerException) {
+ return (StorageContainerException) current;
+ }
+ current = current.getCause();
+ }
+ return null;
+ }
}
diff --git
a/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/replicas/ReplicasVerify.java
b/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/replicas/ReplicasVerify.java
index e886f945c34..784e3fdc918 100644
---
a/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/replicas/ReplicasVerify.java
+++
b/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/replicas/ReplicasVerify.java
@@ -338,14 +338,69 @@ void checkBucket(OzoneClient ozoneClient, OzoneBucket
bucket, ArrayNode keysArra
void processKey(OzoneClient ozoneClient, String volumeName, String
bucketName, String keyName,
ArrayNode keysArray, AtomicBoolean allKeysPassed) throws IOException {
keysProcessed.incrementAndGet();
- OmKeyInfo keyInfo = ozoneClient.getProxy().getKeyInfo(
- volumeName, bucketName, keyName, refreshContainerLocationsFromScm);
+ OmKeyInfo keyInfo;
+ try {
+ keyInfo = ozoneClient.getProxy().getKeyInfo(
+ volumeName, bucketName, keyName, refreshContainerLocationsFromScm);
+ } catch (IOException e) {
+ LOG.warn("Unable to fetch key info from OM for key {}/{}/{}; marking
verification incomplete.",
+ volumeName, bucketName, keyName, e);
+ markKeyFetchFailure(volumeName, bucketName, keyName, e.getMessage(),
keysArray, allKeysPassed);
+ return;
+ }
// Check if key should be processed based on replication config
if (!shouldProcessKeyByReplicationType(keyInfo)) {
return;
}
+ KeyVerificationResult keyVerificationResult = verifyKey(keyInfo,
volumeName, bucketName, keyName);
+ if (keyVerificationResult.shouldRefreshKeyLocation()) {
+ try {
+ OmKeyInfo refreshedKeyInfo = ozoneClient.getProxy().getKeyInfo(
+ volumeName, bucketName, keyName, true);
+ keyVerificationResult = verifyKey(refreshedKeyInfo, volumeName,
bucketName, keyName);
+ } catch (IOException e) {
+ LOG.warn("Unable to refresh key location from OM for key {}/{}/{};
marking verification incomplete.",
+ volumeName, bucketName, keyName, e);
+ keyVerificationResult.markRefreshFailure(e.getMessage());
+ }
+ }
+
+ keyVerificationResult.getKeyNode().put("pass",
keyVerificationResult.passed());
+ if (keyVerificationResult.passed()) {
+ keysPassed.incrementAndGet();
+ } else {
+ keysFailed.incrementAndGet();
+ allKeysPassed.set(false);
+ keyVerificationResult.getFailedVerificationTypes().forEach(failedType ->
failuresByType
+ .computeIfAbsent(failedType, k -> new AtomicInteger(0))
+ .incrementAndGet()
+ );
+ }
+
+ if (!keyVerificationResult.passed() || allResults) {
+ keysArray.add(keyVerificationResult.getKeyNode());
+ }
+ }
+
+ private void markKeyFetchFailure(String volumeName, String bucketName,
String keyName, String message,
+ ArrayNode keysArray, AtomicBoolean allKeysPassed) {
+ ObjectNode keyNode = JsonUtils.createObjectNode(null);
+ keyNode.put("volumeName", volumeName);
+ keyNode.put("bucketName", bucketName);
+ keyNode.put("name", keyName);
+ keyNode.putArray("blocks");
+ keyNode.put("completed", false);
+ keyNode.put("pass", false);
+ keyNode.putArray("failures").addObject().put("message", "Failed to fetch
key info from OM: " + message);
+ keysFailed.incrementAndGet();
+ allKeysPassed.set(false);
+ keysArray.add(keyNode);
+ }
+
+ private KeyVerificationResult verifyKey(
+ OmKeyInfo keyInfo, String volumeName, String bucketName, String keyName)
{
ObjectNode keyNode = JsonUtils.createObjectNode(null);
keyNode.put("volumeName", volumeName);
keyNode.put("bucketName", bucketName);
@@ -353,7 +408,9 @@ void processKey(OzoneClient ozoneClient, String volumeName,
String bucketName, S
ArrayNode blocksArray = keyNode.putArray("blocks");
boolean keyPass = true;
+ boolean shouldRefreshKeyLocation = false;
Set<String> failedVerificationTypes = new HashSet<>();
+ List<ObjectNode> refreshChecks = new ArrayList<>();
for (OmKeyLocationInfo keyLocation :
keyInfo.getLatestVersionLocations().getBlocksLatestVersionOnly()) {
long containerID = keyLocation.getContainerID();
@@ -383,6 +440,10 @@ void processKey(OzoneClient ozoneClient, String
volumeName, String bucketName, S
checkNode.put("type", verifier.getType());
checkNode.put("completed", result.isCompleted());
checkNode.put("pass", result.passed());
+ if (result.shouldRefreshKeyLocation()) {
+ shouldRefreshKeyLocation = true;
+ refreshChecks.add(checkNode);
+ }
ArrayNode failuresArray = checkNode.putArray("failures");
for (String failure : result.getFailures()) {
@@ -406,20 +467,48 @@ void processKey(OzoneClient ozoneClient, String
volumeName, String bucketName, S
}
}
- keyNode.put("pass", keyPass);
- if (keyPass) {
- keysPassed.incrementAndGet();
- } else {
- keysFailed.incrementAndGet();
- allKeysPassed.set(false);
- failedVerificationTypes.forEach(failedType -> failuresByType
- .computeIfAbsent(failedType, k -> new AtomicInteger(0))
- .incrementAndGet()
- );
+ return new KeyVerificationResult(
+ keyNode, keyPass, failedVerificationTypes, shouldRefreshKeyLocation,
refreshChecks);
+ }
+
+ private static final class KeyVerificationResult {
+ private final ObjectNode keyNode;
+ private final boolean pass;
+ private final Set<String> failedVerificationTypes;
+ private final boolean refreshKeyLocation;
+ private final List<ObjectNode> refreshChecks;
+
+ private KeyVerificationResult(ObjectNode keyNode, boolean pass,
Set<String> failedVerificationTypes,
+ boolean refreshKeyLocation, List<ObjectNode> refreshChecks) {
+ this.keyNode = keyNode;
+ this.pass = pass;
+ this.failedVerificationTypes = failedVerificationTypes;
+ this.refreshKeyLocation = refreshKeyLocation;
+ this.refreshChecks = refreshChecks;
+ }
+
+ private ObjectNode getKeyNode() {
+ return keyNode;
+ }
+
+ private boolean passed() {
+ return pass;
}
- if (!keyPass || allResults) {
- keysArray.add(keyNode);
+ private Set<String> getFailedVerificationTypes() {
+ return failedVerificationTypes;
+ }
+
+ private boolean shouldRefreshKeyLocation() {
+ return refreshKeyLocation;
+ }
+
+ private void markRefreshFailure(String message) {
+ String refreshFailure = "Failed to refresh key location from OM: " +
message;
+ for (ObjectNode checkNode : refreshChecks) {
+ checkNode.put("completed", false);
+ checkNode.withArray("failures").addObject().put("message",
refreshFailure);
+ }
}
}
diff --git
a/hadoop-ozone/cli-debug/src/test/java/org/apache/hadoop/ozone/debug/replicas/TestReplicasVerify.java
b/hadoop-ozone/cli-debug/src/test/java/org/apache/hadoop/ozone/debug/replicas/TestReplicasVerify.java
index b42a0cf87b9..a70d7bc7baf 100644
---
a/hadoop-ozone/cli-debug/src/test/java/org/apache/hadoop/ozone/debug/replicas/TestReplicasVerify.java
+++
b/hadoop-ozone/cli-debug/src/test/java/org/apache/hadoop/ozone/debug/replicas/TestReplicasVerify.java
@@ -18,15 +18,45 @@
package org.apache.hadoop.ozone.debug.replicas;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import java.io.IOException;
import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicBoolean;
+import org.apache.hadoop.hdds.client.BlockID;
+import org.apache.hadoop.hdds.client.StandaloneReplicationConfig;
+import org.apache.hadoop.hdds.protocol.DatanodeDetails;
+import org.apache.hadoop.hdds.protocol.MockDatanodeDetails;
+import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
+import org.apache.hadoop.hdds.scm.pipeline.Pipeline;
+import org.apache.hadoop.hdds.scm.pipeline.PipelineID;
+import org.apache.hadoop.hdds.server.JsonUtils;
+import org.apache.hadoop.ozone.client.OzoneClient;
+import org.apache.hadoop.ozone.client.protocol.ClientProtocol;
+import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
+import org.apache.hadoop.ozone.om.helpers.OmKeyLocationInfo;
+import org.apache.hadoop.ozone.om.helpers.OmKeyLocationInfoGroup;
+import org.apache.hadoop.ozone.shell.ShellReplicationOptions;
import org.junit.jupiter.api.Test;
import picocli.CommandLine;
/**
- * Unit tests for replicas verify command option parsing.
+ * Unit tests for replicas verify command.
*/
-public class TestReplicasVerify {
+class TestReplicasVerify {
@Test
void testRefreshContainerLocationsFromScmOption() throws Exception {
@@ -46,9 +76,200 @@ void testRefreshContainerLocationsFromScmDefault() throws
Exception {
assertThat(isRefreshContainerLocationsFromScmEnabled(command)).isFalse();
}
- private boolean isRefreshContainerLocationsFromScmEnabled(ReplicasVerify
command) throws Exception {
+ @Test
+ void testRetriesWithForcedContainerCacheRefreshOnBlockNotFound() throws
Exception {
+ ReplicasVerify replicasVerify = new ReplicasVerify();
+ ReplicaVerifier blockExistenceVerifier = mock(ReplicaVerifier.class);
+ ReplicaVerifier checksumVerifier = mock(ReplicaVerifier.class);
+
+ when(blockExistenceVerifier.getType()).thenReturn("blockExistence");
+ when(checksumVerifier.getType()).thenReturn("checksum");
+ when(blockExistenceVerifier.verifyBlock(any(), any()))
+
.thenReturn(BlockVerificationResult.failCheckAndRefreshKeyLocation("Block not
found"))
+ .thenReturn(BlockVerificationResult.pass());
+ when(checksumVerifier.verifyBlock(any(), any()))
+ .thenReturn(BlockVerificationResult.pass())
+ .thenReturn(BlockVerificationResult.pass());
+ setField(replicasVerify, "replicaVerifiers",
Arrays.asList(blockExistenceVerifier, checksumVerifier));
+ setField(replicasVerify, "replication", emptyReplicationFilter());
+
+ OzoneClient ozoneClient = mock(OzoneClient.class);
+ ClientProtocol proxy = mock(ClientProtocol.class);
+ when(ozoneClient.getProxy()).thenReturn(proxy);
+
+ OmKeyLocationInfo firstLocation = createKeyLocationInfo(1L, 11L);
+ OmKeyLocationInfo refreshedLocation = createKeyLocationInfo(2L, 22L);
+ when(proxy.getKeyInfo("vol1", "bucket1", "key1", false))
+ .thenReturn(createKeyInfo(firstLocation));
+ when(proxy.getKeyInfo("vol1", "bucket1", "key1", true))
+ .thenReturn(createKeyInfo(refreshedLocation));
+
+ ObjectNode root = JsonUtils.createObjectNode(null);
+ ArrayNode keysArray = root.putArray("keys");
+ AtomicBoolean allKeysPassed = new AtomicBoolean(true);
+
+ replicasVerify.processKey(ozoneClient, "vol1", "bucket1", "key1",
keysArray, allKeysPassed);
+
+ verify(proxy).getKeyInfo("vol1", "bucket1", "key1", false);
+ verify(proxy).getKeyInfo("vol1", "bucket1", "key1", true);
+ verify(blockExistenceVerifier, times(2)).verifyBlock(any(), any());
+ verify(checksumVerifier, times(2)).verifyBlock(any(), any());
+ assertTrue(allKeysPassed.get());
+ assertEquals(0, keysArray.size());
+ }
+
+ @Test
+ void testDoesNotRefreshOnNonRefreshableFailure() throws Exception {
+ ReplicasVerify replicasVerify = new ReplicasVerify();
+ ReplicaVerifier blockExistenceVerifier = mock(ReplicaVerifier.class);
+ ReplicaVerifier checksumVerifier = mock(ReplicaVerifier.class);
+
+ when(blockExistenceVerifier.getType()).thenReturn("blockExistence");
+ when(checksumVerifier.getType()).thenReturn("checksum");
+ when(blockExistenceVerifier.verifyBlock(any(), any()))
+ .thenReturn(BlockVerificationResult.failCheck("Block does not exist on
this replica"));
+ when(checksumVerifier.verifyBlock(any(), any()))
+ .thenReturn(BlockVerificationResult.pass());
+ setField(replicasVerify, "replicaVerifiers",
Arrays.asList(blockExistenceVerifier, checksumVerifier));
+ setField(replicasVerify, "replication", emptyReplicationFilter());
+
+ OzoneClient ozoneClient = mock(OzoneClient.class);
+ ClientProtocol proxy = mock(ClientProtocol.class);
+ when(ozoneClient.getProxy()).thenReturn(proxy);
+ when(proxy.getKeyInfo("vol1", "bucket1", "key1", false))
+ .thenReturn(createKeyInfo(createKeyLocationInfo(1L, 11L)));
+
+ ObjectNode root = JsonUtils.createObjectNode(null);
+ ArrayNode keysArray = root.putArray("keys");
+ AtomicBoolean allKeysPassed = new AtomicBoolean(true);
+
+ replicasVerify.processKey(ozoneClient, "vol1", "bucket1", "key1",
keysArray, allKeysPassed);
+
+ verify(proxy).getKeyInfo("vol1", "bucket1", "key1", false);
+ verify(proxy, never()).getKeyInfo("vol1", "bucket1", "key1", true);
+ verify(blockExistenceVerifier, times(1)).verifyBlock(any(), any());
+ verify(checksumVerifier, times(1)).verifyBlock(any(), any());
+ assertFalse(allKeysPassed.get());
+ assertEquals(1, keysArray.size());
+ assertFalse(keysArray.get(0).get("pass").asBoolean());
+ }
+
+ @Test
+ void testRefreshFailureMarksKeyIncompleteAndDoesNotAbortRun() throws
Exception {
+ ReplicasVerify replicasVerify = new ReplicasVerify();
+ ReplicaVerifier blockExistenceVerifier = mock(ReplicaVerifier.class);
+
+ when(blockExistenceVerifier.getType()).thenReturn("blockExistence");
+ when(blockExistenceVerifier.verifyBlock(any(), any()))
+
.thenReturn(BlockVerificationResult.failCheckAndRefreshKeyLocation("Block not
found"));
+ setField(replicasVerify, "replicaVerifiers",
Collections.singletonList(blockExistenceVerifier));
+ setField(replicasVerify, "replication", emptyReplicationFilter());
+
+ OzoneClient ozoneClient = mock(OzoneClient.class);
+ ClientProtocol proxy = mock(ClientProtocol.class);
+ when(ozoneClient.getProxy()).thenReturn(proxy);
+ when(proxy.getKeyInfo("vol1", "bucket1", "key1", false))
+ .thenReturn(createKeyInfo(createKeyLocationInfo(1L, 11L)));
+ when(proxy.getKeyInfo("vol1", "bucket1", "key1", true))
+ .thenThrow(new IOException("OM refresh failed"));
+
+ ObjectNode root = JsonUtils.createObjectNode(null);
+ ArrayNode keysArray = root.putArray("keys");
+ AtomicBoolean allKeysPassed = new AtomicBoolean(true);
+
+ replicasVerify.processKey(ozoneClient, "vol1", "bucket1", "key1",
keysArray, allKeysPassed);
+
+ verify(proxy).getKeyInfo("vol1", "bucket1", "key1", false);
+ verify(proxy).getKeyInfo("vol1", "bucket1", "key1", true);
+ assertFalse(allKeysPassed.get());
+ assertEquals(1, keysArray.size());
+ assertFalse(keysArray.get(0).get("pass").asBoolean());
+ assertFalse(keysArray.get(0).get("blocks").get(0)
+
.get("replicas").get(0).get("checks").get(0).get("completed").asBoolean());
+ assertThat(keysArray.get(0).get("blocks").get(0)
+
.get("replicas").get(0).get("checks").get(0).get("failures").toString())
+ .contains("Failed to refresh key location from OM: OM refresh failed");
+ }
+
+ @Test
+ void testInitialGetKeyInfoFailureMarksKeyIncompleteAndDoesNotAbortRun()
throws Exception {
+ ReplicasVerify replicasVerify = new ReplicasVerify();
+ OzoneClient ozoneClient = mock(OzoneClient.class);
+ ClientProtocol proxy = mock(ClientProtocol.class);
+ when(ozoneClient.getProxy()).thenReturn(proxy);
+ when(proxy.getKeyInfo("vol1", "bucket1", "key1", false))
+ .thenThrow(new IOException("Key not found"));
+
+ ObjectNode root = JsonUtils.createObjectNode(null);
+ ArrayNode keysArray = root.putArray("keys");
+ AtomicBoolean allKeysPassed = new AtomicBoolean(true);
+
+ replicasVerify.processKey(ozoneClient, "vol1", "bucket1", "key1",
keysArray, allKeysPassed);
+
+ verify(proxy).getKeyInfo("vol1", "bucket1", "key1", false);
+ verify(proxy, never()).getKeyInfo("vol1", "bucket1", "key1", true);
+ assertFalse(allKeysPassed.get());
+ assertEquals(1, keysArray.size());
+ assertFalse(keysArray.get(0).get("completed").asBoolean());
+ assertFalse(keysArray.get(0).get("pass").asBoolean());
+ assertThat(keysArray.get(0).get("failures").toString())
+ .contains("Failed to fetch key info from OM: Key not found");
+ }
+
+ private static boolean
isRefreshContainerLocationsFromScmEnabled(ReplicasVerify command) throws
Exception {
Field field =
ReplicasVerify.class.getDeclaredField("refreshContainerLocationsFromScm");
field.setAccessible(true);
return field.getBoolean(command);
}
+
+ private static OmKeyInfo createKeyInfo(OmKeyLocationInfo keyLocationInfo) {
+ OmKeyLocationInfoGroup latestVersionLocations =
+ new OmKeyLocationInfoGroup(0,
Collections.singletonList(keyLocationInfo));
+ return new OmKeyInfo.Builder()
+ .setVolumeName("vol1")
+ .setBucketName("bucket1")
+ .setKeyName("key1")
+
.setReplicationConfig(StandaloneReplicationConfig.getInstance(HddsProtos.ReplicationFactor.ONE))
+
.setOmKeyLocationInfos(Collections.singletonList(latestVersionLocations))
+ .build();
+ }
+
+ private static OmKeyLocationInfo createKeyLocationInfo(long containerId,
long localId) {
+ DatanodeDetails datanode = MockDatanodeDetails.randomDatanodeDetails();
+ Pipeline pipeline = Pipeline.newBuilder()
+ .setId(PipelineID.randomId())
+
.setReplicationConfig(StandaloneReplicationConfig.getInstance(HddsProtos.ReplicationFactor.ONE))
+ .setState(Pipeline.PipelineState.OPEN)
+ .setNodes(Collections.singletonList(datanode))
+ .build();
+
+ return new OmKeyLocationInfo.Builder()
+ .setBlockID(new BlockID(containerId, localId))
+ .setPipeline(pipeline)
+ .setLength(1)
+ .setOffset(0)
+ .setCreateVersion(0)
+ .build();
+ }
+
+ private static ShellReplicationOptions emptyReplicationFilter() {
+ ShellReplicationOptions replication = mock(ShellReplicationOptions.class);
+ when(replication.fromParams(any())).thenReturn(Optional.empty());
+ return replication;
+ }
+
+ private static void setField(Object target, String fieldName, Object value)
throws Exception {
+ Class<?> type = target.getClass();
+ while (type != null) {
+ try {
+ Field field = type.getDeclaredField(fieldName);
+ field.setAccessible(true);
+ field.set(target, value);
+ return;
+ } catch (NoSuchFieldException ignored) {
+ type = type.getSuperclass();
+ }
+ }
+ throw new IOException("Unable to set field '" + fieldName + "' on " +
target.getClass().getName());
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]