Move all options from IdealState to ResourceConfig, add Bulder for building ResourceConfig, and a new RebalanceConfig to hold all rebalance options for a resource.
Project: http://git-wip-us.apache.org/repos/asf/helix/repo Commit: http://git-wip-us.apache.org/repos/asf/helix/commit/65cb3165 Tree: http://git-wip-us.apache.org/repos/asf/helix/tree/65cb3165 Diff: http://git-wip-us.apache.org/repos/asf/helix/diff/65cb3165 Branch: refs/heads/helix-0.6.x Commit: 65cb3165dd244747fed8a29f9a741486f269ad8f Parents: 998a7bd Author: Lei Xia <l...@linkedin.com> Authored: Mon Oct 31 11:06:00 2016 -0700 Committer: Lei Xia <l...@linkedin.com> Committed: Wed Feb 8 09:57:00 2017 -0800 ---------------------------------------------------------------------- .../helix/api/config/RebalanceConfig.java | 221 +++++++++++ .../java/org/apache/helix/model/IdealState.java | 6 + .../org/apache/helix/model/ResourceConfig.java | 397 ++++++++++++++++++- 3 files changed, 610 insertions(+), 14 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/helix/blob/65cb3165/helix-core/src/main/java/org/apache/helix/api/config/RebalanceConfig.java ---------------------------------------------------------------------- diff --git a/helix-core/src/main/java/org/apache/helix/api/config/RebalanceConfig.java b/helix-core/src/main/java/org/apache/helix/api/config/RebalanceConfig.java new file mode 100644 index 0000000..31f6d3b --- /dev/null +++ b/helix-core/src/main/java/org/apache/helix/api/config/RebalanceConfig.java @@ -0,0 +1,221 @@ +package org.apache.helix.api.config; + +/* + * 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 org.apache.helix.ZNRecord; +import org.apache.helix.controller.rebalancer.Rebalancer; +import org.apache.helix.task.TaskRebalancer; +import org.apache.log4j.Logger; + +import java.util.HashMap; +import java.util.Map; + +/** + * Resource's rebalance configurations + */ +public class RebalanceConfig { + /** + * Configurable rebalance options of a resource + */ + public enum RebalanceConfigProperty { + REBALANCE_DELAY, + DELAY_REBALANCE_DISABLED, + REBALANCE_MODE, + REBALANCER_CLASS_NAME, + REBALANCE_TIMER_PERIOD, + REBALANCE_STRATEGY + } + + /** + * The mode used for rebalance. FULL_AUTO does both node location calculation and state + * assignment, SEMI_AUTO only does the latter, and CUSTOMIZED does neither. USER_DEFINED + * uses a Rebalancer implementation plugged in by the user. TASK designates that a + * {@link TaskRebalancer} instance should be used to rebalance this resource. + */ + public enum RebalanceMode { + FULL_AUTO, + SEMI_AUTO, + CUSTOMIZED, + USER_DEFINED, + TASK, + NONE + } + + private static final int DEFAULT_REBALANCE_DELAY = -1; + + private long _rebalanceDelay = DEFAULT_REBALANCE_DELAY; + private RebalanceMode _rebalanceMode; + private String _rebalancerClassName; + private String _rebalanceStrategy; + private Boolean _delayRebalanceDisabled; + private long _rebalanceTimerPeriod = -1; /* in seconds */ + + private static final Logger _logger = Logger.getLogger(RebalanceConfig.class.getName()); + + /** + * Instantiate from an znRecord + * + * @param znRecord + */ + public RebalanceConfig(ZNRecord znRecord) { + _rebalanceDelay = znRecord.getLongField(RebalanceConfigProperty.REBALANCE_DELAY.name(), -1); + _rebalanceMode = znRecord + .getEnumField(RebalanceConfigProperty.REBALANCE_MODE.name(), RebalanceMode.class, + RebalanceMode.NONE); + _rebalancerClassName = + znRecord.getSimpleField(RebalanceConfigProperty.REBALANCER_CLASS_NAME.name()); + _rebalanceStrategy = znRecord.getSimpleField(RebalanceConfigProperty.REBALANCE_STRATEGY.name()); + _delayRebalanceDisabled = + znRecord.getBooleanField(RebalanceConfigProperty.DELAY_REBALANCE_DISABLED.name(), false); + _rebalanceTimerPeriod = + znRecord.getLongField(RebalanceConfigProperty.REBALANCE_TIMER_PERIOD.name(), -1); + } + + /** + * Get rebalance delay (in milliseconds), default is -1 is not set. + * @return + */ + public long getRebalanceDelay() { + return _rebalanceDelay; + } + + /** + * Set the delay time (in ms) that Helix should move the partition after an instance goes offline. + * This option only takes effects when delay rebalance is enabled. + * @param rebalanceDelay + */ + public void setRebalanceDelay(long rebalanceDelay) { + this._rebalanceDelay = rebalanceDelay; + } + + public RebalanceMode getRebalanceMode() { + return _rebalanceMode; + } + + public void setRebalanceMode(RebalanceMode rebalanceMode) { + this._rebalanceMode = rebalanceMode; + } + + /** + * Get the name of the user-defined rebalancer associated with this resource + * @return the rebalancer class name, or null if none is being used + */ + public String getRebalanceClassName() { + return _rebalancerClassName; + } + + /** + * Define a custom rebalancer that implements {@link Rebalancer} + * @param rebalancerClassName the name of the custom rebalancing class + */ + public void setRebalanceClassName(String rebalancerClassName) { + this._rebalancerClassName = rebalancerClassName; + } + + /** + * Get the rebalance strategy for this resource. + * + * @return rebalance strategy, or null if not specified. + */ + public String getRebalanceStrategy() { + return _rebalanceStrategy; + } + + /** + * Specify the strategy for Helix to use to compute the partition-instance assignment, + * i,e, the custom rebalance strategy that implements {@link org.apache.helix.controller.rebalancer.strategy.RebalanceStrategy} + * + * @param rebalanceStrategy + * @return + */ + public void setRebalanceStrategy(String rebalanceStrategy) { + this._rebalanceStrategy = rebalanceStrategy; + } + + /** + * Whether the delay rebalance is disabled. By default, it is false. + * @return + */ + public Boolean isDelayRebalanceDisabled() { + return _delayRebalanceDisabled; + } + + /** + * If disabled is true, the delayed rebalance time will be ignored. + * @param delayRebalanceDisabled + */ + public void setDelayRebalanceDisabled(Boolean delayRebalanceDisabled) { + this._delayRebalanceDisabled = delayRebalanceDisabled; + } + + /** + * Get the frequency with which to rebalance + * @return the rebalancing timer period + */ + public long getRebalanceTimerPeriod() { + return _rebalanceTimerPeriod; + } + + /** + * Set the frequency with which to rebalance + * @param rebalanceTimerPeriod + */ + public void setRebalanceTimerPeriod(long rebalanceTimerPeriod) { + this._rebalanceTimerPeriod = rebalanceTimerPeriod; + } + + /** + * Generate the simple field map for RebalanceConfig. + * + * @return + */ + public Map<String, String> getSimpleFieldsMap() { + Map<String, String> simpleFieldMap = new HashMap<String, String>(); + + if (_rebalanceDelay >= 0) { + simpleFieldMap + .put(RebalanceConfigProperty.REBALANCE_DELAY.name(), String.valueOf(_rebalanceDelay)); + } + if (_rebalanceMode != null) { + simpleFieldMap.put(RebalanceConfigProperty.REBALANCE_MODE.name(), _rebalanceMode.name()); + } + if (_rebalancerClassName != null) { + simpleFieldMap.put(RebalanceConfigProperty.REBALANCER_CLASS_NAME.name(), _rebalancerClassName); + } + if (_rebalanceStrategy != null) { + simpleFieldMap.put(RebalanceConfigProperty.REBALANCE_STRATEGY.name(), _rebalanceStrategy); + } + if (_delayRebalanceDisabled != null) { + simpleFieldMap.put(RebalanceConfigProperty.DELAY_REBALANCE_DISABLED.name(), + String.valueOf(_delayRebalanceDisabled)); + } + if (_rebalanceTimerPeriod > 0) { + simpleFieldMap.put(RebalanceConfigProperty.REBALANCE_TIMER_PERIOD.name(), + String.valueOf(_rebalanceTimerPeriod)); + } + + return simpleFieldMap; + } + + public boolean isValid() { + return true; + } +} + http://git-wip-us.apache.org/repos/asf/helix/blob/65cb3165/helix-core/src/main/java/org/apache/helix/model/IdealState.java ---------------------------------------------------------------------- diff --git a/helix-core/src/main/java/org/apache/helix/model/IdealState.java b/helix-core/src/main/java/org/apache/helix/model/IdealState.java index 5ced7a6..907bd27 100644 --- a/helix-core/src/main/java/org/apache/helix/model/IdealState.java +++ b/helix-core/src/main/java/org/apache/helix/model/IdealState.java @@ -44,7 +44,9 @@ import org.apache.log4j.Logger; public class IdealState extends HelixProperty { /** * Properties that are persisted and are queryable for an ideal state + * Deprecated, use ResourceConfig.ResourceConfigProperty instead. */ + @Deprecated public enum IdealStateProperty { NUM_PARTITIONS, STATE_MODEL_DEF_REF, @@ -69,6 +71,10 @@ public class IdealState extends HelixProperty { public static final String QUERY_LIST = "PREFERENCE_LIST_QUERYS"; + /** + * Deprecated, use ResourceConfig.ResourceConfigConstants instead + */ + @Deprecated public enum IdealStateConstants { ANY_LIVEINSTANCE } http://git-wip-us.apache.org/repos/asf/helix/blob/65cb3165/helix-core/src/main/java/org/apache/helix/model/ResourceConfig.java ---------------------------------------------------------------------- diff --git a/helix-core/src/main/java/org/apache/helix/model/ResourceConfig.java b/helix-core/src/main/java/org/apache/helix/model/ResourceConfig.java index c8c7b72..616d8a2 100644 --- a/helix-core/src/main/java/org/apache/helix/model/ResourceConfig.java +++ b/helix-core/src/main/java/org/apache/helix/model/ResourceConfig.java @@ -25,6 +25,7 @@ import java.util.Map; import org.apache.helix.HelixProperty; import org.apache.helix.ZNRecord; import org.apache.helix.api.config.StateTransitionTimeoutConfig; +import org.apache.helix.api.config.RebalanceConfig; import org.apache.log4j.Logger; /** @@ -36,6 +37,22 @@ public class ResourceConfig extends HelixProperty { */ public enum ResourceConfigProperty { MONITORING_DISABLED, // Resource-level config, do not create Mbean and report any status for the resource. + NUM_PARTITIONS, + STATE_MODEL_DEF_REF, + STATE_MODEL_FACTORY_NAME, + REPLICAS, + MIN_ACTIVE_REPLICAS, + MAX_PARTITIONS_PER_INSTANCE, + INSTANCE_GROUP_TAG, + HELIX_ENABLED, + RESOURCE_GROUP_NAME, + RESOURCE_TYPE, + GROUP_ROUTING_ENABLED, + EXTERNAL_VIEW_DISABLED + } + + public enum ResourceConfigConstants { + ANY_LIVEINSTANCE } private static final Logger _logger = Logger.getLogger(ResourceConfig.class.getName()); @@ -66,6 +83,64 @@ public class ResourceConfig extends HelixProperty { public ResourceConfig(ZNRecord record, String id) { super(record, id); } + + public ResourceConfig(String resourceId, Boolean monitorDisabled, int numPartitions, + String stateModelDefRef, String stateModelFactoryName, String numReplica, + int minActiveReplica, int maxPartitionsPerInstance, String instanceGroupTag, + Boolean helixEnabled, String resourceGroupName, String resourceType, + Boolean groupRoutingEnabled, Boolean externalViewDisabled, + RebalanceConfig rebalanceConfig) { + super(resourceId); + + if (monitorDisabled != null) { + _record.setBooleanField(ResourceConfigProperty.MONITORING_DISABLED.name(), monitorDisabled); + } + _record.setIntField(ResourceConfigProperty.NUM_PARTITIONS.name(), numPartitions); + _record.setSimpleField(ResourceConfigProperty.STATE_MODEL_DEF_REF.name(), stateModelDefRef); + if (stateModelFactoryName != null) { + _record.setSimpleField(ResourceConfigProperty.STATE_MODEL_FACTORY_NAME.name(), stateModelFactoryName); + } + _record.setSimpleField(ResourceConfigProperty.REPLICAS.name(), numReplica); + + if (minActiveReplica >= 0) { + _record.setIntField(ResourceConfigProperty.MIN_ACTIVE_REPLICAS.name(), minActiveReplica); + } + + if (maxPartitionsPerInstance >= 0) { + _record.setIntField(ResourceConfigProperty.MAX_PARTITIONS_PER_INSTANCE.name(), maxPartitionsPerInstance); + } + + if (instanceGroupTag != null) { + _record.setSimpleField(ResourceConfigProperty.INSTANCE_GROUP_TAG.name(), instanceGroupTag); + } + + if (helixEnabled != null) { + _record.setBooleanField(ResourceConfigProperty.HELIX_ENABLED.name(), helixEnabled); + } + + if (resourceGroupName != null) { + _record.setSimpleField(ResourceConfigProperty.RESOURCE_GROUP_NAME.name(), resourceGroupName); + } + + if (resourceType != null) { + _record.setSimpleField(ResourceConfigProperty.RESOURCE_TYPE.name(), resourceType); + } + + if (groupRoutingEnabled != null) { + _record.setBooleanField(ResourceConfigProperty.GROUP_ROUTING_ENABLED.name(), + groupRoutingEnabled); + } + + if (externalViewDisabled != null) { + _record.setBooleanField(ResourceConfigProperty.EXTERNAL_VIEW_DISABLED.name(), externalViewDisabled); + } + + if (rebalanceConfig != null) { + putSimpleConfigs(rebalanceConfig.getSimpleFieldsMap()); + } + } + + /** * Get the value of DisableMonitoring set. * @@ -75,14 +150,122 @@ public class ResourceConfig extends HelixProperty { return _record.getBooleanField(ResourceConfigProperty.MONITORING_DISABLED.toString(), false); } + + /** + * Get the associated resource + * @return the name of the resource + */ + public String getResourceName() { + return _record.getId(); + } + + /** + * Get the number of partitions of this resource + * @return the number of partitions + */ + public int getNumPartitions() { + return _record.getIntField(ResourceConfigProperty.NUM_PARTITIONS.name(), 0); + } + + /** + * Get the state model associated with this resource + * @return an identifier of the state model + */ + public String getStateModelDefRef() { + return _record.getSimpleField(ResourceConfigProperty.STATE_MODEL_DEF_REF.name()); + } + + /** + * Get the state model factory associated with this resource + * @return state model factory name + */ + public String getStateModelFactoryName() { + return _record.getSimpleField(ResourceConfigProperty.STATE_MODEL_FACTORY_NAME.name()); + } + + /** + * Get the number of replicas for each partition of this resource + * @return number of replicas (as a string) + */ + public String getNumReplica() { + // TODO: use IdealState.getNumbReplica()? + return _record.getSimpleField(ResourceConfigProperty.REPLICAS.name()); + } + + /** + * Get the number of minimal active partitions for this resource. + * + * @return + */ + public int getMinActiveReplica() { + return _record.getIntField(ResourceConfigProperty.MIN_ACTIVE_REPLICAS.name(), -1); + } + + public int getMaxPartitionsPerInstance() { + return _record.getIntField(ResourceConfigProperty.MAX_PARTITIONS_PER_INSTANCE.toString(), + Integer.MAX_VALUE); + } + + /** + * Check for a tag that will restrict assignment to instances with a matching tag + * @return the group tag, or null if none is present + */ + public String getInstanceGroupTag() { + return _record.getSimpleField(ResourceConfigProperty.INSTANCE_GROUP_TAG.toString()); + } + + /** + * Get if the resource is enabled or not + * By default, it's enabled + * @return true if enabled; false otherwise + */ + public Boolean isEnabled() { + return _record.getBooleanField(ResourceConfigProperty.HELIX_ENABLED.name(), true); + } + /** - * Set whether to disable monitoring for this resource. + * Get the resource type + * @return the resource type, or null if none is being set + */ + public String getResourceType() { + return _record.getSimpleField(ResourceConfigProperty.RESOURCE_TYPE.name()); + } + + /** + * Get the resource group name * - * @param monitoringDisabled whether to disable monitoring for this resource. + * @return + */ + public String getResourceGroupName() { + return _record.getSimpleField(ResourceConfigProperty.RESOURCE_GROUP_NAME.name()); + } + + /** + * Get if the resource group routing feature is enabled or not + * By default, it's disabled + * + * @return true if enabled; false otherwise + */ + public Boolean isGroupRoutingEnabled() { + return _record.getBooleanField(ResourceConfigProperty.GROUP_ROUTING_ENABLED.name(), false); + } + + /** + * If the external view for this resource is disabled. by default, it is false. + * + * @return true if the external view should be disabled for this resource. + */ + public Boolean isExternalViewDisabled() { + return _record.getBooleanField(ResourceConfigProperty.EXTERNAL_VIEW_DISABLED.name(), false); + } + + /** + * Get rebalance config for this resource. + * @return */ - public void setMonitoringDisabled(boolean monitoringDisabled) { - _record - .setBooleanField(ResourceConfigProperty.MONITORING_DISABLED.toString(), monitoringDisabled); + public RebalanceConfig getRebalanceConfig() { + RebalanceConfig rebalanceConfig = new RebalanceConfig(_record); + return rebalanceConfig; } // TODO: Move it to constructor and Builder when the logic merged in @@ -197,17 +380,203 @@ public class ResourceConfig extends HelixProperty { return getId().hashCode(); } - /** - * Get the name of this resource - * - * @return the instance name - */ - public String getResourceName() { - return _record.getId(); - } - @Override public boolean isValid() { return true; } + + + public class Builder { + private String _resourceId; + private Boolean _monitorDisabled; + private int _numPartitions; + private String _stateModelDefRef; + private String _stateModelFactoryName; + private String _numReplica; + private int _minActiveReplica = -1; + private int _maxPartitionsPerInstance = -1; + private String _instanceGroupTag; + private Boolean _helixEnabled; + private String _resourceGroupName; + private String _resourceType; + private Boolean _groupRoutingEnabled; + private Boolean _externalViewDisabled; + private RebalanceConfig _rebalanceConfig; + + public Builder(String resourceId) { + _resourceId = resourceId; + } + + public Builder setMonitorDisabled(boolean monitorDisabled) { + _monitorDisabled = monitorDisabled; + return this; + } + + public Boolean isMonitorDisabled() { + return _monitorDisabled; + } + + public String getResourceId() { + return _resourceId; + } + + public int getNumPartitions() { + return _numPartitions; + } + + public Builder setNumPartitions(int numPartitions) { + _numPartitions = numPartitions; + return this; + } + + public String getStateModelDefRef() { + return _stateModelDefRef; + } + + public Builder setStateModelDefRef(String stateModelDefRef) { + _stateModelDefRef = stateModelDefRef; + return this; + } + + public String getStateModelFactoryName() { + return _stateModelFactoryName; + } + + public Builder setStateModelFactoryName(String stateModelFactoryName) { + _stateModelFactoryName = stateModelFactoryName; + return this; + } + + public String getNumReplica() { + return _numReplica; + } + + public Builder setNumReplica(String numReplica) { + _numReplica = numReplica; + return this; + } + + public Builder setNumReplica(int numReplica) { + return setNumReplica(String.valueOf(numReplica)); + } + + public int getMinActiveReplica() { + return _minActiveReplica; + } + + public Builder setMinActiveReplica(int minActiveReplica) { + _minActiveReplica = minActiveReplica; + return this; + } + + public int getMaxPartitionsPerInstance() { + return _maxPartitionsPerInstance; + } + + public Builder setMaxPartitionsPerInstance(int maxPartitionsPerInstance) { + _maxPartitionsPerInstance = maxPartitionsPerInstance; + return this; + } + + public String getInstanceGroupTag() { + return _instanceGroupTag; + } + + public Builder setInstanceGroupTag(String instanceGroupTag) { + _instanceGroupTag = instanceGroupTag; + return this; + } + + public Boolean isHelixEnabled() { + return _helixEnabled; + } + + public Builder setHelixEnabled(boolean helixEnabled) { + _helixEnabled = helixEnabled; + return this; + } + + public String getResourceType() { + return _resourceType; + } + + public Builder setResourceType(String resourceType) { + _resourceType = resourceType; + return this; + } + + public String getResourceGroupName() { + return _resourceGroupName; + } + + public Builder setResourceGroupName(String resourceGroupName) { + _resourceGroupName = resourceGroupName; + return this; + } + + public Boolean isGroupRoutingEnabled() { + return _groupRoutingEnabled; + } + + public Builder setGroupRoutingEnabled(boolean groupRoutingEnabled) { + _groupRoutingEnabled = groupRoutingEnabled; + return this; + } + + public Boolean isExternalViewDisabled() { + return _externalViewDisabled; + } + + public Builder setExternalViewDisabled(boolean externalViewDisabled) { + _externalViewDisabled = externalViewDisabled; + return this; + } + + public Builder setRebalanceConfig(RebalanceConfig rebalanceConfig) { + _rebalanceConfig = rebalanceConfig; + return this; + } + + public RebalanceConfig getRebalanceConfig() { + return _rebalanceConfig; + } + + private void validate() { + if (_rebalanceConfig == null) { + throw new IllegalArgumentException("RebalanceConfig not set!"); + } else { + if (_rebalanceConfig.isValid()) { + throw new IllegalArgumentException("Invalid RebalanceConfig!"); + } + } + if (_numPartitions <= 0) { + throw new IllegalArgumentException("Invalid number of partitions!"); + } + + if (_stateModelDefRef == null) { + throw new IllegalArgumentException("State Model Definition Reference is not set!"); + } + + if (_numReplica == null) { + throw new IllegalArgumentException("Number of replica is not set!"); + } else { + if (!_numReplica.equals(ResourceConfigConstants.ANY_LIVEINSTANCE.name())) { + try { + Integer.parseInt(_numReplica); + } catch (NumberFormatException ex) { + throw new IllegalArgumentException("Invalid number of replica!"); + } + } + } + } + + public ResourceConfig build() { + validate(); + + return new ResourceConfig(_resourceId, _monitorDisabled, _numPartitions, _stateModelDefRef, + _stateModelFactoryName, _numReplica, _minActiveReplica, _maxPartitionsPerInstance, + _instanceGroupTag, _helixEnabled, _resourceGroupName, _resourceType, _groupRoutingEnabled, + _externalViewDisabled, _rebalanceConfig); + } + } }