This is an automated email from the ASF dual-hosted git repository.
aswinshakil 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 5e5243eca2a HDDS-14714. Support keeping a configurable number of extra
copies of quasi-closed containers. (#9829)
5e5243eca2a is described below
commit 5e5243eca2a28ba5127be5e10bba97a99adf9d52
Author: Aswin Shakil Balasubramanian <[email protected]>
AuthorDate: Tue Mar 24 11:06:32 2026 -0700
HDDS-14714. Support keeping a configurable number of extra copies of
quasi-closed containers. (#9829)
---
.../QuasiClosedStuckOverReplicationHandler.java | 4 +-
.../replication/QuasiClosedStuckReplicaCount.java | 77 +++++-
.../QuasiClosedStuckUnderReplicationHandler.java | 4 +-
.../container/replication/ReplicationManager.java | 42 ++-
.../health/QuasiClosedStuckReplicationCheck.java | 20 +-
.../container/replication/ReplicationTestUtil.java | 24 ++
...TestQuasiClosedStuckOverReplicationHandler.java | 96 +++++--
.../TestQuasiClosedStuckReplicaCount.java | 302 ++++++++++++++-------
...estQuasiClosedStuckUnderReplicationHandler.java | 61 +++--
.../TestQuasiClosedStuckReplicationCheck.java | 40 ++-
.../replicationManagerTests/quasi_closed.json | 57 ++--
11 files changed, 520 insertions(+), 207 deletions(-)
diff --git
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/QuasiClosedStuckOverReplicationHandler.java
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/QuasiClosedStuckOverReplicationHandler.java
index 3ff23b495e8..e7eee2aeb48 100644
---
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/QuasiClosedStuckOverReplicationHandler.java
+++
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/QuasiClosedStuckOverReplicationHandler.java
@@ -76,8 +76,10 @@ public int processAndSendCommands(Set<ContainerReplica>
replicas, List<Container
})
.collect(Collectors.toSet());
+ ReplicationManager.ReplicationManagerConfiguration rmConf =
replicationManager.getConfig();
QuasiClosedStuckReplicaCount replicaCount =
- new QuasiClosedStuckReplicaCount(healthyReplicas,
remainingMaintenanceRedundancy);
+ new QuasiClosedStuckReplicaCount(healthyReplicas,
remainingMaintenanceRedundancy,
+ rmConf.getQuasiClosedStuckBestOriginCopies(),
rmConf.getQuasiClosedStuckOtherOriginCopies());
List<QuasiClosedStuckReplicaCount.MisReplicatedOrigin> misReplicatedOrigins
= replicaCount.getOverReplicatedOrigins();
diff --git
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/QuasiClosedStuckReplicaCount.java
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/QuasiClosedStuckReplicaCount.java
index 97df8cf958f..0e62913287d 100644
---
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/QuasiClosedStuckReplicaCount.java
+++
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/QuasiClosedStuckReplicaCount.java
@@ -17,6 +17,8 @@
package org.apache.hadoop.hdds.scm.container.replication;
+import static
org.apache.hadoop.hdds.protocol.proto.StorageContainerDatanodeProtocolProtos.ContainerReplicaProto.State.UNHEALTHY;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -26,11 +28,16 @@
import java.util.Set;
import org.apache.hadoop.hdds.protocol.DatanodeID;
import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
-import
org.apache.hadoop.hdds.protocol.proto.StorageContainerDatanodeProtocolProtos;
import org.apache.hadoop.hdds.scm.container.ContainerReplica;
/**
* Class to count the replicas in a quasi-closed stuck container.
+ *
+ * <p>Origins are ranked by their highest healthy BCSID (sequenceId). The
origins with the
+ * highest BCSID receive {@code bestOriginCopies} replicas, while all other
origins receive
+ * {@code otherOriginCopies}. If multiple origins share the same highest BCSID
they are all treated
+ * as "best". For a single-origin container, {@code bestOriginCopies} is
always used.
+ *
*/
public class QuasiClosedStuckReplicaCount {
@@ -40,13 +47,20 @@ public class QuasiClosedStuckReplicaCount {
private final int minHealthyForMaintenance;
private final boolean hasHealthyReplicas;
private final boolean hasOutOfServiceReplicas;
+ private final int bestOriginCopies;
+ private final int otherOriginCopies;
+ private final Set<DatanodeID> bestOrigins;
- public QuasiClosedStuckReplicaCount(Set<ContainerReplica> replicas, int
minHealthyForMaintenance) {
+ public QuasiClosedStuckReplicaCount(Set<ContainerReplica> replicas, int
minHealthyForMaintenance,
+ int bestOriginCopies, int otherOriginCopies) {
this.minHealthyForMaintenance = minHealthyForMaintenance;
+ this.bestOriginCopies = bestOriginCopies;
+ this.otherOriginCopies = otherOriginCopies;
+
boolean hasHealthy = false;
boolean hasOutOfService = false;
for (ContainerReplica r : replicas) {
- if (r.getState() !=
StorageContainerDatanodeProtocolProtos.ContainerReplicaProto.State.UNHEALTHY) {
+ if (r.getState() != UNHEALTHY) {
hasHealthy = true;
}
replicasByOrigin.computeIfAbsent(r.getOriginDatanodeId(), k -> new
HashSet<>()).add(r);
@@ -64,6 +78,39 @@ public QuasiClosedStuckReplicaCount(Set<ContainerReplica>
replicas, int minHealt
this.hasHealthyReplicas = hasHealthy;
this.hasOutOfServiceReplicas = hasOutOfService;
+ this.bestOrigins = computeBestOrigins();
+ }
+
+ /**
+ * Identifies the best origins whose maximum BCSID among healthy replicas
equals the cluster-wide maximum healthy
+ * BCSID. Origins with only UNHEALTHY replicas are excluded. If all replicas
are UNHEALTHY the returned set is empty.
+ */
+ private Set<DatanodeID> computeBestOrigins() {
+ long maxBcsid = Long.MIN_VALUE;
+
+ for (Map.Entry<DatanodeID, Set<ContainerReplica>> entry :
replicasByOrigin.entrySet()) {
+ for (ContainerReplica r : entry.getValue()) {
+ if (r.getState() != UNHEALTHY && r.getSequenceId() != null &&
r.getSequenceId() > maxBcsid) {
+ maxBcsid = r.getSequenceId();
+ }
+ }
+ }
+
+ if (maxBcsid == Long.MIN_VALUE) {
+ return Collections.emptySet();
+ }
+
+ final long highestBcsid = maxBcsid;
+ Set<DatanodeID> best = new HashSet<>();
+ for (Map.Entry<DatanodeID, Set<ContainerReplica>> entry :
replicasByOrigin.entrySet()) {
+ boolean hasBestBcsid = entry.getValue().stream()
+ .anyMatch(r -> r.getState() != UNHEALTHY && r.getSequenceId() != null
+ && r.getSequenceId() == highestBcsid);
+ if (hasBestBcsid) {
+ best.add(entry.getKey());
+ }
+ }
+ return best;
}
public int availableOrigins() {
@@ -92,6 +139,10 @@ private int getMaintenanceCount(DatanodeID origin) {
return maintenance == null ? 0 : maintenance.size();
}
+ private int targetCopiesForOrigin(DatanodeID origin) {
+ return bestOrigins.contains(origin) ? bestOriginCopies : otherOriginCopies;
+ }
+
public List<MisReplicatedOrigin> getUnderReplicatedReplicas() {
List<MisReplicatedOrigin> misReplicatedOrigins = new ArrayList<>();
@@ -114,20 +165,21 @@ public List<MisReplicatedOrigin>
getUnderReplicatedReplicas() {
return misReplicatedOrigins;
}
- // If there are multiple origins, we expect 2 copies of each origin
- // For maintenance, we expect 1 copy of each origin and ignore the
minHealthyForMaintenance parameter
+ // Multiple origins: the best origins target bestOriginCopies; all others
target otherOriginCopies.
+ // For maintenance, we expect 1 copy of each origin online regardless of
best/other designation.
for (Map.Entry<DatanodeID, Set<ContainerReplica>> entry :
replicasByOrigin.entrySet()) {
final Set<ContainerReplica> inService = getInService(entry.getKey());
final int maintenanceCount = getMaintenanceCount(entry.getKey());
+ final int target = targetCopiesForOrigin(entry.getKey());
- if (inService.size() < 2) {
+ if (inService.size() < target) {
if (maintenanceCount > 0) {
if (inService.isEmpty()) {
// We need 1 copy online for maintenance
misReplicatedOrigins.add(new MisReplicatedOrigin(entry.getValue(),
1));
}
} else {
- misReplicatedOrigins.add(new MisReplicatedOrigin(entry.getValue(), 2
- inService.size()));
+ misReplicatedOrigins.add(new MisReplicatedOrigin(entry.getValue(),
target - inService.size()));
}
}
}
@@ -136,7 +188,7 @@ public List<MisReplicatedOrigin>
getUnderReplicatedReplicas() {
/**
* Returns True is the container is over-replicated. This means that if we
have a single origin, there are more than
- * 3 copies. If we have multiple origins, there are more than 2 copies of
each origin.
+ * 3 copies. If we have multiple origins, there are more than target copies
of each origin.
* The over replication check ignore maintenance replicas. The container may
become over replicated when maintenance
* ends.
*
@@ -147,7 +199,7 @@ public boolean isOverReplicated() {
}
public List<MisReplicatedOrigin> getOverReplicatedOrigins() {
- // If there is only a single origin, we expect 3 copies, otherwise we
expect 2 copies of each origin
+ // If there is only a single origin, we expect 3 copies.
if (replicasByOrigin.size() == 1) {
final DatanodeID origin = replicasByOrigin.keySet().iterator().next();
final Set<ContainerReplica> inService = getInService(origin);
@@ -157,15 +209,14 @@ public List<MisReplicatedOrigin>
getOverReplicatedOrigins() {
return Collections.emptyList();
}
- // If there are multiple origins, we expect 2 copies of each origin
List<MisReplicatedOrigin> overReplicatedOrigins = new ArrayList<>();
for (DatanodeID origin : replicasByOrigin.keySet()) {
final Set<ContainerReplica> replicas = getInService(origin);
- if (replicas.size() > 2) {
- overReplicatedOrigins.add(new MisReplicatedOrigin(replicas,
replicas.size() - 2));
+ final int target = targetCopiesForOrigin(origin);
+ if (replicas.size() > target) {
+ overReplicatedOrigins.add(new MisReplicatedOrigin(replicas,
replicas.size() - target));
}
}
- // If we have 2 copies or less of each origin, we are not over-replicated
return overReplicatedOrigins;
}
diff --git
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/QuasiClosedStuckUnderReplicationHandler.java
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/QuasiClosedStuckUnderReplicationHandler.java
index 55b503822fd..91ab321859a 100644
---
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/QuasiClosedStuckUnderReplicationHandler.java
+++
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/QuasiClosedStuckUnderReplicationHandler.java
@@ -83,8 +83,10 @@ public int processAndSendCommands(Set<ContainerReplica>
replicas, List<Container
return 0;
}
+ ReplicationManager.ReplicationManagerConfiguration rmConf =
replicationManager.getConfig();
QuasiClosedStuckReplicaCount replicaCount =
- new QuasiClosedStuckReplicaCount(replicas,
remainingMaintenanceRedundancy);
+ new QuasiClosedStuckReplicaCount(replicas,
remainingMaintenanceRedundancy,
+ rmConf.getQuasiClosedStuckBestOriginCopies(),
rmConf.getQuasiClosedStuckOtherOriginCopies());
List<QuasiClosedStuckReplicaCount.MisReplicatedOrigin> misReplicatedOrigins
= replicaCount.getUnderReplicatedReplicas();
diff --git
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/ReplicationManager.java
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/ReplicationManager.java
index 32808fc85a5..7096c18e6c5 100644
---
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/ReplicationManager.java
+++
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/ReplicationManager.java
@@ -269,7 +269,7 @@ public ReplicationManager(final
ReplicationManagerConfiguration rmConf,
.addNext(new MismatchedReplicasHandler(this))
.addNext(new EmptyContainerHandler(this))
.addNext(new DeletingContainerHandler(this))
- .addNext(new QuasiClosedStuckReplicationCheck())
+ .addNext(new QuasiClosedStuckReplicationCheck(rmConf))
.addNext(ecReplicationCheckHandler)
.addNext(ratisReplicationCheckHandler)
.addNext(new ClosedWithUnhealthyReplicasHandler(this))
@@ -1285,6 +1285,30 @@ public static class ReplicationManagerConfiguration
)
private int containerSampleLimit = 100;
+ @Config(key = "hdds.scm.replication.quasi.closed.stuck.best.origin.copies",
+ type = ConfigType.INT,
+ defaultValue = "3",
+ reconfigurable = true,
+ tags = { SCM },
+ description = "For quasi-closed stuck containers with multiple
diverged origins, " +
+ "the number of replicas to maintain for the origin with the
highest bcsId " +
+ "among healthy replicas. This origin is considered the 'best' copy
and receives " +
+ "extra fault-tolerance. If multiple origins share the same highest
bcsId, all of them receive this count."
+ )
+ private int quasiClosedStuckBestOriginCopies = 3;
+
+ @Config(key =
"hdds.scm.replication.quasi.closed.stuck.other.origin.copies",
+ type = ConfigType.INT,
+ defaultValue = "2",
+ reconfigurable = true,
+ tags = { SCM },
+ description = "For quasi-closed stuck containers with multiple
diverged origins, " +
+ "the number of replicas to maintain for each origin that does not
have the " +
+ "highest block commit sequence ID (BCSID). These replicas are kept
to preserve " +
+ "data integrity across diverged copies."
+ )
+ private int quasiClosedStuckOtherOriginCopies = 2;
+
public long getDatanodeTimeoutOffset() {
return datanodeTimeoutOffset;
}
@@ -1377,6 +1401,22 @@ public void setContainerSampleLimit(int sampleLimit) {
this.containerSampleLimit = sampleLimit;
}
+ public int getQuasiClosedStuckBestOriginCopies() {
+ return quasiClosedStuckBestOriginCopies;
+ }
+
+ public void setQuasiClosedStuckBestOriginCopies(int copies) {
+ this.quasiClosedStuckBestOriginCopies = copies;
+ }
+
+ public int getQuasiClosedStuckOtherOriginCopies() {
+ return quasiClosedStuckOtherOriginCopies;
+ }
+
+ public void setQuasiClosedStuckOtherOriginCopies(int copies) {
+ this.quasiClosedStuckOtherOriginCopies = copies;
+ }
+
@PostConstruct
public void validate() {
if (datanodeTimeoutOffset < 0) {
diff --git
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/health/QuasiClosedStuckReplicationCheck.java
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/health/QuasiClosedStuckReplicationCheck.java
index d89c3bb351e..e520153ad84 100644
---
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/health/QuasiClosedStuckReplicationCheck.java
+++
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/health/QuasiClosedStuckReplicationCheck.java
@@ -28,17 +28,25 @@
import org.apache.hadoop.hdds.scm.container.replication.ContainerHealthResult;
import org.apache.hadoop.hdds.scm.container.replication.ContainerReplicaOp;
import
org.apache.hadoop.hdds.scm.container.replication.QuasiClosedStuckReplicaCount;
+import org.apache.hadoop.hdds.scm.container.replication.ReplicationManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Class to check for the replication of the replicas in quasi-closed stuck
containers. As we want to maintain
- * as much data and information as possible, the rule for QC stuck container
is to maintain 2 copies of each origin
- * if there is more than 1 origin. If there is only 1 origin, then we need to
maintain 3 copies.
+ * as much data and information as possible, the rule for QC stuck container
is to maintain a configurable number
+ * of copies of the origin with the highest BCSID (bestOriginCopies, default
3), and a configurable number of copies
+ * of each other origin (otherOriginCopies, default 2). If there is only 1
origin, bestOriginCopies copies are kept.
*/
public class QuasiClosedStuckReplicationCheck extends AbstractCheck {
private static final Logger LOG =
LoggerFactory.getLogger(QuasiClosedStuckReplicationCheck.class);
+ private final ReplicationManager.ReplicationManagerConfiguration rmConf;
+
+ public
QuasiClosedStuckReplicationCheck(ReplicationManager.ReplicationManagerConfiguration
rmConf) {
+ this.rmConf = rmConf;
+ }
+
public static boolean shouldHandleAsQuasiClosedStuck(ContainerInfo
containerInfo, Set<ContainerReplica> replicas) {
if (containerInfo.getState() != QUASI_CLOSED) {
return false;
@@ -46,7 +54,7 @@ public static boolean
shouldHandleAsQuasiClosedStuck(ContainerInfo containerInfo
if (!QuasiClosedContainerHandler.isQuasiClosedStuck(containerInfo,
replicas)) {
return false;
}
- QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 0);
+ QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 0, 3, 2);
if (replicaCount.availableOrigins() == 1) {
// This is the 3 copies of a single origin case, so allow it to be
handled via the normal under-replicated
// handler.
@@ -70,8 +78,10 @@ public boolean handle(ContainerCheckRequest request) {
return true;
}
- QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(
- request.getContainerReplicas(), request.getMaintenanceRedundancy());
+ QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(request.getContainerReplicas(),
+ request.getMaintenanceRedundancy(),
+ rmConf.getQuasiClosedStuckBestOriginCopies(),
+ rmConf.getQuasiClosedStuckOtherOriginCopies());
if (!replicaCount.hasHealthyReplicas()) {
// All unhealthy are handled by a different handler
diff --git
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/ReplicationTestUtil.java
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/ReplicationTestUtil.java
index ad5a30e3ace..63f4c6c9f33 100644
---
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/ReplicationTestUtil.java
+++
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/ReplicationTestUtil.java
@@ -161,6 +161,30 @@ public static Set<ContainerReplica>
createReplicasWithOriginAndOpState(
return replicas;
}
+ /**
+ * Creates a single replica with a specific origin, operational state,
replica state, and BCSID.
+ */
+ public static ContainerReplica createReplicaWithOriginAndSeqId(
+ ContainerID containerID, DatanodeID originNodeId,
+ HddsProtos.NodeOperationalState opState,
+ ContainerReplicaProto.State replicaState, long seqId) {
+ return createContainerReplica(containerID, 0, opState, replicaState, 123L,
1234L,
+ MockDatanodeDetails.randomDatanodeDetails(), originNodeId, seqId);
+ }
+
+ /**
+ * Adds {@code count} replicas with the given origin, operational state,
replica state, and BCSID.
+ * to the provided set.
+ */
+ public static void addReplicasWithOriginAndSeqId(
+ Set<ContainerReplica> replicas, ContainerID containerID,
+ DatanodeID originNodeId, HddsProtos.NodeOperationalState opState,
+ ContainerReplicaProto.State replicaState, long seqId, int count) {
+ for (int i = 0; i < count; i++) {
+ replicas.add(createReplicaWithOriginAndSeqId(containerID, originNodeId,
opState, replicaState, seqId));
+ }
+ }
+
public static ContainerReplica createContainerReplica(ContainerID
containerID,
int replicaIndex, HddsProtos.NodeOperationalState opState,
ContainerReplicaProto.State replicaState) {
diff --git
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/TestQuasiClosedStuckOverReplicationHandler.java
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/TestQuasiClosedStuckOverReplicationHandler.java
index 67d1fe09371..5a493b1981a 100644
---
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/TestQuasiClosedStuckOverReplicationHandler.java
+++
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/TestQuasiClosedStuckOverReplicationHandler.java
@@ -17,7 +17,9 @@
package org.apache.hadoop.hdds.scm.container.replication;
+import static
org.apache.hadoop.hdds.protocol.proto.HddsProtos.NodeOperationalState.IN_SERVICE;
import static
org.apache.hadoop.hdds.protocol.proto.HddsProtos.ReplicationFactor.THREE;
+import static
org.apache.hadoop.hdds.protocol.proto.StorageContainerDatanodeProtocolProtos.ContainerReplicaProto.State.QUASI_CLOSED;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
@@ -97,11 +99,11 @@ void setup() throws NodeNotFoundException,
@Test
public void testReturnsZeroIfNotOverReplicated() throws IOException {
Set<ContainerReplica> replicas =
ReplicationTestUtil.createReplicasWithOriginAndOpState(container.containerID(),
-
StorageContainerDatanodeProtocolProtos.ContainerReplicaProto.State.QUASI_CLOSED,
- Pair.of(origin1, HddsProtos.NodeOperationalState.IN_SERVICE),
- Pair.of(origin1, HddsProtos.NodeOperationalState.IN_SERVICE),
- Pair.of(origin2, HddsProtos.NodeOperationalState.IN_SERVICE),
- Pair.of(origin2, HddsProtos.NodeOperationalState.IN_SERVICE));
+ QUASI_CLOSED,
+ Pair.of(origin1, IN_SERVICE),
+ Pair.of(origin1, IN_SERVICE),
+ Pair.of(origin2, IN_SERVICE),
+ Pair.of(origin2, IN_SERVICE));
int count = handler.processAndSendCommands(replicas,
Collections.emptyList(), getOverReplicatedHealthResult(), 1);
assertEquals(0, count);
@@ -110,13 +112,13 @@ public void testReturnsZeroIfNotOverReplicated() throws
IOException {
@Test
public void testNoCommandsScheduledIfPendingOps() throws IOException {
Set<ContainerReplica> replicas =
ReplicationTestUtil.createReplicasWithOriginAndOpState(container.containerID(),
-
StorageContainerDatanodeProtocolProtos.ContainerReplicaProto.State.QUASI_CLOSED,
- Pair.of(origin1, HddsProtos.NodeOperationalState.IN_SERVICE),
- Pair.of(origin1, HddsProtos.NodeOperationalState.IN_SERVICE),
- Pair.of(origin1, HddsProtos.NodeOperationalState.IN_SERVICE),
- Pair.of(origin2, HddsProtos.NodeOperationalState.IN_SERVICE),
- Pair.of(origin2, HddsProtos.NodeOperationalState.IN_SERVICE),
- Pair.of(origin2, HddsProtos.NodeOperationalState.IN_SERVICE));
+ QUASI_CLOSED,
+ Pair.of(origin1, IN_SERVICE),
+ Pair.of(origin1, IN_SERVICE),
+ Pair.of(origin1, IN_SERVICE),
+ Pair.of(origin2, IN_SERVICE),
+ Pair.of(origin2, IN_SERVICE),
+ Pair.of(origin2, IN_SERVICE));
List<ContainerReplicaOp> pendingOps = new ArrayList<>();
pendingOps.add(new ContainerReplicaOp(
ContainerReplicaOp.PendingOpType.DELETE,
@@ -132,13 +134,21 @@ public void testNoCommandsScheduledIfPendingOps() throws
IOException {
@Test
public void testCommandScheduledForOverReplicatedContainer() throws
IOException {
- Set<ContainerReplica> replicas =
ReplicationTestUtil.createReplicasWithOriginAndOpState(container.containerID(),
-
StorageContainerDatanodeProtocolProtos.ContainerReplicaProto.State.QUASI_CLOSED,
- Pair.of(origin1, HddsProtos.NodeOperationalState.IN_SERVICE),
- Pair.of(origin1, HddsProtos.NodeOperationalState.IN_SERVICE),
- Pair.of(origin1, HddsProtos.NodeOperationalState.IN_SERVICE),
- Pair.of(origin2, HddsProtos.NodeOperationalState.IN_SERVICE),
- Pair.of(origin2, HddsProtos.NodeOperationalState.IN_SERVICE));
+ // origin1 is the best origin (BCSID=10, target=3): has 4 copies,
over-replicated by 1.
+ // origin2 is an other origin (BCSID=5, target=2): has 2 copies, at target.
+ Set<ContainerReplica> replicas = new HashSet<>();
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(container.containerID(),
+ origin1, IN_SERVICE, QUASI_CLOSED, 10));
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(container.containerID(),
+ origin1, IN_SERVICE, QUASI_CLOSED, 10));
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(container.containerID(),
+ origin1, IN_SERVICE, QUASI_CLOSED, 10));
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(container.containerID(),
+ origin1, IN_SERVICE, QUASI_CLOSED, 10));
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(container.containerID(),
+ origin2, IN_SERVICE, QUASI_CLOSED, 5));
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(container.containerID(),
+ origin2, IN_SERVICE, QUASI_CLOSED, 5));
int count = handler.processAndSendCommands(replicas,
Collections.emptyList(), getOverReplicatedHealthResult(), 1);
assertEquals(1, count);
@@ -148,14 +158,25 @@ public void
testCommandScheduledForOverReplicatedContainer() throws IOException
@Test
public void testOverloadedExceptionContinuesAndThrows() throws
NotLeaderException, CommandTargetOverloadedException {
- Set<ContainerReplica> replicas =
ReplicationTestUtil.createReplicasWithOriginAndOpState(container.containerID(),
-
StorageContainerDatanodeProtocolProtos.ContainerReplicaProto.State.QUASI_CLOSED,
- Pair.of(origin1, HddsProtos.NodeOperationalState.IN_SERVICE),
- Pair.of(origin1, HddsProtos.NodeOperationalState.IN_SERVICE),
- Pair.of(origin1, HddsProtos.NodeOperationalState.IN_SERVICE),
- Pair.of(origin2, HddsProtos.NodeOperationalState.IN_SERVICE),
- Pair.of(origin2, HddsProtos.NodeOperationalState.IN_SERVICE),
- Pair.of(origin2, HddsProtos.NodeOperationalState.IN_SERVICE));
+ // origin1 is the best origin (BCSID=10, target=3): has 4 copies,
over-replicated by 1.
+ // origin2 is an other origin (BCSID=5, target=2): has 3 copies,
over-replicated by 1.
+ // With the first delete overloaded: the first delete command throws, the
second succeeds.
+ // Expect 1 command sent total and CommandTargetOverloadedException thrown.
+ Set<ContainerReplica> replicas = new HashSet<>();
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(container.containerID(),
+ origin1, IN_SERVICE, QUASI_CLOSED, 10));
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(container.containerID(),
+ origin1, IN_SERVICE, QUASI_CLOSED, 10));
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(container.containerID(),
+ origin1, IN_SERVICE, QUASI_CLOSED, 10));
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(container.containerID(),
+ origin1, IN_SERVICE, QUASI_CLOSED, 10));
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(container.containerID(),
+ origin2, IN_SERVICE, QUASI_CLOSED, 5));
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(container.containerID(),
+ origin2, IN_SERVICE, QUASI_CLOSED, 5));
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(container.containerID(),
+ origin2, IN_SERVICE, QUASI_CLOSED, 5));
ReplicationTestUtil.mockRMSendThrottledDeleteCommand(replicationManager,
commandsSent, new AtomicBoolean(true));
@@ -164,6 +185,27 @@ public void testOverloadedExceptionContinuesAndThrows()
throws NotLeaderExceptio
assertEquals(1, commandsSent.size());
}
+ @Test
+ public void testBestOriginNotOverReplicated() throws IOException {
+ // origin1 is the best origin (BCSID=10, target=3): has exactly 3 copies,
at target.
+ // origin2 is an other origin (BCSID=5, target=2): has exactly 2 copies,
at target.
+ // Neither origin is over-replicated, so no delete commands should be
scheduled.
+ Set<ContainerReplica> replicas = new HashSet<>();
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(container.containerID(),
+ origin1, IN_SERVICE, QUASI_CLOSED, 10));
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(container.containerID(),
+ origin1, IN_SERVICE, QUASI_CLOSED, 10));
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(container.containerID(),
+ origin1, IN_SERVICE, QUASI_CLOSED, 10));
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(container.containerID(),
+ origin2, IN_SERVICE, QUASI_CLOSED, 5));
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(container.containerID(),
+ origin2, IN_SERVICE, QUASI_CLOSED, 5));
+
+ int count = handler.processAndSendCommands(replicas,
Collections.emptyList(), getOverReplicatedHealthResult(), 1);
+ assertEquals(0, count);
+ }
+
private ContainerHealthResult.OverReplicatedHealthResult
getOverReplicatedHealthResult() {
ContainerHealthResult.OverReplicatedHealthResult
healthResult =
mock(ContainerHealthResult.OverReplicatedHealthResult.class);
diff --git
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/TestQuasiClosedStuckReplicaCount.java
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/TestQuasiClosedStuckReplicaCount.java
index 3b74eccc72f..bfa27006d54 100644
---
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/TestQuasiClosedStuckReplicaCount.java
+++
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/TestQuasiClosedStuckReplicaCount.java
@@ -27,6 +27,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang3.tuple.Pair;
@@ -46,13 +47,17 @@ public class TestQuasiClosedStuckReplicaCount {
@Test
public void testCorrectlyReplicationWithThreeOrigins() {
- Set<ContainerReplica> replicas =
ReplicationTestUtil.createReplicasWithOriginAndOpState(
- ContainerID.valueOf(1), QUASI_CLOSED,
- Pair.of(origin1, IN_SERVICE), Pair.of(origin1, IN_SERVICE),
- Pair.of(origin2, IN_SERVICE), Pair.of(origin2, IN_SERVICE),
- Pair.of(origin3, IN_SERVICE), Pair.of(origin3, IN_SERVICE));
-
- QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1);
+ // origin1 is best (BCSID=10) with 3 copies at target; origin2 and origin3
are other (BCSID=5)
+ // with 2 copies each at target.
+ Set<ContainerReplica> replicas = new HashSet<>();
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin1,
+ IN_SERVICE, QUASI_CLOSED, 10, 3);
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin2,
+ IN_SERVICE, QUASI_CLOSED, 5, 2);
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin3,
+ IN_SERVICE, QUASI_CLOSED, 5, 2);
+
+ QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1, 3, 2);
assertFalse(replicaCount.isUnderReplicated());
assertFalse(replicaCount.isOverReplicated());
assertTrue(replicaCount.getUnderReplicatedReplicas().isEmpty());
@@ -60,12 +65,14 @@ public void testCorrectlyReplicationWithThreeOrigins() {
@Test
public void testCorrectReplicationWithTwoOrigins() {
- Set<ContainerReplica> replicas =
ReplicationTestUtil.createReplicasWithOriginAndOpState(
- ContainerID.valueOf(1), QUASI_CLOSED,
- Pair.of(origin1, IN_SERVICE), Pair.of(origin1, IN_SERVICE),
- Pair.of(origin2, IN_SERVICE), Pair.of(origin2, IN_SERVICE));
-
- QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1);
+ // origin1 is best (BCSID=10) with 3 copies at target; origin2 is other
(BCSID=5) with 2 copies at target.
+ Set<ContainerReplica> replicas = new HashSet<>();
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin1,
+ IN_SERVICE, QUASI_CLOSED, 10, 3);
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin2,
+ IN_SERVICE, QUASI_CLOSED, 5, 2);
+
+ QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1, 3, 2);
assertFalse(replicaCount.isUnderReplicated());
assertFalse(replicaCount.isOverReplicated());
assertTrue(replicaCount.getUnderReplicatedReplicas().isEmpty());
@@ -77,7 +84,7 @@ public void testCorrectReplicationWithOneOrigin() {
ContainerID.valueOf(1), QUASI_CLOSED,
Pair.of(origin1, IN_SERVICE), Pair.of(origin1, IN_SERVICE),
Pair.of(origin1, IN_SERVICE));
- QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1);
+ QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1, 3, 2);
assertFalse(replicaCount.isUnderReplicated());
assertFalse(replicaCount.isOverReplicated());
assertTrue(replicaCount.getUnderReplicatedReplicas().isEmpty());
@@ -85,13 +92,18 @@ public void testCorrectReplicationWithOneOrigin() {
@Test
public void testUnderReplicationWithThreeOrigins() {
- Set<ContainerReplica> replicas =
ReplicationTestUtil.createReplicasWithOriginAndOpState(
- ContainerID.valueOf(1), QUASI_CLOSED,
- Pair.of(origin1, IN_SERVICE), Pair.of(origin1, IN_SERVICE),
- Pair.of(origin2, IN_SERVICE), Pair.of(origin2, IN_SERVICE),
- Pair.of(origin3, IN_SERVICE));
-
- QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1);
+ // origin1 is best (BCSID=10) with 3 copies at target.
+ // origin2 is other (BCSID=5) with 2 copies at target.
+ // origin3 is other (BCSID=5) with only 1 copy, so it is under-replicated
by 1.
+ Set<ContainerReplica> replicas = new HashSet<>();
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin1,
+ IN_SERVICE, QUASI_CLOSED, 10, 3);
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin2,
+ IN_SERVICE, QUASI_CLOSED, 5, 2);
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin3,
+ IN_SERVICE, QUASI_CLOSED, 5, 1);
+
+ QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1, 3, 2);
assertTrue(replicaCount.isUnderReplicated());
assertFalse(replicaCount.isOverReplicated());
validateMisReplicatedOrigins(replicaCount.getUnderReplicatedReplicas(), 1,
1, 1, origin3);
@@ -99,19 +111,23 @@ public void testUnderReplicationWithThreeOrigins() {
@Test
public void testUnderReplicationWithThreeOriginsTwoUnderReplicated() {
- Set<ContainerReplica> replicas =
ReplicationTestUtil.createReplicasWithOriginAndOpState(
- ContainerID.valueOf(1), QUASI_CLOSED,
- Pair.of(origin1, IN_SERVICE),
- Pair.of(origin2, IN_SERVICE), Pair.of(origin2, IN_SERVICE),
- Pair.of(origin3, IN_SERVICE));
-
- QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1);
+ // origin2 is best (BCSID=10) with 3 copies at target.
+ // origin1 and origin3 are other (BCSID=5) with only 1 copy each, so both
are under-replicated.
+ Set<ContainerReplica> replicas = new HashSet<>();
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin1,
+ IN_SERVICE, QUASI_CLOSED, 5, 1);
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin2,
+ IN_SERVICE, QUASI_CLOSED, 10, 3);
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin3,
+ IN_SERVICE, QUASI_CLOSED, 5, 1);
+
+ QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1, 3, 2);
assertTrue(replicaCount.isUnderReplicated());
assertFalse(replicaCount.isOverReplicated());
List<QuasiClosedStuckReplicaCount.MisReplicatedOrigin>
misReplicatedOrigins =
replicaCount.getUnderReplicatedReplicas();
- assertTrue(misReplicatedOrigins.size() == 2);
+ assertEquals(2, misReplicatedOrigins.size());
for (QuasiClosedStuckReplicaCount.MisReplicatedOrigin misReplicatedOrigin
: misReplicatedOrigins) {
final DatanodeID source =
misReplicatedOrigin.getSources().iterator().next().getOriginDatanodeId();
@@ -121,12 +137,15 @@ public void
testUnderReplicationWithThreeOriginsTwoUnderReplicated() {
@Test
public void testUnderReplicationWithTwoOrigins() {
- Set<ContainerReplica> replicas =
ReplicationTestUtil.createReplicasWithOriginAndOpState(
- ContainerID.valueOf(1), QUASI_CLOSED,
- Pair.of(origin1, IN_SERVICE), Pair.of(origin1, IN_SERVICE),
- Pair.of(origin2, IN_SERVICE));
-
- QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1);
+ // origin1 is best (BCSID=10) with 3 copies at target.
+ // origin2 is other (BCSID=5) with only 1 copy, so it is under-replicated
by 1.
+ Set<ContainerReplica> replicas = new HashSet<>();
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin1,
+ IN_SERVICE, QUASI_CLOSED, 10, 3);
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin2,
+ IN_SERVICE, QUASI_CLOSED, 5, 1);
+
+ QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1, 3, 2);
assertTrue(replicaCount.isUnderReplicated());
assertFalse(replicaCount.isOverReplicated());
validateMisReplicatedOrigins(replicaCount.getUnderReplicatedReplicas(), 1,
1, 1, origin2);
@@ -138,7 +157,7 @@ public void testUnderReplicationWithOneOrigin() {
ContainerID.valueOf(1), QUASI_CLOSED,
Pair.of(origin1, IN_SERVICE));
- QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1);
+ QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1, 3, 2);
assertTrue(replicaCount.isUnderReplicated());
assertFalse(replicaCount.isOverReplicated());
validateMisReplicatedOrigins(replicaCount.getUnderReplicatedReplicas(), 1,
1, 2, origin1);
@@ -146,13 +165,18 @@ public void testUnderReplicationWithOneOrigin() {
@Test
public void testOverReplicationWithThreeOrigins() {
- Set<ContainerReplica> replicas =
ReplicationTestUtil.createReplicasWithOriginAndOpState(
- ContainerID.valueOf(1), QUASI_CLOSED,
- Pair.of(origin1, IN_SERVICE), Pair.of(origin1, IN_SERVICE),
- Pair.of(origin2, IN_SERVICE), Pair.of(origin2, IN_SERVICE),
- Pair.of(origin3, IN_SERVICE), Pair.of(origin3, IN_SERVICE),
Pair.of(origin3, IN_SERVICE));
-
- QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1);
+ // origin1 is best (BCSID=10) with 3 copies at target.
+ // origin2 is other (BCSID=5) with 2 copies at target.
+ // origin3 is other (BCSID=5) with 3 copies, exceeding its target of 2 by
1.
+ Set<ContainerReplica> replicas = new HashSet<>();
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin1,
+ IN_SERVICE, QUASI_CLOSED, 10, 3);
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin2,
+ IN_SERVICE, QUASI_CLOSED, 5, 2);
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin3,
+ IN_SERVICE, QUASI_CLOSED, 5, 3);
+
+ QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1, 3, 2);
assertFalse(replicaCount.isUnderReplicated());
assertTrue(replicaCount.isOverReplicated());
validateMisReplicatedOrigins(replicaCount.getOverReplicatedOrigins(), 1,
3, 1, origin3);
@@ -160,12 +184,15 @@ public void testOverReplicationWithThreeOrigins() {
@Test
public void testOverReplicationWithTwoOrigins() {
- Set<ContainerReplica> replicas =
ReplicationTestUtil.createReplicasWithOriginAndOpState(
- ContainerID.valueOf(1), QUASI_CLOSED,
- Pair.of(origin1, IN_SERVICE), Pair.of(origin1, IN_SERVICE),
- Pair.of(origin2, IN_SERVICE), Pair.of(origin2, IN_SERVICE),
Pair.of(origin2, IN_SERVICE));
-
- QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1);
+ // origin1 is best (BCSID=10) with 3 copies at target.
+ // origin2 is other (BCSID=5) with 3 copies, exceeding its target of 2 by
1.
+ Set<ContainerReplica> replicas = new HashSet<>();
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin1,
+ IN_SERVICE, QUASI_CLOSED, 10, 3);
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin2,
+ IN_SERVICE, QUASI_CLOSED, 5, 3);
+
+ QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1, 3, 2);
assertFalse(replicaCount.isUnderReplicated());
assertTrue(replicaCount.isOverReplicated());
validateMisReplicatedOrigins(replicaCount.getOverReplicatedOrigins(), 1,
3, 1, origin2);
@@ -178,7 +205,7 @@ public void testOverReplicationWithOneOrigin() {
Pair.of(origin1, IN_SERVICE), Pair.of(origin1, IN_SERVICE),
Pair.of(origin1, IN_SERVICE),
Pair.of(origin1, IN_SERVICE));
- QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1);
+ QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1, 3, 2);
assertFalse(replicaCount.isUnderReplicated());
assertTrue(replicaCount.isOverReplicated());
validateMisReplicatedOrigins(replicaCount.getOverReplicatedOrigins(), 1,
4, 1, origin1);
@@ -186,29 +213,38 @@ public void testOverReplicationWithOneOrigin() {
@Test
public void testUnderReplicationDueToDecommissionWithThreeOrigins() {
- Set<ContainerReplica> replicas =
ReplicationTestUtil.createReplicasWithOriginAndOpState(
- ContainerID.valueOf(1), QUASI_CLOSED,
- Pair.of(origin1, DECOMMISSIONING), Pair.of(origin1, DECOMMISSIONING),
- Pair.of(origin2, IN_SERVICE), Pair.of(origin2, IN_SERVICE),
- Pair.of(origin3, IN_SERVICE), Pair.of(origin3, IN_SERVICE));
-
- QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1);
+ // origin1 is best (BCSID=10) with 2 decommissioning copies and 0
in-service, so it is under-replicated by 3.
+ // origin2 and origin3 are other (BCSID=5) with 2 in-service copies each
at target 2.
+ Set<ContainerReplica> replicas = new HashSet<>();
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin1,
+ DECOMMISSIONING, QUASI_CLOSED, 10, 2);
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin2,
+ IN_SERVICE, QUASI_CLOSED, 5, 2);
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin3,
+ IN_SERVICE, QUASI_CLOSED, 5, 2);
+
+ QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1, 3, 2);
assertTrue(replicaCount.isUnderReplicated());
assertFalse(replicaCount.isOverReplicated());
- validateMisReplicatedOrigins(replicaCount.getUnderReplicatedReplicas(), 1,
2, 2, origin1);
+ validateMisReplicatedOrigins(replicaCount.getUnderReplicatedReplicas(), 1,
2, 3, origin1);
}
@Test
public void testUnderReplicationDueToDecommissionWithTwoOrigins() {
- Set<ContainerReplica> replicas =
ReplicationTestUtil.createReplicasWithOriginAndOpState(
- ContainerID.valueOf(1), QUASI_CLOSED,
- Pair.of(origin1, IN_SERVICE), Pair.of(origin1, DECOMMISSIONING),
- Pair.of(origin2, IN_SERVICE), Pair.of(origin2, IN_SERVICE));
-
- QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1);
+ // origin1 is best (BCSID=10) with 1 in-service and 1 decommissioning
copy; it needs 2 more to reach target 3.
+ // origin2 is other (BCSID=5) with 2 in-service copies at target 2.
+ Set<ContainerReplica> replicas = new HashSet<>();
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(ContainerID.valueOf(1),
origin1,
+ IN_SERVICE, QUASI_CLOSED, 10));
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(ContainerID.valueOf(1),
origin1,
+ DECOMMISSIONING, QUASI_CLOSED, 10));
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin2,
+ IN_SERVICE, QUASI_CLOSED, 5, 2);
+
+ QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1, 3, 2);
assertTrue(replicaCount.isUnderReplicated());
assertFalse(replicaCount.isOverReplicated());
- validateMisReplicatedOrigins(replicaCount.getUnderReplicatedReplicas(), 1,
2, 1, origin1);
+ validateMisReplicatedOrigins(replicaCount.getUnderReplicatedReplicas(), 1,
2, 2, origin1);
}
@Test
@@ -217,7 +253,7 @@ public void
testUnderReplicationDueToDecommissionWithOneOrigin() {
ContainerID.valueOf(1), QUASI_CLOSED,
Pair.of(origin1, IN_SERVICE), Pair.of(origin1, DECOMMISSIONING),
Pair.of(origin1, DECOMMISSIONING));
- QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1);
+ QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1, 3, 2);
assertTrue(replicaCount.isUnderReplicated());
assertFalse(replicaCount.isOverReplicated());
validateMisReplicatedOrigins(replicaCount.getUnderReplicatedReplicas(), 1,
3, 2, origin1);
@@ -225,25 +261,37 @@ public void
testUnderReplicationDueToDecommissionWithOneOrigin() {
@Test
public void testNoOverReplicationWithOutOfServiceReplicasWithThreeOrigins() {
- Set<ContainerReplica> replicas =
ReplicationTestUtil.createReplicasWithOriginAndOpState(
- ContainerID.valueOf(1), QUASI_CLOSED,
- Pair.of(origin1, IN_SERVICE), Pair.of(origin1, IN_SERVICE),
Pair.of(origin1, DECOMMISSIONED),
- Pair.of(origin2, IN_SERVICE), Pair.of(origin2, IN_SERVICE),
- Pair.of(origin3, IN_SERVICE), Pair.of(origin3, IN_SERVICE));
-
- QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1);
+ // origin1 is best (BCSID=10) with 3 in-service copies at target plus 1
decommissioned.
+ // The decommissioned replica is out-of-service and must not be counted
toward over-replication.
+ // origin2 and origin3 are other (BCSID=5) with 2 in-service copies each
at target 2.
+ Set<ContainerReplica> replicas = new HashSet<>();
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin1,
+ IN_SERVICE, QUASI_CLOSED, 10, 3);
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(ContainerID.valueOf(1),
origin1,
+ DECOMMISSIONED, QUASI_CLOSED, 10));
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin2,
+ IN_SERVICE, QUASI_CLOSED, 5, 2);
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin3,
+ IN_SERVICE, QUASI_CLOSED, 5, 2);
+
+ QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1, 3, 2);
assertFalse(replicaCount.isUnderReplicated());
assertFalse(replicaCount.isOverReplicated());
}
@Test
public void testNoOverReplicationWithOutOfServiceReplicasWithTwoOrigins() {
- Set<ContainerReplica> replicas =
ReplicationTestUtil.createReplicasWithOriginAndOpState(
- ContainerID.valueOf(1), QUASI_CLOSED,
- Pair.of(origin1, IN_SERVICE), Pair.of(origin1, IN_SERVICE),
Pair.of(origin1, DECOMMISSIONED),
- Pair.of(origin2, IN_SERVICE), Pair.of(origin2, IN_SERVICE));
-
- QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1);
+ // origin1 is best (BCSID=10) with 3 in-service copies at target plus 1
decommissioned.
+ // origin2 is other (BCSID=5) with 2 in-service copies at target 2.
+ Set<ContainerReplica> replicas = new HashSet<>();
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin1,
+ IN_SERVICE, QUASI_CLOSED, 10, 3);
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(ContainerID.valueOf(1),
origin1,
+ DECOMMISSIONED, QUASI_CLOSED, 10));
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin2,
+ IN_SERVICE, QUASI_CLOSED, 5, 2);
+
+ QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1, 3, 2);
assertFalse(replicaCount.isUnderReplicated());
assertFalse(replicaCount.isOverReplicated());
}
@@ -255,7 +303,7 @@ public void
testNoOverReplicationWithOutOfServiceReplicasWithOneOrigin() {
Pair.of(origin1, IN_SERVICE), Pair.of(origin1, IN_SERVICE),
Pair.of(origin1, IN_SERVICE),
Pair.of(origin1, DECOMMISSIONED));
- QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1);
+ QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1, 3, 2);
assertFalse(replicaCount.isUnderReplicated());
assertFalse(replicaCount.isOverReplicated());
}
@@ -266,7 +314,7 @@ public void
testUnderReplicationWithMaintenanceWithOneOrigin() {
ContainerID.valueOf(1), QUASI_CLOSED,
Pair.of(origin1, IN_SERVICE), Pair.of(origin1, IN_SERVICE),
Pair.of(origin1, ENTERING_MAINTENANCE));
- QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1);
+ QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1, 3, 2);
assertFalse(replicaCount.isUnderReplicated());
assertFalse(replicaCount.isOverReplicated());
@@ -274,7 +322,7 @@ public void
testUnderReplicationWithMaintenanceWithOneOrigin() {
ContainerID.valueOf(1), QUASI_CLOSED,
Pair.of(origin1, IN_SERVICE), Pair.of(origin1, ENTERING_MAINTENANCE),
Pair.of(origin1, ENTERING_MAINTENANCE));
- replicaCount = new QuasiClosedStuckReplicaCount(replicas, 2);
+ replicaCount = new QuasiClosedStuckReplicaCount(replicas, 2, 3, 2);
assertTrue(replicaCount.isUnderReplicated());
assertFalse(replicaCount.isOverReplicated());
validateMisReplicatedOrigins(replicaCount.getUnderReplicatedReplicas(), 1,
3, 1, origin1);
@@ -282,21 +330,30 @@ public void
testUnderReplicationWithMaintenanceWithOneOrigin() {
@Test
public void testUnderReplicationWithMaintenanceWithTwoOrigins() {
- Set<ContainerReplica> replicas =
ReplicationTestUtil.createReplicasWithOriginAndOpState(
- ContainerID.valueOf(1), QUASI_CLOSED,
- Pair.of(origin1, IN_SERVICE), Pair.of(origin1, ENTERING_MAINTENANCE),
- Pair.of(origin2, IN_SERVICE), Pair.of(origin2, IN_SERVICE));
-
- QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1);
+ // origin1 is best (BCSID=10) with 1 in-service and 1 entering-maintenance
copy.
+ // Because origin1 has at least 1 in-service replica while under
maintenance, it is not under-replicated.
+ // origin2 is other (BCSID=5) with 2 in-service copies at target 2.
+ Set<ContainerReplica> replicas = new HashSet<>();
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(ContainerID.valueOf(1),
origin1,
+ IN_SERVICE, QUASI_CLOSED, 10));
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(ContainerID.valueOf(1),
origin1,
+ ENTERING_MAINTENANCE, QUASI_CLOSED, 10));
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin2,
+ IN_SERVICE, QUASI_CLOSED, 5, 2);
+
+ QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1, 3, 2);
assertFalse(replicaCount.isUnderReplicated());
assertFalse(replicaCount.isOverReplicated());
- replicas = ReplicationTestUtil.createReplicasWithOriginAndOpState(
- ContainerID.valueOf(1), QUASI_CLOSED,
- Pair.of(origin1, ENTERING_MAINTENANCE), Pair.of(origin1,
ENTERING_MAINTENANCE),
- Pair.of(origin2, IN_SERVICE), Pair.of(origin2, IN_SERVICE));
+ // When all of origin1's replicas are entering-maintenance it has no
in-service copies,
+ // so it is under-replicated by 1 (the maintenance path requires at least
1 online copy).
+ replicas = new HashSet<>();
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin1,
+ ENTERING_MAINTENANCE, QUASI_CLOSED, 10, 2);
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin2,
+ IN_SERVICE, QUASI_CLOSED, 5, 2);
- replicaCount = new QuasiClosedStuckReplicaCount(replicas, 1);
+ replicaCount = new QuasiClosedStuckReplicaCount(replicas, 1, 3, 2);
assertTrue(replicaCount.isUnderReplicated());
assertFalse(replicaCount.isOverReplicated());
validateMisReplicatedOrigins(replicaCount.getUnderReplicatedReplicas(), 1,
2, 1, origin1);
@@ -304,12 +361,18 @@ public void
testUnderReplicationWithMaintenanceWithTwoOrigins() {
@Test
public void testNoOverReplicationWithExcessMaintenanceReplicasTwoOrigins() {
- Set<ContainerReplica> replicas =
ReplicationTestUtil.createReplicasWithOriginAndOpState(
- ContainerID.valueOf(1), QUASI_CLOSED,
- Pair.of(origin1, IN_SERVICE), Pair.of(origin1, IN_SERVICE),
Pair.of(origin1, IN_MAINTENANCE),
- Pair.of(origin2, IN_SERVICE), Pair.of(origin2, IN_SERVICE));
-
- QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1);
+ // origin1 is best (BCSID=10) with 2 in-service copies and 1
in-maintenance copy.
+ // The maintenance replica is excluded from the over-replication check.
+ // origin2 is other (BCSID=5) with 2 in-service copies at target 2.
+ Set<ContainerReplica> replicas = new HashSet<>();
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin1,
+ IN_SERVICE, QUASI_CLOSED, 10, 2);
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(ContainerID.valueOf(1),
origin1,
+ IN_MAINTENANCE, QUASI_CLOSED, 10));
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin2,
+ IN_SERVICE, QUASI_CLOSED, 5, 2);
+
+ QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1, 3, 2);
assertFalse(replicaCount.isUnderReplicated());
assertFalse(replicaCount.isOverReplicated());
}
@@ -321,11 +384,50 @@ public void
testNoOverReplicationWithExcessMaintenanceReplicasOneOrigin() {
Pair.of(origin1, IN_SERVICE), Pair.of(origin1, IN_SERVICE),
Pair.of(origin1, IN_SERVICE),
Pair.of(origin1, IN_MAINTENANCE));
- QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1);
+ QuasiClosedStuckReplicaCount replicaCount = new
QuasiClosedStuckReplicaCount(replicas, 1, 3, 2);
assertFalse(replicaCount.isUnderReplicated());
assertFalse(replicaCount.isOverReplicated());
}
+ @Test
+ public void testShiftInBestOriginOnNewHigherBcsid() {
+ // Initial state: origin1 is best (BCSID=10, target=3) with 3 copies;
+ // origin2 is other (BCSID=5, target=2) with 2 copies. Both are at target.
+ Set<ContainerReplica> replicas = new HashSet<>();
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin1,
+ IN_SERVICE, QUASI_CLOSED, 10, 3);
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(replicas,
ContainerID.valueOf(1), origin2,
+ IN_SERVICE, QUASI_CLOSED, 5, 2);
+
+ QuasiClosedStuckReplicaCount initialCount = new
QuasiClosedStuckReplicaCount(replicas, 1, 3, 2);
+ assertFalse(initialCount.isUnderReplicated());
+ assertFalse(initialCount.isOverReplicated());
+
+ // A new replica arrives from origin3 with BCSID=20, higher than the
previous best of 10.
+ // origin3 is now the best origin (BCSID=20, target=3) but has only 1
copy: under-replicated by 2.
+ // origin1 is now an other origin (BCSID=10, target=2) but still has 3
copies: over-replicated by 1.
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(ContainerID.valueOf(1),
origin3,
+ IN_SERVICE, QUASI_CLOSED, 20));
+
+ QuasiClosedStuckReplicaCount updatedCount = new
QuasiClosedStuckReplicaCount(replicas, 1, 3, 2);
+
+ // The new best origin (origin3, BCSID=20) is under-replicated and must
receive more copies.
+ assertTrue(updatedCount.isUnderReplicated());
+ List<QuasiClosedStuckReplicaCount.MisReplicatedOrigin> underRep =
updatedCount.getUnderReplicatedReplicas();
+ assertEquals(1, underRep.size());
+ assertEquals(2, underRep.get(0).getReplicaDelta());
+ assertTrue(underRep.get(0).getSources().stream()
+ .allMatch(r -> r.getOriginDatanodeId().equals(origin3)));
+
+ // The old best origin (origin1, BCSID=10) is now over-replicated and one
copy must be deleted.
+ assertTrue(updatedCount.isOverReplicated());
+ List<QuasiClosedStuckReplicaCount.MisReplicatedOrigin> overRep =
updatedCount.getOverReplicatedOrigins();
+ assertEquals(1, overRep.size());
+ assertEquals(1, overRep.get(0).getReplicaDelta());
+ assertTrue(overRep.get(0).getSources().stream()
+ .allMatch(r -> r.getOriginDatanodeId().equals(origin1)));
+ }
+
private void validateMisReplicatedOrigins(
List<QuasiClosedStuckReplicaCount.MisReplicatedOrigin>
misReplicatedOrigins,
int expectedUnderRepOrigins, int expectedSources, int expectedDelta,
DatanodeID expectedOrigin) {
diff --git
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/TestQuasiClosedStuckUnderReplicationHandler.java
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/TestQuasiClosedStuckUnderReplicationHandler.java
index ff7853f8c8d..0ae73131856 100644
---
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/TestQuasiClosedStuckUnderReplicationHandler.java
+++
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/TestQuasiClosedStuckUnderReplicationHandler.java
@@ -17,7 +17,9 @@
package org.apache.hadoop.hdds.scm.container.replication;
+import static
org.apache.hadoop.hdds.protocol.proto.HddsProtos.NodeOperationalState.IN_SERVICE;
import static
org.apache.hadoop.hdds.protocol.proto.HddsProtos.ReplicationFactor.THREE;
+import static
org.apache.hadoop.hdds.protocol.proto.StorageContainerDatanodeProtocolProtos.ContainerReplicaProto.State.QUASI_CLOSED;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
@@ -39,7 +41,6 @@
import org.apache.hadoop.hdds.protocol.DatanodeID;
import org.apache.hadoop.hdds.protocol.MockDatanodeDetails;
import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
-import
org.apache.hadoop.hdds.protocol.proto.StorageContainerDatanodeProtocolProtos;
import org.apache.hadoop.hdds.scm.PlacementPolicy;
import org.apache.hadoop.hdds.scm.container.ContainerInfo;
import org.apache.hadoop.hdds.scm.container.ContainerReplica;
@@ -115,10 +116,7 @@ void setup(@TempDir File testDir) throws
NodeNotFoundException,
public void testReturnsZeroIfNotUnderReplicated() throws IOException {
final DatanodeID origin = DatanodeID.randomID();
Set<ContainerReplica> replicas =
ReplicationTestUtil.createReplicasWithOriginAndOpState(container.containerID(),
-
StorageContainerDatanodeProtocolProtos.ContainerReplicaProto.State.QUASI_CLOSED,
- Pair.of(origin, HddsProtos.NodeOperationalState.IN_SERVICE),
- Pair.of(origin, HddsProtos.NodeOperationalState.IN_SERVICE),
- Pair.of(origin, HddsProtos.NodeOperationalState.IN_SERVICE));
+ QUASI_CLOSED, Pair.of(origin, IN_SERVICE), Pair.of(origin,
IN_SERVICE), Pair.of(origin, IN_SERVICE));
int count = handler.processAndSendCommands(replicas,
Collections.emptyList(), getUnderReplicatedHealthResult(), 1);
assertEquals(0, count);
@@ -128,9 +126,7 @@ public void testReturnsZeroIfNotUnderReplicated() throws
IOException {
public void testNoCommandsScheduledIfPendingOps() throws IOException {
final DatanodeID origin = DatanodeID.randomID();
Set<ContainerReplica> replicas =
ReplicationTestUtil.createReplicasWithOriginAndOpState(container.containerID(),
-
StorageContainerDatanodeProtocolProtos.ContainerReplicaProto.State.QUASI_CLOSED,
- Pair.of(origin, HddsProtos.NodeOperationalState.IN_SERVICE),
- Pair.of(origin, HddsProtos.NodeOperationalState.IN_SERVICE));
+ QUASI_CLOSED, Pair.of(origin, IN_SERVICE), Pair.of(origin,
IN_SERVICE));
List<ContainerReplicaOp> pendingOps = new ArrayList<>();
pendingOps.add(new ContainerReplicaOp(
ContainerReplicaOp.PendingOpType.ADD,
MockDatanodeDetails.randomDatanodeDetails(), 0, null, Long.MAX_VALUE, 0));
@@ -143,8 +139,7 @@ public void testNoCommandsScheduledIfPendingOps() throws
IOException {
public void testCommandScheduledForUnderReplicatedContainer() throws
IOException {
final DatanodeID origin = DatanodeID.randomID();
Set<ContainerReplica> replicas =
ReplicationTestUtil.createReplicasWithOriginAndOpState(container.containerID(),
-
StorageContainerDatanodeProtocolProtos.ContainerReplicaProto.State.QUASI_CLOSED,
- Pair.of(origin, HddsProtos.NodeOperationalState.IN_SERVICE));
+ QUASI_CLOSED, Pair.of(origin, IN_SERVICE));
int count = handler.processAndSendCommands(replicas,
Collections.emptyList(), getUnderReplicatedHealthResult(), 1);
assertEquals(2, count);
@@ -155,10 +150,13 @@ public void
testCommandScheduledForUnderReplicatedContainer() throws IOException
public void testOverloadedExceptionContinuesAndThrows() throws
NotLeaderException, CommandTargetOverloadedException {
final DatanodeID origin1 = DatanodeID.randomID();
final DatanodeID origin2 = DatanodeID.randomID();
- Set<ContainerReplica> replicas =
ReplicationTestUtil.createReplicasWithOriginAndOpState(container.containerID(),
-
StorageContainerDatanodeProtocolProtos.ContainerReplicaProto.State.QUASI_CLOSED,
- Pair.of(origin1, HddsProtos.NodeOperationalState.IN_SERVICE),
- Pair.of(origin2, HddsProtos.NodeOperationalState.IN_SERVICE));
+ Set<ContainerReplica> replicas = new HashSet<>();
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(container.containerID(),
+ origin1, IN_SERVICE, QUASI_CLOSED, 10));
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(container.containerID(),
+ origin1, IN_SERVICE, QUASI_CLOSED, 10));
+
replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(container.containerID(),
+ origin2, IN_SERVICE, QUASI_CLOSED, 5));
ReplicationTestUtil.mockRMSendThrottleReplicateCommand(replicationManager,
commandsSent, new AtomicBoolean(true));
@@ -172,9 +170,7 @@ public void testInsufficientNodesExceptionThrown() {
final DatanodeID origin1 = DatanodeID.randomID();
final DatanodeID origin2 = DatanodeID.randomID();
Set<ContainerReplica> replicas =
ReplicationTestUtil.createReplicasWithOriginAndOpState(container.containerID(),
-
StorageContainerDatanodeProtocolProtos.ContainerReplicaProto.State.QUASI_CLOSED,
- Pair.of(origin1, HddsProtos.NodeOperationalState.IN_SERVICE),
- Pair.of(origin2, HddsProtos.NodeOperationalState.IN_SERVICE));
+ QUASI_CLOSED, Pair.of(origin1, IN_SERVICE), Pair.of(origin2,
IN_SERVICE));
PlacementPolicy policy =
ReplicationTestUtil.getNoNodesTestPlacementPolicy(nodeManager, conf);
handler = new QuasiClosedStuckUnderReplicationHandler(policy, conf,
replicationManager);
@@ -188,8 +184,7 @@ public void testInsufficientNodesExceptionThrown() {
public void testPartialReplicationExceptionThrown() {
final DatanodeID origin1 = DatanodeID.randomID();
Set<ContainerReplica> replicas =
ReplicationTestUtil.createReplicasWithOriginAndOpState(container.containerID(),
-
StorageContainerDatanodeProtocolProtos.ContainerReplicaProto.State.QUASI_CLOSED,
- Pair.of(origin1, HddsProtos.NodeOperationalState.IN_SERVICE));
+ QUASI_CLOSED, Pair.of(origin1, IN_SERVICE));
PlacementPolicy policy =
ReplicationTestUtil.getInsufficientNodesTestPlacementPolicy(nodeManager, conf,
2);
handler = new QuasiClosedStuckUnderReplicationHandler(policy, conf,
replicationManager);
@@ -199,6 +194,34 @@ public void testPartialReplicationExceptionThrown() {
assertEquals(1, commandsSent.size());
}
+ @Test
+ public void testOriginCopies() throws IOException {
+ final DatanodeID origin1 = DatanodeID.randomID();
+ final DatanodeID origin2 = DatanodeID.randomID();
+
+ // Configure default copy counts: best origin gets 3 copies, other origins
get 2 copies.
+ ReplicationManager.ReplicationManagerConfiguration rmConf =
+ new
OzoneConfiguration().getObject(ReplicationManager.ReplicationManagerConfiguration.class);
+ rmConf.setQuasiClosedStuckBestOriginCopies(3);
+ rmConf.setQuasiClosedStuckOtherOriginCopies(2);
+ when(replicationManager.getConfig()).thenReturn(rmConf);
+
+ // origin1 is the best origin (BCSID=10, target=3): has 2 copies, needs 1
more.
+ // origin2 is an other origin (BCSID=5, target=2): has 2 copies, already
at target.
+ Set<ContainerReplica> replicas = new HashSet<>();
+ replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(
+ container.containerID(), origin1, IN_SERVICE, QUASI_CLOSED, 10));
+ replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(
+ container.containerID(), origin1, IN_SERVICE, QUASI_CLOSED, 10));
+ replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(
+ container.containerID(), origin2, IN_SERVICE, QUASI_CLOSED, 5));
+ replicas.add(ReplicationTestUtil.createReplicaWithOriginAndSeqId(
+ container.containerID(), origin2, IN_SERVICE, QUASI_CLOSED, 5));
+
+ int count = handler.processAndSendCommands(replicas,
Collections.emptyList(), getUnderReplicatedHealthResult(), 1);
+ assertEquals(1, count);
+ }
+
private ContainerHealthResult.UnderReplicatedHealthResult
getUnderReplicatedHealthResult() {
ContainerHealthResult.UnderReplicatedHealthResult
healthResult =
mock(ContainerHealthResult.UnderReplicatedHealthResult.class);
diff --git
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/health/TestQuasiClosedStuckReplicationCheck.java
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/health/TestQuasiClosedStuckReplicationCheck.java
index c11450a79c3..1d8738787c4 100644
---
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/health/TestQuasiClosedStuckReplicationCheck.java
+++
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/health/TestQuasiClosedStuckReplicationCheck.java
@@ -24,7 +24,6 @@
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.Mockito.mock;
import java.util.ArrayList;
import java.util.Collections;
@@ -33,6 +32,7 @@
import java.util.Set;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.hadoop.hdds.client.RatisReplicationConfig;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.protocol.DatanodeID;
import org.apache.hadoop.hdds.protocol.MockDatanodeDetails;
import
org.apache.hadoop.hdds.protocol.proto.StorageContainerDatanodeProtocolProtos.ContainerReplicaProto.State;
@@ -64,8 +64,8 @@ public class TestQuasiClosedStuckReplicationCheck {
@BeforeEach
public void setup() {
- rmConf = mock(ReplicationManager.ReplicationManagerConfiguration.class);
- handler = new QuasiClosedStuckReplicationCheck();
+ rmConf = new
OzoneConfiguration().getObject(ReplicationManager.ReplicationManagerConfiguration.class);
+ handler = new QuasiClosedStuckReplicationCheck(rmConf);
report = new ReplicationManagerReport(rmConf.getContainerSampleLimit());
report.resetContainerHealthState(); // Reset before each test
queue = new ReplicationQueue();
@@ -148,10 +148,14 @@ public void testCorrectlyReplicated() {
ContainerInfo containerInfo = ReplicationTestUtil.createContainerInfo(
RatisReplicationConfig.getInstance(THREE), 1, QUASI_CLOSED);
- Set<ContainerReplica> containerReplicas = ReplicationTestUtil
- .createReplicasWithOriginAndOpState(containerInfo.containerID(),
State.QUASI_CLOSED,
- Pair.of(origin1, IN_SERVICE), Pair.of(origin1, IN_SERVICE),
- Pair.of(origin2, IN_SERVICE), Pair.of(origin2, IN_SERVICE));
+ // origin1 is the best origin (seqId=10, target=3): has 3 copies, at
target.
+ // origin2 is an other origin (seqId=5, target=2): has 2 copies, at target.
+ Set<ContainerReplica> containerReplicas = new HashSet<>();
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(containerReplicas,
containerInfo.containerID(),
+ origin1, IN_SERVICE, State.QUASI_CLOSED, 10, 3);
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(containerReplicas,
containerInfo.containerID(),
+ origin2, IN_SERVICE, State.QUASI_CLOSED, 5, 2);
+
ContainerCheckRequest request = new ContainerCheckRequest.Builder()
.setPendingOps(Collections.emptyList())
.setReport(report)
@@ -246,10 +250,13 @@ public void testOverReplicatedIsQueued() {
ContainerInfo containerInfo = ReplicationTestUtil.createContainerInfo(
RatisReplicationConfig.getInstance(THREE), 1, QUASI_CLOSED);
- Set<ContainerReplica> containerReplicas = ReplicationTestUtil
- .createReplicasWithOriginAndOpState(containerInfo.containerID(),
State.QUASI_CLOSED,
- Pair.of(origin1, IN_SERVICE), Pair.of(origin1, IN_SERVICE),
Pair.of(origin1, IN_SERVICE),
- Pair.of(origin2, IN_SERVICE), Pair.of(origin2, IN_SERVICE));
+ // origin1 is the best origin (seqId=10, target=3): has 3 copies, at
target.
+ // origin2 is an other origin (seqId=5, target=2): has 3 copies,
over-replicated by 1.
+ Set<ContainerReplica> containerReplicas = new HashSet<>();
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(containerReplicas,
containerInfo.containerID(),
+ origin1, IN_SERVICE, State.QUASI_CLOSED, 10, 3);
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(containerReplicas,
containerInfo.containerID(),
+ origin2, IN_SERVICE, State.QUASI_CLOSED, 5, 3);
ContainerCheckRequest request = new ContainerCheckRequest.Builder()
.setPendingOps(Collections.emptyList())
@@ -273,10 +280,13 @@ public void
testOverReplicatedWithPendingDeleteIsNotQueued() {
ContainerInfo containerInfo = ReplicationTestUtil.createContainerInfo(
RatisReplicationConfig.getInstance(THREE), 1, QUASI_CLOSED);
- Set<ContainerReplica> containerReplicas = ReplicationTestUtil
- .createReplicasWithOriginAndOpState(containerInfo.containerID(),
State.QUASI_CLOSED,
- Pair.of(origin1, IN_SERVICE), Pair.of(origin1, IN_SERVICE),
- Pair.of(origin2, IN_SERVICE), Pair.of(origin2, IN_SERVICE),
Pair.of(origin2, IN_SERVICE));
+ // origin1 is the best origin (seqId=10, target=3): has 3 copies, at
target.
+ // origin2 is an other origin (seqId=5, target=2): has 3 copies,
over-replicated by 1.
+ Set<ContainerReplica> containerReplicas = new HashSet<>();
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(containerReplicas,
containerInfo.containerID(),
+ origin1, IN_SERVICE, State.QUASI_CLOSED, 10, 3);
+ ReplicationTestUtil.addReplicasWithOriginAndSeqId(containerReplicas,
containerInfo.containerID(),
+ origin2, IN_SERVICE, State.QUASI_CLOSED, 5, 3);
List<ContainerReplicaOp> pendingOps = new ArrayList<>();
pendingOps.add(new ContainerReplicaOp(
diff --git
a/hadoop-hdds/server-scm/src/test/resources/replicationManagerTests/quasi_closed.json
b/hadoop-hdds/server-scm/src/test/resources/replicationManagerTests/quasi_closed.json
index 6d229d652c8..2137b523754 100644
---
a/hadoop-hdds/server-scm/src/test/resources/replicationManagerTests/quasi_closed.json
+++
b/hadoop-hdds/server-scm/src/test/resources/replicationManagerTests/quasi_closed.json
@@ -14,11 +14,12 @@
{ "description": "Quasi-closed with 2 replicas", "containerState":
"QUASI_CLOSED", "replicationConfig": "RATIS:THREE", "sequenceId": 12,
"replicas": [
{ "state": "QUASI_CLOSED", "index": 0, "datanode": "d1", "sequenceId":
12, "isEmpty": false, "origin": "o1"},
- { "state": "QUASI_CLOSED", "index": 0, "datanode": "d2", "sequenceId":
12, "isEmpty": false, "origin": "o2"}
+ { "state": "QUASI_CLOSED", "index": 0, "datanode": "d2", "sequenceId":
10, "isEmpty": false, "origin": "o2"}
],
"expectation": { "quasiClosedStuckUnderReplicated": 1,
"underReplicatedQueue": 1, "overReplicated": 0, "overReplicatedQueue": 0,
"quasiClosedStuck": 1},
"checkCommands": [],
"commands": [
+ { "type": "replicateContainerCommand", "datanode": "d1" },
{ "type": "replicateContainerCommand", "datanode": "d1" },
{ "type": "replicateContainerCommand", "datanode": "d2" }
]
@@ -26,12 +27,13 @@
{ "description": "Quasi-closed with 3 replicas 2 origins", "containerState":
"QUASI_CLOSED", "replicationConfig": "RATIS:THREE", "sequenceId": 12,
"replicas": [
{ "state": "QUASI_CLOSED", "index": 0, "datanode": "d1", "sequenceId":
12, "isEmpty": false, "origin": "o1"},
- { "state": "QUASI_CLOSED", "index": 0, "datanode": "d2", "sequenceId":
12, "isEmpty": false, "origin": "o2"},
- { "state": "QUASI_CLOSED", "index": 0, "datanode": "d3", "sequenceId":
12, "isEmpty": false, "origin": "o2"}
+ { "state": "QUASI_CLOSED", "index": 0, "datanode": "d2", "sequenceId":
10, "isEmpty": false, "origin": "o2"},
+ { "state": "QUASI_CLOSED", "index": 0, "datanode": "d3", "sequenceId":
10, "isEmpty": false, "origin": "o2"}
],
"expectation": { "quasiClosedStuckUnderReplicated": 1,
"underReplicatedQueue": 1, "overReplicated": 0, "overReplicatedQueue": 0,
"quasiClosedStuck": 1, "unhealthy": 0 },
"checkCommands": [],
"commands": [
+ { "type": "replicateContainerCommand", "datanode": "d1" },
{ "type": "replicateContainerCommand", "datanode": "d1" }
]
},
@@ -95,12 +97,13 @@
{ "description": "Quasi-Closed with 2 replicas and unhealthy where unhealthy
is highest BCSID", "containerState": "QUASI_CLOSED", "replicationConfig":
"RATIS:THREE", "sequenceId": 11,
"replicas": [
{ "state": "QUASI_CLOSED", "index": 0, "datanode": "d1", "sequenceId":
10, "isEmpty": false, "origin": "o1"},
- { "state": "QUASI_CLOSED", "index": 0, "datanode": "d2", "sequenceId":
10, "isEmpty": false, "origin": "o2"},
+ { "state": "QUASI_CLOSED", "index": 0, "datanode": "d2", "sequenceId":
8, "isEmpty": false, "origin": "o2"},
{ "state": "UNHEALTHY", "index": 0, "datanode": "d3", "sequenceId":
11, "isEmpty": false, "origin": "o3"}
],
"expectation": { "quasiClosedStuckUnderReplicated": 1,
"underReplicatedQueue": 1, "overReplicated": 0, "overReplicatedQueue": 0,
"quasiClosedStuck": 1, "unhealthy": 0 },
"checkCommands": [],
"commands": [
+ { "type": "replicateContainerCommand", "datanode": "d1" },
{ "type": "replicateContainerCommand", "datanode": "d1" },
{ "type": "replicateContainerCommand", "datanode": "d2" },
{ "type": "replicateContainerCommand", "datanode": "d3" }
@@ -120,8 +123,9 @@
"replicas": [
{ "state": "QUASI_CLOSED", "index": 0, "datanode": "d1", "sequenceId":
10, "isEmpty": false, "origin": "o1"},
{ "state": "QUASI_CLOSED", "index": 0, "datanode": "d2", "sequenceId":
10, "isEmpty": false, "origin": "o1"},
- { "state": "QUASI_CLOSED", "index": 0, "datanode": "d3", "sequenceId":
10, "isEmpty": false, "origin": "o2"},
- { "state": "QUASI_CLOSED", "index": 0, "datanode": "d4", "sequenceId":
10, "isEmpty": false, "origin": "o2"}
+ { "state": "QUASI_CLOSED", "index": 0, "datanode": "d5", "sequenceId":
10, "isEmpty": false, "origin": "o1"},
+ { "state": "QUASI_CLOSED", "index": 0, "datanode": "d3", "sequenceId":
8, "isEmpty": false, "origin": "o2"},
+ { "state": "QUASI_CLOSED", "index": 0, "datanode": "d4", "sequenceId":
8, "isEmpty": false, "origin": "o2"}
],
"expectation": { "underReplicated": 0, "underReplicatedQueue": 0,
"overReplicated": 0, "overReplicatedQueue": 0, "quasiClosedStuck": 1,
"unhealthy": 0 },
"checkCommands": [],
@@ -131,8 +135,9 @@
"replicas": [
{ "state": "QUASI_CLOSED", "index": 0, "datanode": "d1", "sequenceId":
10, "isEmpty": false, "origin": "o1"},
{ "state": "QUASI_CLOSED", "index": 0, "datanode": "d2", "sequenceId":
10, "isEmpty": false, "origin": "o1"},
- { "state": "QUASI_CLOSED", "index": 0, "datanode": "d3", "sequenceId":
10, "isEmpty": false, "origin": "o2"},
- { "state": "QUASI_CLOSED", "index": 0, "datanode": "d4", "sequenceId":
10, "isEmpty": false, "origin": "o2"},
+ { "state": "QUASI_CLOSED", "index": 0, "datanode": "d7", "sequenceId":
10, "isEmpty": false, "origin": "o1"},
+ { "state": "QUASI_CLOSED", "index": 0, "datanode": "d3", "sequenceId":
8, "isEmpty": false, "origin": "o2"},
+ { "state": "QUASI_CLOSED", "index": 0, "datanode": "d4", "sequenceId":
8, "isEmpty": false, "origin": "o2"},
{ "state": "UNHEALTHY", "index": 0, "datanode": "d5", "sequenceId":
11, "isEmpty": false, "origin": "o3"},
{ "state": "UNHEALTHY", "index": 0, "datanode": "d6", "sequenceId":
11, "isEmpty": false, "origin": "o3"}
],
@@ -143,13 +148,14 @@
{ "description": "Quasi-Closed with 3 QC and one unhealthy",
"containerState": "QUASI_CLOSED", "replicationConfig": "RATIS:THREE",
"sequenceId": 11,
"replicas": [
{ "state": "QUASI_CLOSED", "index": 0, "datanode": "d1", "sequenceId":
10, "isEmpty": false, "origin": "o1"},
- { "state": "QUASI_CLOSED", "index": 0, "datanode": "d2", "sequenceId":
10, "isEmpty": false, "origin": "o2"},
- { "state": "QUASI_CLOSED", "index": 0, "datanode": "d3", "sequenceId":
10, "isEmpty": false, "origin": "o2"},
+ { "state": "QUASI_CLOSED", "index": 0, "datanode": "d2", "sequenceId":
8, "isEmpty": false, "origin": "o2"},
+ { "state": "QUASI_CLOSED", "index": 0, "datanode": "d3", "sequenceId":
8, "isEmpty": false, "origin": "o2"},
{ "state": "UNHEALTHY", "index": 0, "datanode": "d4", "sequenceId":
11, "isEmpty": false, "origin": "o3"}
],
"expectation": { "quasiClosedStuckUnderReplicated": 1,
"underReplicatedQueue": 1, "overReplicated": 0, "overReplicatedQueue": 0,
"quasiClosedStuck": 1, "unhealthy": 0 },
"checkCommands": [],
"commands": [
+ { "type": "replicateContainerCommand", "datanode": "d1" },
{ "type": "replicateContainerCommand", "datanode": "d1" },
{ "type": "replicateContainerCommand", "datanode": "d4" }
]
@@ -199,14 +205,13 @@
{ "state": "QUASI_CLOSED", "index": 0, "datanode": "d1", "sequenceId":
10, "isEmpty": false, "origin": "o1"},
{ "state": "QUASI_CLOSED", "index": 0, "datanode": "d2", "sequenceId":
10, "isEmpty": false, "origin": "o1"},
{ "state": "QUASI_CLOSED", "index": 0, "datanode": "d3", "sequenceId":
10, "isEmpty": false, "origin": "o1"},
- { "state": "QUASI_CLOSED", "index": 0, "datanode": "d4", "sequenceId":
10, "isEmpty": false, "origin": "o2"},
- { "state": "QUASI_CLOSED", "index": 0, "datanode": "d5", "sequenceId":
10, "isEmpty": false, "origin": "o2"},
- { "state": "QUASI_CLOSED", "index": 0, "datanode": "d6", "sequenceId":
10, "isEmpty": false, "origin": "o2"}
+ { "state": "QUASI_CLOSED", "index": 0, "datanode": "d4", "sequenceId":
8, "isEmpty": false, "origin": "o2"},
+ { "state": "QUASI_CLOSED", "index": 0, "datanode": "d5", "sequenceId":
8, "isEmpty": false, "origin": "o2"},
+ { "state": "QUASI_CLOSED", "index": 0, "datanode": "d6", "sequenceId":
8, "isEmpty": false, "origin": "o2"}
],
"expectation": { "underReplicated": 0, "underReplicatedQueue": 0,
"overReplicated": 0, "quasiClosedStuckOverReplicated": 1,
"overReplicatedQueue": 1, "quasiClosedStuck": 1, "unhealthy": 0 },
"checkCommands": [],
"commands": [
- { "type": "deleteContainerCommand", "datanode": "d1|d2|d3" },
{ "type": "deleteContainerCommand", "datanode": "d4|d5|d6" }
]
},
@@ -227,10 +232,11 @@
"replicas": [
{ "state": "QUASI_CLOSED", "index": 0, "datanode": "d1", "sequenceId":
10, "isEmpty": false, "origin": "o1"},
{ "state": "QUASI_CLOSED", "index": 0, "datanode": "d2", "sequenceId":
10, "isEmpty": false, "origin": "o1"},
+ { "state": "QUASI_CLOSED", "index": 0, "datanode": "d7", "sequenceId":
10, "isEmpty": false, "origin": "o1"},
{ "state": "QUASI_CLOSED", "index": 0, "datanode": "d3", "sequenceId":
10, "isEmpty": false, "origin": "o1", "operationalState": "DECOMMISSIONED" },
- { "state": "QUASI_CLOSED", "index": 0, "datanode": "d4", "sequenceId":
10, "isEmpty": false, "origin": "o2"},
- { "state": "QUASI_CLOSED", "index": 0, "datanode": "d5", "sequenceId":
10, "isEmpty": false, "origin": "o2"},
- { "state": "QUASI_CLOSED", "index": 0, "datanode": "d6", "sequenceId":
10, "isEmpty": false, "origin": "o2", "operationalState": "DECOMMISSIONED"}
+ { "state": "QUASI_CLOSED", "index": 0, "datanode": "d4", "sequenceId":
8, "isEmpty": false, "origin": "o2"},
+ { "state": "QUASI_CLOSED", "index": 0, "datanode": "d5", "sequenceId":
8, "isEmpty": false, "origin": "o2"},
+ { "state": "QUASI_CLOSED", "index": 0, "datanode": "d6", "sequenceId":
8, "isEmpty": false, "origin": "o2", "operationalState": "DECOMMISSIONED"}
],
"expectation": { "underReplicated": 0, "underReplicatedQueue": 0,
"overReplicated": 0, "overReplicatedQueue": 0, "quasiClosedStuck": 1,
"unhealthy": 0 },
"checkCommands": [],
@@ -241,15 +247,16 @@
{ "state": "QUASI_CLOSED", "index": 0, "datanode": "d1", "sequenceId":
10, "isEmpty": false, "origin": "o1"},
{ "state": "QUASI_CLOSED", "index": 0, "datanode": "d2", "sequenceId":
10, "isEmpty": false, "origin": "o1"},
{ "state": "QUASI_CLOSED", "index": 0, "datanode": "d3", "sequenceId":
10, "isEmpty": false, "origin": "o1"},
- { "state": "QUASI_CLOSED", "index": 0, "datanode": "d4", "sequenceId":
10, "isEmpty": false, "origin": "o1", "operationalState": "IN_MAINTENANCE" },
- { "state": "QUASI_CLOSED", "index": 0, "datanode": "d5", "sequenceId":
10, "isEmpty": false, "origin": "o2"},
- { "state": "QUASI_CLOSED", "index": 0, "datanode": "d6", "sequenceId":
10, "isEmpty": false, "origin": "o2"},
- { "state": "QUASI_CLOSED", "index": 0, "datanode": "d7", "sequenceId":
10, "isEmpty": false, "origin": "o2", "operationalState": "IN_MAINTENANCE"}
+ { "state": "QUASI_CLOSED", "index": 0, "datanode": "d4", "sequenceId":
10, "isEmpty": false, "origin": "o1"},
+ { "state": "QUASI_CLOSED", "index": 0, "datanode": "d8", "sequenceId":
10, "isEmpty": false, "origin": "o1", "operationalState": "IN_MAINTENANCE" },
+ { "state": "QUASI_CLOSED", "index": 0, "datanode": "d5", "sequenceId":
8, "isEmpty": false, "origin": "o2"},
+ { "state": "QUASI_CLOSED", "index": 0, "datanode": "d6", "sequenceId":
8, "isEmpty": false, "origin": "o2"},
+ { "state": "QUASI_CLOSED", "index": 0, "datanode": "d7", "sequenceId":
8, "isEmpty": false, "origin": "o2", "operationalState": "IN_MAINTENANCE"}
],
"expectation": { "underReplicated": 0, "underReplicatedQueue": 0,
"quasiClosedStuckOverReplicated": 1, "overReplicatedQueue": 1,
"quasiClosedStuck": 1, "unhealthy": 0 },
"checkCommands": [],
"commands": [
- { "type": "deleteContainerCommand", "datanode": "d1|d2|d3" }
+ { "type": "deleteContainerCommand", "datanode": "d1|d2|d3|d4" }
]
},
{ "description": "Quasi-Closed stuck two origins over replicated with
stale", "containerState": "QUASI_CLOSED", "replicationConfig": "RATIS:THREE",
"sequenceId": 10,
@@ -257,9 +264,9 @@
{ "state": "QUASI_CLOSED", "index": 0, "datanode": "d1", "sequenceId":
10, "isEmpty": false, "origin": "o1"},
{ "state": "QUASI_CLOSED", "index": 0, "datanode": "d2", "sequenceId":
10, "isEmpty": false, "origin": "o1"},
{ "state": "QUASI_CLOSED", "index": 0, "datanode": "d3", "sequenceId":
10, "isEmpty": false, "origin": "o1", "healthState": "STALE" },
- { "state": "QUASI_CLOSED", "index": 0, "datanode": "d4", "sequenceId":
10, "isEmpty": false, "origin": "o2"},
- { "state": "QUASI_CLOSED", "index": 0, "datanode": "d5", "sequenceId":
10, "isEmpty": false, "origin": "o2"},
- { "state": "QUASI_CLOSED", "index": 0, "datanode": "d6", "sequenceId":
10, "isEmpty": false, "origin": "o2", "healthState": "STALE" }
+ { "state": "QUASI_CLOSED", "index": 0, "datanode": "d4", "sequenceId":
8, "isEmpty": false, "origin": "o2"},
+ { "state": "QUASI_CLOSED", "index": 0, "datanode": "d5", "sequenceId":
8, "isEmpty": false, "origin": "o2"},
+ { "state": "QUASI_CLOSED", "index": 0, "datanode": "d6", "sequenceId":
8, "isEmpty": false, "origin": "o2", "healthState": "STALE" }
],
"expectation": { "underReplicated": 0, "underReplicatedQueue": 0,
"quasiClosedStuckOverReplicated": 1, "overReplicatedQueue": 1,
"quasiClosedStuck": 1, "unhealthy": 0 },
"checkCommands": [],
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]