diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/LegacyReplicationManager.java b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/LegacyReplicationManager.java index debbc0d03274..27eba21af015 100644 --- a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/LegacyReplicationManager.java +++ b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/LegacyReplicationManager.java @@ -428,6 +428,7 @@ protected void processContainer(ContainerInfo container, * we have to resend close container command to the datanodes. */ if (state == LifeCycleState.CLOSING) { + setHealthStateForClosing(replicas, container, report); for (ContainerReplica replica: replicas) { if (replica.getState() != State.UNHEALTHY) { sendCloseCommand( @@ -1613,6 +1614,18 @@ private boolean isOpenContainerHealthy( .allMatch(r -> compareState(state, r.getState())); } + private void setHealthStateForClosing(Set replicas, + ContainerInfo container, + ReplicationManagerReport report) { + if (replicas.size() == 0) { + report.incrementAndSample(HealthState.MISSING, container.containerID()); + report.incrementAndSample(HealthState.UNDER_REPLICATED, + container.containerID()); + report.incrementAndSample(HealthState.MIS_REPLICATED, + container.containerID()); + } + } + public boolean isContainerReplicatingOrDeleting(ContainerID containerID) { return inflightReplication.containsKey(containerID) || inflightDeletion.containsKey(containerID); diff --git a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/TestLegacyReplicationManager.java b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/TestLegacyReplicationManager.java index 8c46db43ac3d..27a33b53ea45 100644 --- a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/TestLegacyReplicationManager.java +++ b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/TestLegacyReplicationManager.java @@ -397,6 +397,62 @@ public void testClosingContainer() throws IOException, TimeoutException { Assertions.assertEquals(1, report.getStat(LifeCycleState.CLOSING)); } + /** + * Create closing container with 1 replica. + * Expectation: Missing containers 0. + * Remove the only replica. + * Expectation: Missing containers 1. + */ + @Test + public void testClosingMissingContainer() + throws IOException, TimeoutException { + final ContainerInfo container = getContainer(LifeCycleState.CLOSING); + final ContainerID id = container.containerID(); + + containerStateManager.addContainer(container.getProtobuf()); + + // One replica in OPEN state + final Set replicas = getReplicas(id, State.OPEN, + randomDatanodeDetails()); + + for (ContainerReplica replica : replicas) { + containerStateManager.updateContainerReplica(id, replica); + } + + final int currentCloseCommandCount = datanodeCommandHandler + .getInvocationCount(SCMCommandProto.Type.closeContainerCommand); + + replicationManager.processAll(); + eventQueue.processAll(1000); + Assertions.assertEquals(currentCloseCommandCount + 1, + datanodeCommandHandler.getInvocationCount( + SCMCommandProto.Type.closeContainerCommand)); + + ReplicationManagerReport report = replicationManager.getContainerReport(); + Assertions.assertEquals(1, report.getStat(LifeCycleState.CLOSING)); + Assertions.assertEquals(0, report.getStat( + ReplicationManagerReport.HealthState.MISSING)); + + for (ContainerReplica replica : replicas) { + containerStateManager.removeContainerReplica(id, replica); + } + + replicationManager.processAll(); + eventQueue.processAll(1000); + Assertions.assertEquals(currentCloseCommandCount + 1, + datanodeCommandHandler.getInvocationCount( + SCMCommandProto.Type.closeContainerCommand)); + + report = replicationManager.getContainerReport(); + Assertions.assertEquals(1, report.getStat(LifeCycleState.CLOSING)); + Assertions.assertEquals(1, report.getStat( + ReplicationManagerReport.HealthState.MISSING)); + Assertions.assertEquals(1, report.getStat( + ReplicationManagerReport.HealthState.UNDER_REPLICATED)); + Assertions.assertEquals(1, report.getStat( + ReplicationManagerReport.HealthState.MIS_REPLICATED)); + } + @Test public void testReplicateCommandTimeout() throws IOException, TimeoutException {