You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@helix.apache.org by ji...@apache.org on 2020/04/23 19:27:48 UTC

[helix] 02/23: add CustomizedStateAggregation config (#776)

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

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

commit 2189de73936f1d2b7166bb407019b88c4faffde2
Author: zhangmeng916 <56...@users.noreply.github.com>
AuthorDate: Thu Feb 20 11:53:44 2020 -0800

    add CustomizedStateAggregation config (#776)
    
    Add CustomizedViewAggregation as a cluster level config. This config defines the types of customized states that will be aggregated by Helix controller to generate a customized view. If Helix customers would like to have an aggregated view generated for their own states, they will need to add the type of the state to the list view in this config.
---
 .../main/java/org/apache/helix/ConfigAccessor.java |  22 ++++
 .../main/java/org/apache/helix/PropertyKey.java    |  11 ++
 .../model/CustomizedStateAggregationConfig.java    | 144 +++++++++++++++++++++
 .../org/apache/helix/model/HelixConfigScope.java   |   5 +-
 .../model/builder/HelixConfigScopeBuilder.java     |   2 +
 .../TestCustomizedStateAggregationConfig.java      | 124 ++++++++++++++++++
 6 files changed, 307 insertions(+), 1 deletion(-)

diff --git a/helix-core/src/main/java/org/apache/helix/ConfigAccessor.java b/helix-core/src/main/java/org/apache/helix/ConfigAccessor.java
index 41f7365..5a41241 100644
--- a/helix-core/src/main/java/org/apache/helix/ConfigAccessor.java
+++ b/helix-core/src/main/java/org/apache/helix/ConfigAccessor.java
@@ -33,6 +33,7 @@ import org.apache.helix.manager.zk.ZKUtil;
 import org.apache.helix.model.ClusterConfig;
 import org.apache.helix.model.CloudConfig;
 import org.apache.helix.model.ConfigScope;
+import org.apache.helix.model.CustomizedStateAggregationConfig;
 import org.apache.helix.model.HelixConfigScope;
 import org.apache.helix.model.HelixConfigScope.ConfigScopeProperty;
 import org.apache.helix.model.InstanceConfig;
@@ -588,6 +589,27 @@ public class ConfigAccessor {
   }
 
   /**
+   * Get CustomizedStateAggregationConfig of the given cluster.
+   * @param clusterName
+   * @return The instance of {@link CustomizedStateAggregationConfig}
+   */
+  public CustomizedStateAggregationConfig getCustomizedStateAggregationConfig(String clusterName) {
+    if (!ZKUtil.isClusterSetup(clusterName, _zkClient)) {
+      throw new HelixException(String.format("Failed to get config. cluster: %s is not setup.", clusterName));
+    }
+    HelixConfigScope scope =
+        new HelixConfigScopeBuilder(ConfigScopeProperty.CUSTOMIZED_STATE_AGGREGATION).forCluster(clusterName).build();
+    ZNRecord record = getConfigZnRecord(scope);
+
+    if (record == null) {
+      LOG.warn("No customized state aggregation config found at {}.", scope.getZkPath());
+      return null;
+    }
+
+    return new CustomizedStateAggregationConfig(record);
+  }
+
+  /**
    * Get ClusterConfig of the given cluster.
    *
    * @param clusterName
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 73cc3f0..1df56ff 100644
--- a/helix-core/src/main/java/org/apache/helix/PropertyKey.java
+++ b/helix-core/src/main/java/org/apache/helix/PropertyKey.java
@@ -27,6 +27,7 @@ import org.apache.helix.model.ClusterConfig;
 import org.apache.helix.model.ClusterConstraints;
 import org.apache.helix.model.ControllerHistory;
 import org.apache.helix.model.CurrentState;
+import org.apache.helix.model.CustomizedStateAggregationConfig;
 import org.apache.helix.model.Error;
 import org.apache.helix.model.ExternalView;
 import org.apache.helix.model.HealthStat;
@@ -245,6 +246,16 @@ public class PropertyKey {
     }
 
     /**
+     * Get a property key associated with this customized state aggregation configuration
+     * @return {@link PropertyKey}
+     */
+    public PropertyKey customizedStateAggregationConfig() {
+      return new PropertyKey(CONFIGS, ConfigScopeProperty.CUSTOMIZED_STATE_AGGREGATION,
+          CustomizedStateAggregationConfig.class, _clusterName,
+          ConfigScopeProperty.CUSTOMIZED_STATE_AGGREGATION.name(), _clusterName);
+    }
+
+    /**
      * Get a property key associated with {@link InstanceConfig}
      * @return {@link PropertyKey}
      */
diff --git a/helix-core/src/main/java/org/apache/helix/model/CustomizedStateAggregationConfig.java b/helix-core/src/main/java/org/apache/helix/model/CustomizedStateAggregationConfig.java
new file mode 100644
index 0000000..0e4a065
--- /dev/null
+++ b/helix-core/src/main/java/org/apache/helix/model/CustomizedStateAggregationConfig.java
@@ -0,0 +1,144 @@
+package org.apache.helix.model;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.helix.HelixProperty;
+import org.apache.helix.ZNRecord;
+
+/**
+ * CustomizedStateAggregation configurations
+ */
+public class CustomizedStateAggregationConfig extends HelixProperty {
+  /**
+   * Indicate which customized states will be aggregated.
+   * NOTE: Do NOT use this field name directly, use its corresponding getter/setter in the
+   * CustomizedStateAggregationConfig.
+   */
+  public enum CustomizedStateAggregationProperty {
+    AGGREGATION_ENABLED_TYPES,
+  }
+
+  /**
+   * Instantiate the CustomizedStateAggregationConfig
+   * @param cluster
+   */
+  public CustomizedStateAggregationConfig(String cluster) {
+    super(cluster);
+  }
+
+  /**
+   * Instantiate with a pre-populated record
+   * @param record a ZNRecord corresponding to a CustomizedStateAggregationConfig
+   */
+  public CustomizedStateAggregationConfig(ZNRecord record) {
+    super(record);
+  }
+
+  /**
+   * Instantiate the config using each field individually.
+   * Users should use CustomizedStateAggregationConfig.Builder to create
+   * CustomizedStateAggregationConfig.
+   * @param cluster
+   * @param aggregationEnabledTypes
+   */
+  public CustomizedStateAggregationConfig(String cluster, List<String> aggregationEnabledTypes) {
+    super(cluster);
+    _record.setListField(CustomizedStateAggregationProperty.AGGREGATION_ENABLED_TYPES.name(),
+        aggregationEnabledTypes);
+
+  }
+
+  /**
+   * Set the AGGREGATION_ENABLED_STATES field.
+   * @param aggregationEnabledTypes
+   */
+  public void setAggregationEnabledTypes(List<String> aggregationEnabledTypes) {
+    _record.setListField(CustomizedStateAggregationProperty.AGGREGATION_ENABLED_TYPES.name(),
+        aggregationEnabledTypes);
+  }
+
+  /**
+   * Get the AGGREGATION_ENABLED_STATES field.
+   * @return AGGREGATION_ENABLED_STATES field.
+   */
+  public List<String> getAggregationEnabledTypes() {
+    return _record
+        .getListField(CustomizedStateAggregationProperty.AGGREGATION_ENABLED_TYPES.name());
+  }
+
+  public static class Builder {
+    private String _clusterName = null;
+    private List<String> _aggregationEnabledTypes;
+
+    public CustomizedStateAggregationConfig build() {
+      return new CustomizedStateAggregationConfig(_clusterName, _aggregationEnabledTypes);
+    }
+
+    /**
+     * Default constructor
+     */
+    public Builder() {
+    }
+
+    /**
+     * Constructor with Cluster Name as input
+     * @param clusterName
+     */
+    public Builder(String clusterName) {
+      _clusterName = clusterName;
+    }
+
+    /**
+     * Constructor with CustomizedStateAggregationConfig as input
+     * @param customizedStateAggregationConfig
+     */
+    public Builder(CustomizedStateAggregationConfig customizedStateAggregationConfig) {
+      _aggregationEnabledTypes = customizedStateAggregationConfig.getAggregationEnabledTypes();
+    }
+
+    public Builder setClusterName(String v) {
+      _clusterName = v;
+      return this;
+    }
+
+    public Builder setAggregationEnabledTypes(List<String> v) {
+      _aggregationEnabledTypes = v;
+      return this;
+    }
+
+    public Builder addAggregationEnabledType(String v) {
+      if (_aggregationEnabledTypes == null) {
+        _aggregationEnabledTypes = new ArrayList<String>();
+      }
+      _aggregationEnabledTypes.add(v);
+      return this;
+    }
+
+    public String getClusterName() {
+      return _clusterName;
+    }
+
+    public List<String> getAggregationEnabledTypes() {
+      return _aggregationEnabledTypes;
+    }
+  }
+}
diff --git a/helix-core/src/main/java/org/apache/helix/model/HelixConfigScope.java b/helix-core/src/main/java/org/apache/helix/model/HelixConfigScope.java
index 8d814c5..cf49ccd 100644
--- a/helix-core/src/main/java/org/apache/helix/model/HelixConfigScope.java
+++ b/helix-core/src/main/java/org/apache/helix/model/HelixConfigScope.java
@@ -37,7 +37,8 @@ public class HelixConfigScope {
     PARTITION(2, 1),
     CONSTRAINT(2, 0),
     REST(2, 0),
-    CLOUD(2, 0);
+    CLOUD(2, 0),
+    CUSTOMIZED_STATE_AGGREGATION(2, 0);
 
     final int _zkPathArgNum;
     final int _mapKeyArgNum;
@@ -88,6 +89,8 @@ public class HelixConfigScope {
     template.addEntry(ConfigScopeProperty.RESOURCE, 1, "/{clusterName}/CONFIGS/RESOURCE");
     template.addEntry(ConfigScopeProperty.REST, 2, "/{clusterName}/CONFIGS/REST/{clusterName}");
     template.addEntry(ConfigScopeProperty.CLOUD, 1, "/{clusterName}/CONFIGS/CLOUD");
+    template.addEntry(ConfigScopeProperty.CUSTOMIZED_STATE_AGGREGATION, 2,
+        "/{clusterName}/CONFIGS/CUSTOMIZED_STATE_AGGREGATION/{clusterName}");
   }
 
   final ConfigScopeProperty _type;
diff --git a/helix-core/src/main/java/org/apache/helix/model/builder/HelixConfigScopeBuilder.java b/helix-core/src/main/java/org/apache/helix/model/builder/HelixConfigScopeBuilder.java
index 78ed074..98de1e7 100644
--- a/helix-core/src/main/java/org/apache/helix/model/builder/HelixConfigScopeBuilder.java
+++ b/helix-core/src/main/java/org/apache/helix/model/builder/HelixConfigScopeBuilder.java
@@ -129,6 +129,8 @@ public class HelixConfigScopeBuilder {
     case CLOUD:
       scope = new HelixConfigScope(_type, Arrays.asList(_clusterName, _clusterName), null);
       break;
+    case CUSTOMIZED_STATE_AGGREGATION:
+      scope = new HelixConfigScope(_type, Arrays.asList(_clusterName, _clusterName), null);
     default:
       break;
     }
diff --git a/helix-core/src/test/java/org/apache/helix/model/TestCustomizedStateAggregationConfig.java b/helix-core/src/test/java/org/apache/helix/model/TestCustomizedStateAggregationConfig.java
new file mode 100644
index 0000000..5cdc333
--- /dev/null
+++ b/helix-core/src/test/java/org/apache/helix/model/TestCustomizedStateAggregationConfig.java
@@ -0,0 +1,124 @@
+package org.apache.helix.model;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.ArrayList;
+import org.apache.helix.ConfigAccessor;
+import org.apache.helix.HelixException;
+import org.apache.helix.PropertyKey.Builder;
+import org.apache.helix.TestHelper;
+import org.apache.helix.ZkUnitTestBase;
+import org.apache.helix.manager.zk.ZKHelixDataAccessor;
+import java.util.List;
+import org.apache.helix.manager.zk.ZkBaseDataAccessor;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class TestCustomizedStateAggregationConfig extends ZkUnitTestBase {
+
+  @Test(expectedExceptions = HelixException.class)
+  public void TestCustomizedStateAggregationConfigNonExistentCluster() {
+    String className = getShortClassName();
+    String clusterName = "CLUSTER_" + className;
+    // Read CustomizedStateAggregationConfig from Zookeeper and get exception since cluster in not setup yet
+    ConfigAccessor _configAccessor = new ConfigAccessor(_gZkClient);
+    CustomizedStateAggregationConfig customizedStateAggregationConfig =
+        _configAccessor.getCustomizedStateAggregationConfig(clusterName);
+  }
+
+  @Test(dependsOnMethods = "TestCustomizedStateAggregationConfigNonExistentCluster")
+  public void testCustomizedStateAggregationConfigNull() {
+    String className = getShortClassName();
+    String clusterName = "CLUSTER_" + className;
+    TestHelper.setupEmptyCluster(_gZkClient, clusterName);
+    // Read CustomizedStateAggregationConfig from Zookeeper
+    ConfigAccessor _configAccessor = new ConfigAccessor(_gZkClient);
+    CustomizedStateAggregationConfig customizedStateAggregationConfigFromZk =
+        _configAccessor.getCustomizedStateAggregationConfig(clusterName);
+    Assert.assertNull(customizedStateAggregationConfigFromZk);
+  }
+
+  @Test(dependsOnMethods = "testCustomizedStateAggregationConfigNull")
+  public void testCustomizedStateAggregationConfig() {
+    String className = getShortClassName();
+    String clusterName = "CLUSTER_" + className;
+    TestHelper.setupEmptyCluster(_gZkClient, clusterName);
+
+    // Create dummy CustomizedStateAggregationConfig object
+    CustomizedStateAggregationConfig customizedStateAggregationConfig =
+        new CustomizedStateAggregationConfig(clusterName);
+    List<String> aggregationEnabledTypes = new ArrayList<String>();
+    aggregationEnabledTypes.add("mockState1");
+    aggregationEnabledTypes.add("mockState2");
+    customizedStateAggregationConfig.setAggregationEnabledTypes(aggregationEnabledTypes);
+
+    // Write the CustomizedStateAggregationConfig to Zookeeper
+    ZKHelixDataAccessor accessor =
+        new ZKHelixDataAccessor(clusterName, new ZkBaseDataAccessor(_gZkClient));
+    Builder keyBuilder = accessor.keyBuilder();
+    accessor.setProperty(keyBuilder.customizedStateAggregationConfig(),
+        customizedStateAggregationConfig);
+
+    // Read CustomizedStateAggregationConfig from Zookeeper and check the content
+    ConfigAccessor _configAccessor = new ConfigAccessor(_gZkClient);
+    CustomizedStateAggregationConfig customizedStateAggregationConfigFromZk =
+        _configAccessor.getCustomizedStateAggregationConfig(clusterName);
+    Assert.assertEquals(customizedStateAggregationConfigFromZk.getAggregationEnabledTypes().size(),
+        2);
+    Assert.assertEquals(aggregationEnabledTypes.get(0), "mockType1");
+    Assert.assertEquals(aggregationEnabledTypes.get(1), "mockType2");
+  }
+
+  @Test(dependsOnMethods = "testCustomizedStateAggregationConfig")
+  public void testCustomizedStateAggregationConfigBuilder() {
+    String className = getShortClassName();
+    String clusterName = "CLUSTER_" + className;
+    TestHelper.setupEmptyCluster(_gZkClient, clusterName);
+    CustomizedStateAggregationConfig.Builder builder =
+        new CustomizedStateAggregationConfig.Builder(clusterName);
+    builder.addAggregationEnabledType("mockType1");
+    builder.addAggregationEnabledType("mockType2");
+
+    // Check builder getter methods
+    Assert.assertEquals(builder.getClusterName(), clusterName);
+    List<String> aggregationEnabledTypes = builder.getAggregationEnabledTypes();
+    Assert.assertEquals(aggregationEnabledTypes.size(), 2);
+    Assert.assertEquals(aggregationEnabledTypes.get(0), "mockType1");
+    Assert.assertEquals(aggregationEnabledTypes.get(1), "mockType2");
+
+    CustomizedStateAggregationConfig customizedStateAggregationConfig = builder.build();
+
+    ZKHelixDataAccessor accessor =
+        new ZKHelixDataAccessor(clusterName, new ZkBaseDataAccessor(_gZkClient));
+    Builder keyBuilder = accessor.keyBuilder();
+    accessor.setProperty(keyBuilder.customizedStateAggregationConfig(),
+        customizedStateAggregationConfig);
+
+    // Read CustomizedStateAggregationConfig from Zookeeper and check the content
+    ConfigAccessor _configAccessor = new ConfigAccessor(_gZkClient);
+    CustomizedStateAggregationConfig customizedStateAggregationConfigFromZk =
+        _configAccessor.getCustomizedStateAggregationConfig(clusterName);
+    List<String> aggregationEnabledTypesFromZk =
+        customizedStateAggregationConfigFromZk.getAggregationEnabledTypes();
+    Assert.assertEquals(aggregationEnabledTypesFromZk.get(0), "mockType1");
+    Assert.assertEquals(aggregationEnabledTypesFromZk.get(1), "mockType2");
+  }
+
+}