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

hulee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/helix.git


The following commit(s) were added to refs/heads/master by this push:
     new 6de54ab  Fix ZkClient leakage by correctly setting 
usesExternalZkClient flag (#1562)
6de54ab is described below

commit 6de54ab5c35637accebe0dd819e946f79cabcceb
Author: Hunter Lee <[email protected]>
AuthorDate: Wed Jan 6 11:36:43 2021 -0800

    Fix ZkClient leakage by correctly setting usesExternalZkClient flag (#1562)
    
    ZkBaseDataAccessor and Helix API that uses it using its Builder were having 
zkClient thread leak issues because the usesExternalZkClient flag was not being 
set properly. Also, the family of Verifiers were having a similar issue. This 
change solves this by making sure the private/protected constructors used by 
the Builders of these classes set the flag correctly to false so that in their 
respective close() functions, the underlying zkClient (created by the Builder) 
would get closed.
---
 .../helix/manager/zk/ZkBaseDataAccessor.java       | 13 ++++++------
 .../BestPossibleExternalViewVerifier.java          | 14 +++++++++----
 .../ClusterVerifiers/ClusterLiveNodesVerifier.java |  8 ++++++--
 .../StrictMatchExternalViewVerifier.java           | 23 +++++++++++++++++-----
 .../ClusterVerifiers/ZkHelixClusterVerifier.java   | 11 ++++++-----
 5 files changed, 47 insertions(+), 22 deletions(-)

diff --git 
a/helix-core/src/main/java/org/apache/helix/manager/zk/ZkBaseDataAccessor.java 
b/helix-core/src/main/java/org/apache/helix/manager/zk/ZkBaseDataAccessor.java
index 4e6a7b0..2721640 100644
--- 
a/helix-core/src/main/java/org/apache/helix/manager/zk/ZkBaseDataAccessor.java
+++ 
b/helix-core/src/main/java/org/apache/helix/manager/zk/ZkBaseDataAccessor.java
@@ -134,14 +134,13 @@ public class ZkBaseDataAccessor<T> implements 
BaseDataAccessor<T> {
    */
   @Deprecated
   public ZkBaseDataAccessor(RealmAwareZkClient zkClient) {
-    if (zkClient == null) {
-      throw new NullPointerException("zkclient is null");
-    }
-    _zkClient = zkClient;
-    _usesExternalZkClient = true;
+    this(zkClient, true);
   }
 
   private ZkBaseDataAccessor(RealmAwareZkClient zkClient, boolean 
usesExternalZkClient) {
+    if (zkClient == null) {
+      throw new IllegalArgumentException("zkclient is null");
+    }
     _zkClient = zkClient;
     _usesExternalZkClient = usesExternalZkClient;
   }
@@ -1317,9 +1316,11 @@ public class ZkBaseDataAccessor<T> implements 
BaseDataAccessor<T> {
      */
     public ZkBaseDataAccessor<T> build() {
       validate();
+      // Initialize ZkBaseDataAccessor with usesExternalZkClient = false so 
that
+      // ZkBaseDataAccessor::close() would close ZkClient as well to prevent 
thread leakage
       return new ZkBaseDataAccessor<>(
           createZkClient(_realmMode, _realmAwareZkConnectionConfig, 
_realmAwareZkClientConfig,
-              _zkAddress));
+              _zkAddress), false);
     }
   }
 
diff --git 
a/helix-core/src/main/java/org/apache/helix/tools/ClusterVerifiers/BestPossibleExternalViewVerifier.java
 
b/helix-core/src/main/java/org/apache/helix/tools/ClusterVerifiers/BestPossibleExternalViewVerifier.java
index c984d38..f916583 100644
--- 
a/helix-core/src/main/java/org/apache/helix/tools/ClusterVerifiers/BestPossibleExternalViewVerifier.java
+++ 
b/helix-core/src/main/java/org/apache/helix/tools/ClusterVerifiers/BestPossibleExternalViewVerifier.java
@@ -111,7 +111,9 @@ public class BestPossibleExternalViewVerifier extends 
ZkHelixClusterVerifier {
   public BestPossibleExternalViewVerifier(RealmAwareZkClient zkClient, String 
clusterName,
       Set<String> resources, Map<String, Map<String, String>> errStates,
       Set<String> expectLiveInstances, int waitTillVerify) {
-    super(zkClient, clusterName, waitTillVerify);
+    // usesExternalZkClient = true because ZkClient is given by the caller
+    // at close(), we will not close this ZkClient because it might be being 
used elsewhere
+    super(zkClient, clusterName, true, waitTillVerify);
     _errStates = errStates;
     _resources = resources;
     _expectLiveInstances = expectLiveInstances;
@@ -120,8 +122,10 @@ public class BestPossibleExternalViewVerifier extends 
ZkHelixClusterVerifier {
 
   private BestPossibleExternalViewVerifier(RealmAwareZkClient zkClient, String 
clusterName,
       Map<String, Map<String, String>> errStates, Set<String> resources,
-      Set<String> expectLiveInstances, int waitPeriodTillVerify) {
-    super(zkClient, clusterName, waitPeriodTillVerify);
+      Set<String> expectLiveInstances, int waitPeriodTillVerify, boolean 
usesExternalZkClient) {
+    // Initialize BestPossibleExternalViewVerifier with usesExternalZkClient = 
false so that
+    // BestPossibleExternalViewVerifier::close() would close ZkClient to 
prevent thread leakage
+    super(zkClient, clusterName, usesExternalZkClient, waitPeriodTillVerify);
     // Deep copy data from Builder
     _errStates = new HashMap<>();
     if (errStates != null) {
@@ -139,6 +143,7 @@ public class BestPossibleExternalViewVerifier extends 
ZkHelixClusterVerifier {
     private Set<String> _resources;
     private Set<String> _expectLiveInstances;
     private RealmAwareZkClient _zkClient;
+    private boolean _usesExternalZkClient = false; // false by default
 
     public Builder(String clusterName) {
       _clusterName = clusterName;
@@ -164,7 +169,7 @@ public class BestPossibleExternalViewVerifier extends 
ZkHelixClusterVerifier {
       return new BestPossibleExternalViewVerifier(
           createZkClient(RealmAwareZkClient.RealmMode.SINGLE_REALM, 
_realmAwareZkConnectionConfig,
               _realmAwareZkClientConfig, _zkAddress), _clusterName, 
_errStates, _resources,
-          _expectLiveInstances, _waitPeriodTillVerify);
+          _expectLiveInstances, _waitPeriodTillVerify, _usesExternalZkClient);
     }
 
     public String getClusterName() {
@@ -204,6 +209,7 @@ public class BestPossibleExternalViewVerifier extends 
ZkHelixClusterVerifier {
 
     public Builder setZkClient(RealmAwareZkClient zkClient) {
       _zkClient = zkClient;
+      _usesExternalZkClient = true; // Set the flag since external ZkClient is 
used
       return this;
     }
   }
diff --git 
a/helix-core/src/main/java/org/apache/helix/tools/ClusterVerifiers/ClusterLiveNodesVerifier.java
 
b/helix-core/src/main/java/org/apache/helix/tools/ClusterVerifiers/ClusterLiveNodesVerifier.java
index 8e28f3e..789b509 100644
--- 
a/helix-core/src/main/java/org/apache/helix/tools/ClusterVerifiers/ClusterLiveNodesVerifier.java
+++ 
b/helix-core/src/main/java/org/apache/helix/tools/ClusterVerifiers/ClusterLiveNodesVerifier.java
@@ -34,13 +34,17 @@ public class ClusterLiveNodesVerifier extends 
ZkHelixClusterVerifier {
   @Deprecated
   public ClusterLiveNodesVerifier(RealmAwareZkClient zkclient, String 
clusterName,
       List<String> expectLiveNodes) {
-    super(zkclient, clusterName, 0);
+    // usesExternalZkClient = true because ZkClient is given by the caller
+    // at close(), we will not close this ZkClient because it might be being 
used elsewhere
+    super(zkclient, clusterName, true, 0);
     _expectLiveNodes = new HashSet<>(expectLiveNodes);
   }
 
   private ClusterLiveNodesVerifier(RealmAwareZkClient zkClient, String 
clusterName,
       Set<String> expectLiveNodes, int waitPeriodTillVerify) {
-    super(zkClient, clusterName, waitPeriodTillVerify);
+    // Initialize ClusterLiveNodesVerifier with usesExternalZkClient = false 
so that
+    // ClusterLiveNodesVerifier::close() would close ZkClient to prevent 
thread leakage
+    super(zkClient, clusterName, false, waitPeriodTillVerify);
     _expectLiveNodes = expectLiveNodes == null ? new HashSet<>() : new 
HashSet<>(expectLiveNodes);
   }
 
diff --git 
a/helix-core/src/main/java/org/apache/helix/tools/ClusterVerifiers/StrictMatchExternalViewVerifier.java
 
b/helix-core/src/main/java/org/apache/helix/tools/ClusterVerifiers/StrictMatchExternalViewVerifier.java
index bb991bd..ca47c16 100644
--- 
a/helix-core/src/main/java/org/apache/helix/tools/ClusterVerifiers/StrictMatchExternalViewVerifier.java
+++ 
b/helix-core/src/main/java/org/apache/helix/tools/ClusterVerifiers/StrictMatchExternalViewVerifier.java
@@ -66,7 +66,13 @@ public class StrictMatchExternalViewVerifier extends 
ZkHelixClusterVerifier {
   @Deprecated
   public StrictMatchExternalViewVerifier(RealmAwareZkClient zkClient, String 
clusterName,
       Set<String> resources, Set<String> expectLiveInstances) {
-    this(zkClient, clusterName, resources, expectLiveInstances, false, 0);
+    // usesExternalZkClient = true because ZkClient is given by the caller
+    // at close(), we will not close this ZkClient because it might be being 
used elsewhere
+    super(zkClient, clusterName, true, 0);
+    _resources = resources == null ? new HashSet<>() : new 
HashSet<>(resources);
+    _expectLiveInstances =
+        expectLiveInstances == null ? new HashSet<>() : new 
HashSet<>(expectLiveInstances);
+    _isDeactivatedNodeAware = false;
   }
 
   @Deprecated
@@ -79,8 +85,11 @@ public class StrictMatchExternalViewVerifier extends 
ZkHelixClusterVerifier {
   }
 
   private StrictMatchExternalViewVerifier(RealmAwareZkClient zkClient, String 
clusterName,
-      Set<String> resources, Set<String> expectLiveInstances, boolean 
isDeactivatedNodeAware, int waitPeriodTillVerify) {
-    super(zkClient, clusterName, waitPeriodTillVerify);
+      Set<String> resources, Set<String> expectLiveInstances, boolean 
isDeactivatedNodeAware,
+      int waitPeriodTillVerify, boolean usesExternalZkClient) {
+    // Initialize StrictMatchExternalViewVerifier with usesExternalZkClient = 
false so that
+    // StrictMatchExternalViewVerifier::close() would close ZkClient to 
prevent thread leakage
+    super(zkClient, clusterName, usesExternalZkClient, 0);
     _resources = resources == null ? new HashSet<>() : new 
HashSet<>(resources);
     _expectLiveInstances =
         expectLiveInstances == null ? new HashSet<>() : new 
HashSet<>(expectLiveInstances);
@@ -94,6 +103,7 @@ public class StrictMatchExternalViewVerifier extends 
ZkHelixClusterVerifier {
     private RealmAwareZkClient _zkClient;
     // For backward compatibility, set the default isDeactivatedNodeAware to 
be false.
     private boolean _isDeactivatedNodeAware = false;
+    private boolean _usesExternalZkClient = false; // false by default
 
     public StrictMatchExternalViewVerifier build() {
       if (_clusterName == null) {
@@ -102,7 +112,8 @@ public class StrictMatchExternalViewVerifier extends 
ZkHelixClusterVerifier {
 
       if (_zkClient != null) {
         return new StrictMatchExternalViewVerifier(_zkClient, _clusterName, 
_resources,
-            _expectLiveInstances, _isDeactivatedNodeAware, 
_waitPeriodTillVerify);
+            _expectLiveInstances, _isDeactivatedNodeAware, 
_waitPeriodTillVerify,
+            _usesExternalZkClient);
       }
 
       if (_realmAwareZkConnectionConfig == null || _realmAwareZkClientConfig 
== null) {
@@ -115,7 +126,8 @@ public class StrictMatchExternalViewVerifier extends 
ZkHelixClusterVerifier {
       return new StrictMatchExternalViewVerifier(
           createZkClient(RealmAwareZkClient.RealmMode.SINGLE_REALM, 
_realmAwareZkConnectionConfig,
               _realmAwareZkClientConfig, _zkAddress), _clusterName, _resources,
-          _expectLiveInstances, _isDeactivatedNodeAware, 
_waitPeriodTillVerify);
+          _expectLiveInstances, _isDeactivatedNodeAware, _waitPeriodTillVerify,
+          _usesExternalZkClient);
     }
 
     public Builder(String clusterName) {
@@ -151,6 +163,7 @@ public class StrictMatchExternalViewVerifier extends 
ZkHelixClusterVerifier {
     @Deprecated
     public Builder setZkClient(RealmAwareZkClient zkClient) {
       _zkClient = zkClient;
+      _usesExternalZkClient = true; // Set the flag since external ZkClient is 
used
       return this;
     }
 
diff --git 
a/helix-core/src/main/java/org/apache/helix/tools/ClusterVerifiers/ZkHelixClusterVerifier.java
 
b/helix-core/src/main/java/org/apache/helix/tools/ClusterVerifiers/ZkHelixClusterVerifier.java
index 9050592..623a91e 100644
--- 
a/helix-core/src/main/java/org/apache/helix/tools/ClusterVerifiers/ZkHelixClusterVerifier.java
+++ 
b/helix-core/src/main/java/org/apache/helix/tools/ClusterVerifiers/ZkHelixClusterVerifier.java
@@ -94,12 +94,13 @@ public abstract class ZkHelixClusterVerifier
     }
   }
 
-  protected ZkHelixClusterVerifier(RealmAwareZkClient zkClient, String 
clusterName, int waitPeriodTillVerify) {
+  protected ZkHelixClusterVerifier(RealmAwareZkClient zkClient, String 
clusterName,
+      boolean usesExternalZkClient, int waitPeriodTillVerify) {
     if (zkClient == null || clusterName == null) {
       throw new IllegalArgumentException("requires zkClient|clusterName");
     }
     _zkClient = zkClient;
-    _usesExternalZkClient = true;
+    _usesExternalZkClient = usesExternalZkClient;
     _clusterName = clusterName;
     _accessor = new ZKHelixDataAccessor(clusterName, new 
ZkBaseDataAccessor<>(_zkClient));
     _keyBuilder = _accessor.keyBuilder();
@@ -113,6 +114,9 @@ public abstract class ZkHelixClusterVerifier
     }
     // If the multi ZK config is enabled, use DedicatedZkClient on multi-realm 
mode
     if (Boolean.getBoolean(SystemPropertyKeys.MULTI_ZK_ENABLED) || zkAddr == 
null) {
+      LOG.info(
+          "ZkHelixClusterVerifier: zkAddr is null or multi-zk mode is enabled 
in System Properties."
+              + " Instantiating in multi-zk mode!");
       try {
         RealmAwareZkClient.RealmAwareZkConnectionConfig.Builder 
connectionConfigBuilder =
             new RealmAwareZkClient.RealmAwareZkConnectionConfig.Builder();
@@ -127,9 +131,6 @@ public abstract class ZkHelixClusterVerifier
         throw new HelixException("ZkHelixClusterVerifier: failed to create 
ZkClient!", e);
       }
     } else {
-      if (zkAddr == null) {
-        throw new IllegalArgumentException("ZkHelixClusterVerifier: ZkAddress 
is null or empty!");
-      }
       _zkClient = DedicatedZkClientFactory.getInstance()
           .buildZkClient(new HelixZkClient.ZkConnectionConfig(zkAddr));
     }

Reply via email to