helix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From hu...@apache.org
Subject [helix] 05/14: Util methods for checking if instance healthy
Date Wed, 22 May 2019 23:41:30 GMT
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

commit b43681634820ea5990851efae941e1123c5b4c54
Author: Yi Wang <ywang4@linkedin.com>
AuthorDate: Tue Mar 12 16:59:25 2019 -0700

    Util methods for checking if instance healthy
    
    RB=1585486
    G=helix-reviewers
    A=jxue
    
    Signed-off-by: Hunter Lee <hulee@linkedin.com>
---
 .gitignore                                         |  3 +-
 .../main/java/org/apache/helix/PropertyKey.java    |  2 +-
 .../apache/helix/util/InstanceValidationUtil.java  | 87 ++++++++++++++++++++--
 .../helix/rest/common/ZKReadAccessorWrapper.java   | 50 +++++++++++++
 4 files changed, 133 insertions(+), 9 deletions(-)

diff --git a/.gitignore b/.gitignore
index 27c2cdf..5cd0404 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,5 +11,6 @@ target/
 .settings/
 out/
 .DS_Store
-#this directory will be part of release process 
+#this directory will be part of release process
 helix-dev-release/
+.shelf/
diff --git a/helix-core/src/main/java/org/apache/helix/PropertyKey.java b/helix-core/src/main/java/org/apache/helix/PropertyKey.java
index 2ddc8bb..03d369b 100644
--- a/helix-core/src/main/java/org/apache/helix/PropertyKey.java
+++ b/helix-core/src/main/java/org/apache/helix/PropertyKey.java
@@ -22,8 +22,8 @@ package org.apache.helix;
 import static org.apache.helix.PropertyType.*;
 
 import java.util.Arrays;
-
 import java.util.Objects;
+
 import org.apache.helix.model.ClusterConfig;
 import org.apache.helix.model.ClusterConstraints;
 import org.apache.helix.model.ControllerHistory;
diff --git a/helix-core/src/main/java/org/apache/helix/util/InstanceValidationUtil.java b/helix-core/src/main/java/org/apache/helix/util/InstanceValidationUtil.java
index 23aa89b..b701864 100644
--- a/helix-core/src/main/java/org/apache/helix/util/InstanceValidationUtil.java
+++ b/helix-core/src/main/java/org/apache/helix/util/InstanceValidationUtil.java
@@ -25,21 +25,25 @@ import java.util.Map;
 import org.apache.helix.AccessOption;
 import org.apache.helix.ConfigAccessor;
 import org.apache.helix.HelixDataAccessor;
+import org.apache.helix.HelixDefinedState;
+import org.apache.helix.HelixException;
 import org.apache.helix.PropertyKey;
 import org.apache.helix.model.ClusterConfig;
 import org.apache.helix.model.CurrentState;
 import org.apache.helix.model.InstanceConfig;
 import org.apache.helix.model.LiveInstance;
-
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Utility class for validating Helix properties
  * Warning: each method validates one single property of instance individually and independently.
  * One validation wouldn't depend on the results of other validations
