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


##########
hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/ReplicationManager.java:
##########
@@ -537,6 +581,12 @@ public void sendThrottledReplicationCommand(ContainerInfo 
containerInfo,
   public void sendThrottledReconstructionCommand(ContainerInfo containerInfo,
       ReconstructECContainersCommand command)
       throws CommandTargetOverloadedException, NotLeaderException {
+    if (isReconstructionLimitReached()) {
+      metrics.incrECReconstructionCmdsDeferredTotal();
+      throw new CommandTargetOverloadedException(
+          "Global reconstruction limit (" + getReconstructionInFlightLimit()
+              + ") reached for container " + containerInfo.getContainerID());
+    }

Review Comment:
   The global reconstruction limit check is not atomic with the subsequent 
increment of inflightReconstructionCount (the increment happens later in 
adjustPendingOpsAndMetrics). With multiple threads calling 
sendThrottledReconstructionCommand concurrently, it’s possible for several 
calls to pass the check and then all increment, exceeding the configured limit.



##########
hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/TestReplicationManager.java:
##########
@@ -1801,4 +1802,186 @@ private void mockReplicationCommandCounts(
         });
   }
 
+  @Test
+  public void testReconstructionGlobalLimitDisabledByDefault() throws 
IOException {
+    assertEquals(0, rmConf.getReconstructionGlobalLimit());
+    ReplicationManager rm = createReplicationManager();
+    assertEquals(0, rm.getReconstructionInFlightLimit());
+    assertFalse(rm.isReconstructionLimitReached());
+  }
+
+  @Test
+  public void testInflightReconstructionLimit() throws IOException, 
NodeNotFoundException {
+    rmConf.setReconstructionGlobalLimit(2);
+    ReplicationManager rm = createReplicationManager();
+    assertEquals(2, rm.getReconstructionInFlightLimit());
+    assertEquals(0, rm.getInflightReconstructionCount());
+    assertFalse(rm.isReconstructionLimitReached());
+
+    mockReplicationCommandCounts(dn -> 0, dn -> 0);
+
+    ContainerInfo container = ReplicationTestUtil.createContainerInfo(
+        repConfig, 1, HddsProtos.LifeCycleState.CLOSED, 10, 20);
+    
+    // Send one reconstruction command with 2 fragments
+    ReconstructECContainersCommand cmd1 = new ReconstructECContainersCommand(
+        1L, Collections.emptyList(),
+        ImmutableList.of(MockDatanodeDetails.randomDatanodeDetails(),
+            MockDatanodeDetails.randomDatanodeDetails()),
+        ECUnderReplicationHandler.integers2ByteString(ImmutableList.of(1, 2)), 
(ECReplicationConfig) repConfig);
+
+    rm.sendThrottledReconstructionCommand(container, cmd1);
+    assertEquals(1, rm.getInflightReconstructionCount());
+    assertFalse(rm.isReconstructionLimitReached());
+
+    // Send another reconstruction command with 1 fragment
+    ReconstructECContainersCommand cmd2 = new ReconstructECContainersCommand(
+        2L, Collections.emptyList(),
+        ImmutableList.of(MockDatanodeDetails.randomDatanodeDetails()),
+        ECUnderReplicationHandler.integers2ByteString(ImmutableList.of(3)), 
(ECReplicationConfig) repConfig);    
+    rm.sendThrottledReconstructionCommand(container, cmd2);

Review Comment:
   Remove trailing whitespace at the end of this line (and consider wrapping 
the arguments for readability / style consistency).



##########
hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/TestReplicationManager.java:
##########
@@ -1801,4 +1802,186 @@ private void mockReplicationCommandCounts(
         });
   }
 
