This is an automated email from the ASF dual-hosted git repository.

adoroszlai 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 88ad6d1ec1 HDDS-8867. Datanode re-registration memory leak (#4916)
88ad6d1ec1 is described below

commit 88ad6d1ec19816c7123f1d70afe2fa1c3fdf80a6
Author: Doroszlai, Attila <[email protected]>
AuthorDate: Sat Jun 17 15:21:14 2023 +0200

    HDDS-8867. Datanode re-registration memory leak (#4916)
---
 .../hadoop/hdds/scm/node/SCMNodeManager.java       | 48 ++++++++-----------
 .../hadoop/hdds/scm/node/TestSCMNodeManager.java   | 56 +++++++++-------------
 2 files changed, 41 insertions(+), 63 deletions(-)

diff --git 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/node/SCMNodeManager.java
 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/node/SCMNodeManager.java
index 721e6ef680..21b639ca8a 100644
--- 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/node/SCMNodeManager.java
+++ 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/node/SCMNodeManager.java
@@ -20,7 +20,6 @@ package org.apache.hadoop.hdds.scm.node;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import org.apache.hadoop.hdds.DFSConfigKeysLegacy;
 import org.apache.hadoop.hdds.conf.OzoneConfiguration;
 import org.apache.hadoop.hdds.protocol.DatanodeDetails;
@@ -401,7 +400,7 @@ public class SCMNodeManager implements NodeManager {
         // Check that datanode in nodeStateManager has topology parent set
         DatanodeDetails dn = nodeStateManager.getNode(datanodeDetails);
         Preconditions.checkState(dn.getParent() != null);
-        addEntryToDnsToUuidMap(dnsName, datanodeDetails.getUuidString());
+        addToDnsToUuidMap(dnsName, datanodeDetails.getUuidString());
         // Updating Node Report, as registration is successful
         processNodeReport(datanodeDetails, nodeReport);
         LOG.info("Registered Data node : {}", datanodeDetails.toDebugString());
@@ -435,7 +434,7 @@ public class SCMNodeManager implements NodeManager {
           } else {
             oldDnsName = datanodeInfo.getIpAddress();
           }
-          updateEntryFromDnsToUuidMap(oldDnsName,
+          updateDnsToUuidMap(oldDnsName,
                   dnsName,
                   datanodeDetails.getUuidString());
 
@@ -464,38 +463,29 @@ public class SCMNodeManager implements NodeManager {
    * running on that host. As each address can have many DNs running on it,
    * this is a one to many mapping.
    *
-   * @param dnsName String representing the hostname or IP of the node
-   * @param uuid    String representing the UUID of the registered node.
+   * @param addr the hostname or IP of the node
+   * @param uuid the UUID of the registered node.
    */
-  @SuppressFBWarnings(value = 
"AT_OPERATION_SEQUENCE_ON_CONCURRENT_ABSTRACTION")
-  private synchronized void addEntryToDnsToUuidMap(
-          String dnsName, String uuid) {
-    Set<String> dnList = dnsToUuidMap.get(dnsName);
-    if (dnList == null) {
-      dnList = ConcurrentHashMap.newKeySet();
-      dnsToUuidMap.put(dnsName, dnList);
-    }
-    dnList.add(uuid);
+  private synchronized void addToDnsToUuidMap(String addr, String uuid) {
+    dnsToUuidMap.computeIfAbsent(addr, k -> ConcurrentHashMap.newKeySet())
+        .add(uuid);
   }
 
-  private synchronized void removeEntryFromDnsToUuidMap(String dnsName) {
-    if (!dnsToUuidMap.containsKey(dnsName)) {
-      return;
-    }
-    Set<String> dnSet = dnsToUuidMap.get(dnsName);
-    if (dnSet.contains(dnsName)) {
-      dnSet.remove(dnsName);
-    }
-    if (dnSet.isEmpty()) {
-      dnsToUuidMap.remove(dnsName);
+  private synchronized void removeFromDnsToUuidMap(String addr, String uuid) {
+    Set<String> dnSet = dnsToUuidMap.get(addr);
+    if (dnSet != null && dnSet.remove(uuid) && dnSet.isEmpty()) {
+      dnsToUuidMap.remove(addr);
     }
   }
 
-  private synchronized void updateEntryFromDnsToUuidMap(String oldDnsName,
-                                                        String newDnsName,
-                                                        String uuid) {
-    removeEntryFromDnsToUuidMap(oldDnsName);
-    addEntryToDnsToUuidMap(newDnsName, uuid);
+  private synchronized void updateDnsToUuidMap(
+      String oldDnsName, String newDnsName, String uuid) {
+    Preconditions.checkNotNull(oldDnsName, "old address == null");
+    Preconditions.checkNotNull(newDnsName, "new address == null");
+    if (!oldDnsName.equals(newDnsName)) {
+      removeFromDnsToUuidMap(oldDnsName, uuid);
+      addToDnsToUuidMap(newDnsName, uuid);
+    }
   }
 
   /**
diff --git 
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/node/TestSCMNodeManager.java
 
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/node/TestSCMNodeManager.java
index 6a789cb92a..2f677629a0 100644
--- 
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/node/TestSCMNodeManager.java
+++ 
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/node/TestSCMNodeManager.java
@@ -90,6 +90,7 @@ import java.util.Map;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
+import static java.util.Collections.emptyList;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.SECONDS;
 import static 
org.apache.hadoop.fs.CommonConfigurationKeysPublic.NET_TOPOLOGY_NODE_SWITCH_MAPPING_IMPL_KEY;
@@ -121,6 +122,8 @@ import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
 import org.slf4j.Logger;
@@ -977,7 +980,7 @@ public class TestSCMNodeManager {
     }
     for (int i = 0; i < 5; i++) {
       nodeManager.addDatanodeCommand(node1.getUuid(),
-          new DeleteBlocksCommand(Collections.emptyList()));
+          new DeleteBlocksCommand(emptyList()));
     }
 
     Assertions.assertEquals(3, nodeManager.getTotalDatanodeCommandCount(
@@ -1063,7 +1066,7 @@ public class TestSCMNodeManager {
     SCMCommand<?> createPipelineCommand =
         new CreatePipelineCommand(PipelineID.randomId(),
             HddsProtos.ReplicationType.RATIS,
-            HddsProtos.ReplicationFactor.THREE, Collections.emptyList());
+            HddsProtos.ReplicationFactor.THREE, emptyList());
 
     nodeManager.onMessage(
         new CommandForDatanode<>(datanode1, closeContainerCommand), null);
@@ -1525,7 +1528,7 @@ public class TestSCMNodeManager {
         StorageReportProto report = HddsTestUtils
             .createStorageReport(dnId, storagePath, capacity, used, free, 
null);
         nodeManager.register(dn, HddsTestUtils.createNodeReport(
-            Arrays.asList(report), Collections.emptyList()), null);
+            Arrays.asList(report), emptyList()), null);
         nodeManager.processHeartbeat(dn, layoutInfo);
       }
       //TODO: wait for EventQueue to be processed
@@ -1578,7 +1581,7 @@ public class TestSCMNodeManager {
         failed = !failed;
       }
       nodeManager.register(dn, HddsTestUtils.createNodeReport(reports,
-          Collections.emptyList()), null);
+          emptyList()), null);
       LayoutVersionManager versionManager =
           nodeManager.getLayoutVersionManager();
       LayoutVersionProto layoutInfo = toLayoutVersionProto(
@@ -1635,7 +1638,7 @@ public class TestSCMNodeManager {
             .createStorageReport(dnId, storagePath, capacity, scmUsed,
                 remaining, null);
         NodeReportProto nodeReportProto = HddsTestUtils.createNodeReport(
-            Arrays.asList(report), Collections.emptyList());
+            Arrays.asList(report), emptyList());
         nodeReportHandler.onMessage(
             new NodeReportFromDatanode(datanodeDetails, nodeReportProto),
             publisher);
@@ -1767,7 +1770,7 @@ public class TestSCMNodeManager {
 
       nodemanager
           .register(datanodeDetails, HddsTestUtils.createNodeReport(
-              Arrays.asList(report), Collections.emptyList()),
+              Arrays.asList(report), emptyList()),
                   HddsTestUtils.getRandomPipelineReports());
       eq.fireEvent(DATANODE_COMMAND,
           new CommandForDatanode<>(datanodeDetails.getUuid(),
@@ -1813,25 +1816,6 @@ public class TestSCMNodeManager {
     testScmRegisterNodeWithNetworkTopology(true);
   }
 
-  /**
-   * Test getNodesByAddress when using IPs.
-   *
-   */
-  @Test
-  public void testgetNodesByAddressWithIpAddress()
-      throws IOException, InterruptedException, AuthenticationException {
-    testGetNodesByAddress(false);
-  }
-
-  /**
-   * Test getNodesByAddress when using hostnames.
-   */
-  @Test
-  public void testgetNodesByAddressWithHostname()
-      throws IOException, InterruptedException, AuthenticationException {
-    testGetNodesByAddress(true);
-  }
-
   /**
    * Test add node into a 4-layer network topology during node register.
    */
@@ -1948,7 +1932,7 @@ public class TestSCMNodeManager {
               remaining, null);
 
       nodeManager.register(datanodeDetails, HddsTestUtils.createNodeReport(
-          Arrays.asList(report), Collections.emptyList()),
+          Arrays.asList(report), emptyList()),
           HddsTestUtils.getRandomPipelineReports());
 
       LayoutVersionManager versionManager =
@@ -1958,7 +1942,7 @@ public class TestSCMNodeManager {
           versionManager.getSoftwareLayoutVersion());
       nodeManager.register(datanodeDetails,
           HddsTestUtils.createNodeReport(Arrays.asList(report),
-              Collections.emptyList()),
+              emptyList()),
           HddsTestUtils.getRandomPipelineReports(), layoutInfo);
       nodeManager.processHeartbeat(datanodeDetails, layoutInfo);
       if (i == 5) {
@@ -1992,20 +1976,21 @@ public class TestSCMNodeManager {
   /**
    * Test add node into a 4-layer network topology during node register.
    */
-  private void testGetNodesByAddress(boolean useHostname)
-      throws IOException, InterruptedException, AuthenticationException {
+  @ParameterizedTest
+  @ValueSource(booleans = {true, false})
+  void testGetNodesByAddress(boolean useHostname)
+      throws IOException, AuthenticationException {
     OzoneConfiguration conf = getConf();
     conf.setTimeDuration(OZONE_SCM_HEARTBEAT_PROCESS_INTERVAL, 1000,
         MILLISECONDS);
+    conf.setBoolean(DFSConfigKeysLegacy.DFS_DATANODE_USE_DN_HOSTNAME,
+        useHostname);
 
     // create a set of hosts - note two hosts on "host1"
     String[] hostNames = {"host1", "host1", "host2", "host3", "host4"};
     String[] ipAddress =
         {"1.2.3.4", "1.2.3.4", "2.3.4.5", "3.4.5.6", "4.5.6.7"};
 
-    if (useHostname) {
-      conf.set(DFSConfigKeysLegacy.DFS_DATANODE_USE_DN_HOSTNAME, "true");
-    }
     final int nodeCount = hostNames.length;
     try (SCMNodeManager nodeManager = createNodeManager(conf)) {
       for (int i = 0; i < nodeCount; i++) {
@@ -2070,7 +2055,7 @@ public class TestSCMNodeManager {
       assertEquals(hostName, returnedNode.getHostName());
       assertTrue(returnedNode.getNetworkLocation()
               .startsWith("/rack1/ng"));
-      assertTrue(returnedNode.getParent() != null);
+      assertNotNull(returnedNode.getParent());
 
       // test updating ip address and host name
       String updatedIpAddress = "2.3.4.5";
@@ -2091,7 +2076,10 @@ public class TestSCMNodeManager {
       assertEquals(updatedHostName, returnedUpdatedNode.getHostName());
       assertTrue(returnedUpdatedNode.getNetworkLocation()
               .startsWith("/rack1/ng"));
-      assertTrue(returnedUpdatedNode.getParent() != null);
+      assertNotNull(returnedUpdatedNode.getParent());
+
+      assertEquals(emptyList(), nodeManager.getNodesByAddress(hostName));
+      assertEquals(emptyList(), nodeManager.getNodesByAddress(ipAddress));
     }
   }
 }


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

Reply via email to