- * TODO: integrate on-demand cache if the performance is the bottleneck
- * TODO: manually tested the function, need to add detailed integration test
+ * TODO: add unit tests
  */
 public class InstanceValidationUtil {
+  private static final Logger _logger = LoggerFactory.getLogger(InstanceValidationUtil.class);
+
   private InstanceValidationUtil() {
   }
 
@@ -53,6 +57,7 @@ public class InstanceValidationUtil {
    */
   public static boolean isEnabled(HelixDataAccessor dataAccessor, ConfigAccessor configAccessor,
       String clusterId, String instanceName) {
+    // TODO use static builder instance to reduce GC
     PropertyKey propertyKey = new PropertyKey.Builder(clusterId).instanceConfig(instanceName);
     InstanceConfig instanceConfig = dataAccessor.getProperty(propertyKey);
     ClusterConfig clusterConfig = configAccessor.getClusterConfig(clusterId);
@@ -95,24 +100,92 @@ public class InstanceValidationUtil {
    */
   public static boolean hasResourceAssigned(HelixDataAccessor dataAccessor, String clusterId,
       String instanceName) {
-    PropertyKey liveInstanceKey = new PropertyKey.Builder(clusterId).liveInstance(instanceName);
+    PropertyKey.Builder propertyKeyBuilder = new PropertyKey.Builder(clusterId);
+    PropertyKey liveInstanceKey = propertyKeyBuilder.liveInstance(instanceName);
     LiveInstance liveInstance = dataAccessor.getProperty(liveInstanceKey);
     if (liveInstance != null) {
       String sessionId = liveInstance.getSessionId();
 
       PropertyKey currentStatesKey =
-          new PropertyKey.Builder(clusterId).currentStates(instanceName, sessionId);
+          propertyKeyBuilder.currentStates(instanceName, sessionId);
       List<String> resourceNames = dataAccessor.getChildNames(currentStatesKey);
       for (String resourceName : resourceNames) {
         PropertyKey key =
-            dataAccessor.keyBuilder().currentState(instanceName, sessionId, resourceName);
+            propertyKeyBuilder.currentState(instanceName, sessionId, resourceName);
+        CurrentState currentState = dataAccessor.getProperty(key);
+        if (currentState != null && currentState.getPartitionStateMap().size() >
0) {
+          return true;
+        }
+      }
+    }
+
+    _logger.warn(String.format("The instance %s is not active", instanceName));
+    return false;
+  }
+
+  /**
+   * Method to check if the instance has any disabled partition assigned
+   * @param dataAccessor
+   * @param clusterId
+   * @param instanceName
+   * @return
+   */
+  public static boolean hasDisabledPartitions(HelixDataAccessor dataAccessor, String clusterId,
+      String instanceName) {
+    PropertyKey propertyKey = new PropertyKey.Builder(clusterId).instanceConfig(instanceName);
+    InstanceConfig instanceConfig = dataAccessor.getProperty(propertyKey);
+    if (instanceConfig != null) {
+      return !instanceConfig.getDisabledPartitionsMap().isEmpty();
+    }
+
+    throw new HelixException("Fail to get instance config for " + instanceName);
+  }
+
+  /**
+   * Method to check if the instance has valid configuration
+   * @param dataAccessor
+   * @param clusterId
+   * @param instanceName
+   * @return
+   */
+  public static boolean hasValidConfig(HelixDataAccessor dataAccessor, String clusterId,
+      String instanceName) {
+    PropertyKey propertyKey = new PropertyKey.Builder(clusterId).instanceConfig(instanceName);
+    InstanceConfig instanceConfig = dataAccessor.getProperty(propertyKey);
+    return instanceConfig != null && instanceConfig.isValid();
+  }
+
+  /**
+   * Method to check if the instance has error partitions
+   * @param dataAccessor
+   * @param clusterId
+   * @param instanceName
+   * @return
+   */
+  public static boolean hasErrorPartitions(HelixDataAccessor dataAccessor, String clusterId,
+      String instanceName) {
+    PropertyKey.Builder propertyKeyBuilder = new PropertyKey.Builder(clusterId);
+    PropertyKey liveInstanceKey = propertyKeyBuilder.liveInstance(instanceName);
+    LiveInstance liveInstance = dataAccessor.getProperty(liveInstanceKey);
+    if (liveInstance != null) {
+      String sessionId = liveInstance.getSessionId();
+
+      PropertyKey currentStatesKey =
+          propertyKeyBuilder.currentStates(instanceName, sessionId);
+      List<String> resourceNames = dataAccessor.getChildNames(currentStatesKey);
+      for (String resourceName : resourceNames) {
+        PropertyKey key =
+            propertyKeyBuilder.currentState(instanceName, sessionId, resourceName);
+
         CurrentState currentState = dataAccessor.getProperty(key);
-        if (currentState.getPartitionStateMap().size() > 0) {
+        if (currentState != null
+            && currentState.getPartitionStateMap().containsValue(HelixDefinedState.ERROR.name()))
{
           return true;
         }
       }
     }
 
+    _logger.warn(String.format("The instance %s is not active", instanceName));
     return false;
   }
 }
diff --git a/helix-rest/src/main/java/org/apache/helix/rest/common/ZKReadAccessorWrapper.java
b/helix-rest/src/main/java/org/apache/helix/rest/common/ZKReadAccessorWrapper.java
new file mode 100644
index 0000000..f8a4f4f
--- /dev/null
+++ b/helix-rest/src/main/java/org/apache/helix/rest/common/ZKReadAccessorWrapper.java
@@ -0,0 +1,50 @@
+package org.apache.helix.rest.common;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.helix.BaseDataAccessor;
+import org.apache.helix.HelixProperty;
+import org.apache.helix.InstanceType;
+import org.apache.helix.PropertyKey;
+import org.apache.helix.ZNRecord;
+import org.apache.helix.manager.zk.ZKHelixDataAccessor;
+
+
+/**
+ * A read-only wrapper of {@link ZKHelixDataAccessor} with transient cache
+ * The caches is of the value from get methods and short lived for the lifecycle of one rest
request
+ * TODO: add more cached read method based on needs
+ */
+public class ZKReadAccessorWrapper extends ZKHelixDataAccessor {
+  private final Map<PropertyKey, HelixProperty> _propertyCache = new HashMap<>();
+  private final Map<PropertyKey, List<String>> _batchNameCache = new HashMap<>();
+
+  public ZKReadAccessorWrapper(String clusterName, InstanceType instanceType,
+      BaseDataAccessor<ZNRecord> baseDataAccessor) {
+    super(clusterName, instanceType, baseDataAccessor);
+  }
+
+  @Override
+  public <T extends HelixProperty> T getProperty(PropertyKey key) {
+    if (_propertyCache.containsKey(key)) {
+      return (T) _propertyCache.get(key);
+    }
+    T property = super.getProperty(key);
+    _propertyCache.put(key, property);
+    return property;
+  }
+
+  @Override
+  public List<String> getChildNames(PropertyKey key) {
+    if (_batchNameCache.containsKey(key)) {
+      return _batchNameCache.get(key);
+    }
+
+    List<String> names = super.getChildNames(key);
+    _batchNameCache.put(key, names);
+
+    return names;
+  }
+}


Mime
View raw message