+  @Test
+  public void testReconstructionGlobalLimitDisabledByDefault() throws 
IOException {
+    assertEquals(0, rmConf.getReconstructionGlobalLimit());
+    ReplicationManager rm = createReplicationManager();
+    assertEquals(0, rm.getReconstructionInFlightLimit());
+    assertFalse(rm.isReconstructionLimitReached());
+  }
+
+  @Test
+  public void testInflightReconstructionLimit() throws IOException, 
NodeNotFoundException {
+    rmConf.setReconstructionGlobalLimit(2);
+    ReplicationManager rm = createReplicationManager();
+    assertEquals(2, rm.getReconstructionInFlightLimit());
+    assertEquals(0, rm.getInflightReconstructionCount());
+    assertFalse(rm.isReconstructionLimitReached());
+
+    mockReplicationCommandCounts(dn -> 0, dn -> 0);
+
+    ContainerInfo container = ReplicationTestUtil.createContainerInfo(
+        repConfig, 1, HddsProtos.LifeCycleState.CLOSED, 10, 20);
+    
+    // Send one reconstruction command with 2 fragments
+    ReconstructECContainersCommand cmd1 = new ReconstructECContainersCommand(
+        1L, Collections.emptyList(),
+        ImmutableList.of(MockDatanodeDetails.randomDatanodeDetails(),
+            MockDatanodeDetails.randomDatanodeDetails()),
+        ECUnderReplicationHandler.integers2ByteString(ImmutableList.of(1, 2)), 
(ECReplicationConfig) repConfig);
+
+    rm.sendThrottledReconstructionCommand(container, cmd1);
+    assertEquals(1, rm.getInflightReconstructionCount());
+    assertFalse(rm.isReconstructionLimitReached());
+
+    // Send another reconstruction command with 1 fragment
+    ReconstructECContainersCommand cmd2 = new ReconstructECContainersCommand(
+        2L, Collections.emptyList(),
+        ImmutableList.of(MockDatanodeDetails.randomDatanodeDetails()),
+        ECUnderReplicationHandler.integers2ByteString(ImmutableList.of(3)), 
(ECReplicationConfig) repConfig);    
+    rm.sendThrottledReconstructionCommand(container, cmd2);
+    assertEquals(2, rm.getInflightReconstructionCount());
+    assertTrue(rm.isReconstructionLimitReached());
+
+    // Complete one fragment of cmd1
+    ContainerReplicaOp op1 = new ContainerReplicaOp(
+        ContainerReplicaOp.PendingOpType.ADD, 
+        cmd1.getTargetDatanodes().get(0), 1, cmd1, Long.MAX_VALUE, 0);
+    rm.opCompleted(op1, container.containerID(), false);
+    // Still 2 because cmd1 is not fully finished
+    assertEquals(2, rm.getInflightReconstructionCount());
+
+    // Complete second fragment of cmd1
+    ContainerReplicaOp op2 = new ContainerReplicaOp(
+        ContainerReplicaOp.PendingOpType.ADD, 
+        cmd1.getTargetDatanodes().get(1), 2, cmd1, Long.MAX_VALUE, 0);
+    rm.opCompleted(op2, container.containerID(), false);
+    // Now 1
+    assertEquals(1, rm.getInflightReconstructionCount());
+    assertFalse(rm.isReconstructionLimitReached());
+
+    // Complete cmd2
+    ContainerReplicaOp op3 = new ContainerReplicaOp(
+        ContainerReplicaOp.PendingOpType.ADD, 
+        cmd2.getTargetDatanodes().get(0), 3, cmd2, Long.MAX_VALUE, 0);
+    rm.opCompleted(op3, container.containerID(), false);

Review Comment:
   These lines include trailing whitespace after commas (eg after "ADD,") which 
can break checkstyle and should be removed.



##########
hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/TestReplicationManager.java:
##########
@@ -1801,4 +1802,186 @@ private void mockReplicationCommandCounts(
         });
   }
 
+  @Test
+  public void testReconstructionGlobalLimitDisabledByDefault() throws 
IOException {
+    assertEquals(0, rmConf.getReconstructionGlobalLimit());
+    ReplicationManager rm = createReplicationManager();
+    assertEquals(0, rm.getReconstructionInFlightLimit());
+    assertFalse(rm.isReconstructionLimitReached());
+  }
+
+  @Test
+  public void testInflightReconstructionLimit() throws IOException, 
NodeNotFoundException {
+    rmConf.setReconstructionGlobalLimit(2);
+    ReplicationManager rm = createReplicationManager();
+    assertEquals(2, rm.getReconstructionInFlightLimit());
+    assertEquals(0, rm.getInflightReconstructionCount());
+    assertFalse(rm.isReconstructionLimitReached());
+
+    mockReplicationCommandCounts(dn -> 0, dn -> 0);
+
+    ContainerInfo container = ReplicationTestUtil.createContainerInfo(
+        repConfig, 1, HddsProtos.LifeCycleState.CLOSED, 10, 20);
+    
+    // Send one reconstruction command with 2 fragments

Review Comment:
   There is trailing whitespace on the blank line after the container creation, 
which can fail checkstyle and creates noisy diffs.



##########
hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/TestReplicationManager.java:
##########
@@ -1801,4 +1802,186 @@ private void mockReplicationCommandCounts(
         });
   }
 
+  @Test
+  public void testReconstructionGlobalLimitDisabledByDefault() throws 
IOException {
+    assertEquals(0, rmConf.getReconstructionGlobalLimit());
+    ReplicationManager rm = createReplicationManager();
+    assertEquals(0, rm.getReconstructionInFlightLimit());
+    assertFalse(rm.isReconstructionLimitReached());
+  }
+
+  @Test
+  public void testInflightReconstructionLimit() throws IOException, 
NodeNotFoundException {
+    rmConf.setReconstructionGlobalLimit(2);
+    ReplicationManager rm = createReplicationManager();
+    assertEquals(2, rm.getReconstructionInFlightLimit());
+    assertEquals(0, rm.getInflightReconstructionCount());
+    assertFalse(rm.isReconstructionLimitReached());
+
+    mockReplicationCommandCounts(dn -> 0, dn -> 0);
+
+    ContainerInfo container = ReplicationTestUtil.createContainerInfo(
+        repConfig, 1, HddsProtos.LifeCycleState.CLOSED, 10, 20);
+    
+    // Send one reconstruction command with 2 fragments
+    ReconstructECContainersCommand cmd1 = new ReconstructECContainersCommand(
+        1L, Collections.emptyList(),
+        ImmutableList.of(MockDatanodeDetails.randomDatanodeDetails(),
+            MockDatanodeDetails.randomDatanodeDetails()),
+        ECUnderReplicationHandler.integers2ByteString(ImmutableList.of(1, 2)), 
(ECReplicationConfig) repConfig);
+
+    rm.sendThrottledReconstructionCommand(container, cmd1);
+    assertEquals(1, rm.getInflightReconstructionCount());
+    assertFalse(rm.isReconstructionLimitReached());
+
+    // Send another reconstruction command with 1 fragment
+    ReconstructECContainersCommand cmd2 = new ReconstructECContainersCommand(
+        2L, Collections.emptyList(),
+        ImmutableList.of(MockDatanodeDetails.randomDatanodeDetails()),
+        ECUnderReplicationHandler.integers2ByteString(ImmutableList.of(3)), 
(ECReplicationConfig) repConfig);    
+    rm.sendThrottledReconstructionCommand(container, cmd2);
+    assertEquals(2, rm.getInflightReconstructionCount());
+    assertTrue(rm.isReconstructionLimitReached());
+
+    // Complete one fragment of cmd1
+    ContainerReplicaOp op1 = new ContainerReplicaOp(
+        ContainerReplicaOp.PendingOpType.ADD, 
+        cmd1.getTargetDatanodes().get(0), 1, cmd1, Long.MAX_VALUE, 0);
+    rm.opCompleted(op1, container.containerID(), false);

Review Comment:
   These lines include trailing whitespace after commas (eg after "ADD,") which 
can break checkstyle and should be removed.



##########
hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/TestReplicationManager.java:
##########
@@ -1801,4 +1802,186 @@ private void mockReplicationCommandCounts(
         });
   }
 
+  @Test
+  public void testReconstructionGlobalLimitDisabledByDefault() throws 
IOException {
+    assertEquals(0, rmConf.getReconstructionGlobalLimit());
+    ReplicationManager rm = createReplicationManager();
+    assertEquals(0, rm.getReconstructionInFlightLimit());
+    assertFalse(rm.isReconstructionLimitReached());
+  }
+
+  @Test
+  public void testInflightReconstructionLimit() throws IOException, 
NodeNotFoundException {
+    rmConf.setReconstructionGlobalLimit(2);
+    ReplicationManager rm = createReplicationManager();
+    assertEquals(2, rm.getReconstructionInFlightLimit());
+    assertEquals(0, rm.getInflightReconstructionCount());
+    assertFalse(rm.isReconstructionLimitReached());
+
+    mockReplicationCommandCounts(dn -> 0, dn -> 0);
+
+    ContainerInfo container = ReplicationTestUtil.createContainerInfo(
+        repConfig, 1, HddsProtos.LifeCycleState.CLOSED, 10, 20);
+    
+    // Send one reconstruction command with 2 fragments
+    ReconstructECContainersCommand cmd1 = new ReconstructECContainersCommand(
+        1L, Collections.emptyList(),
+        ImmutableList.of(MockDatanodeDetails.randomDatanodeDetails(),
+            MockDatanodeDetails.randomDatanodeDetails()),
+        ECUnderReplicationHandler.integers2ByteString(ImmutableList.of(1, 2)), 
(ECReplicationConfig) repConfig);
+
+    rm.sendThrottledReconstructionCommand(container, cmd1);
+    assertEquals(1, rm.getInflightReconstructionCount());
+    assertFalse(rm.isReconstructionLimitReached());
+
+    // Send another reconstruction command with 1 fragment
+    ReconstructECContainersCommand cmd2 = new ReconstructECContainersCommand(
+        2L, Collections.emptyList(),
+        ImmutableList.of(MockDatanodeDetails.randomDatanodeDetails()),
+        ECUnderReplicationHandler.integers2ByteString(ImmutableList.of(3)), 
(ECReplicationConfig) repConfig);    
+    rm.sendThrottledReconstructionCommand(container, cmd2);
+    assertEquals(2, rm.getInflightReconstructionCount());
+    assertTrue(rm.isReconstructionLimitReached());
+
+    // Complete one fragment of cmd1
+    ContainerReplicaOp op1 = new ContainerReplicaOp(
+        ContainerReplicaOp.PendingOpType.ADD, 
+        cmd1.getTargetDatanodes().get(0), 1, cmd1, Long.MAX_VALUE, 0);
+    rm.opCompleted(op1, container.containerID(), false);
+    // Still 2 because cmd1 is not fully finished
+    assertEquals(2, rm.getInflightReconstructionCount());
+
+    // Complete second fragment of cmd1
+    ContainerReplicaOp op2 = new ContainerReplicaOp(
+        ContainerReplicaOp.PendingOpType.ADD, 
+        cmd1.getTargetDatanodes().get(1), 2, cmd1, Long.MAX_VALUE, 0);
+    rm.opCompleted(op2, container.containerID(), false);

Review Comment:
   These lines include trailing whitespace after commas (eg after "ADD,") which 
can break checkstyle and should be removed.



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

To unsubscribe, e-mail: [email protected]

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


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

Reply via email to