This is an automated email from the ASF dual-hosted git repository. jackie pushed a commit to branch resource_allocation in repository https://gitbox.apache.org/repos/asf/incubator-pinot.git
commit e79b208f946b9e1cff78893e284e855f949935d5 Author: Xiaotian (Jackie) Jiang <xaji...@linkedin.com> AuthorDate: Thu Nov 29 12:47:28 2018 -0800 commit --- .../helix/core/instance/InstanceAttributes.java | 68 ++++++++++++++++++++++ .../helix/core/instance/InstancePoolUtils.java | 34 +++++++++++ .../helix/core/instance/InstanceRole.java | 5 ++ .../instance/assignment/AssignmentStrategy.java | 4 ++ .../instances/AllInstancesConstraint.java | 22 +++++++ .../FixedNumInstancesPerReplicaConstraint.java | 42 +++++++++++++ .../instances/NumInstancesConstraint.java | 17 ++++++ .../replicagroup/CustomReplicaGroupConstraint.java | 12 ++++ .../DefaultReplicaGroupConstraint.java | 43 ++++++++++++++ .../replicagroup/NoReplicaGroupConstraint.java | 13 +++++ .../replicagroup/ReplicaGroupConstraint.java | 16 +++++ .../instance/selection/result/SelectionResult.java | 32 ++++++++++ .../selection/result/SelectionResultUtils.java | 20 +++++++ .../selection/strategy/SelectionStrategy.java | 12 ++++ 14 files changed, 340 insertions(+) diff --git a/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/InstanceAttributes.java b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/InstanceAttributes.java new file mode 100644 index 0000000..434bc96 --- /dev/null +++ b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/InstanceAttributes.java @@ -0,0 +1,68 @@ +package com.linkedin.pinot.controller.helix.core.instance; + +import com.google.common.base.Preconditions; +import javax.annotation.Nullable; + + +public class InstanceAttributes { + private static final String TAG_DELIMITER = "_"; + private static final String UNTAGGED = "untagged"; + + private final InstanceRole _role; + private final String _poolName; + private final int _groupId; + + public InstanceAttributes(InstanceRole role, String poolName, int groupId) { + _role = role; + _poolName = poolName; + _groupId = groupId; + } + + @Nullable + public static InstanceAttributes fromTag(String tag) { + String[] parts = tag.split(TAG_DELIMITER); + Preconditions.checkArgument(parts.length == 2 || parts.length == 3); + + // For backward-compatible + if (parts.length == 2) { + // E.g. broker_untagged, server_untagged, minion_untagged + if (parts[1].equals(UNTAGGED)) { + return null; + } + // E.g. poolName_OFFLINE, poolName_REALTIME, poolName_BROKER + return new InstanceAttributes(InstanceRole.valueOf(parts[1]), parts[0], 0); + } else { + // E.g. poolName_0_OFFLINE, poolName_1_REALTIME + return new InstanceAttributes(InstanceRole.valueOf(parts[2]), parts[0], Integer.parseInt(parts[1])); + } + } + + public InstanceRole getRole() { + return _role; + } + + public String getPoolName() { + return _poolName; + } + + public int getGroupId() { + return _groupId; + } + + @Override + public int hashCode() { + return 37 * 37 * _role.hashCode() + 37 * _poolName.hashCode() + _groupId; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof InstanceAttributes) { + InstanceAttributes that = (InstanceAttributes) obj; + return _role == that._role && _poolName.equals(that._poolName) && _groupId == that._groupId; + } + return false; + } +} diff --git a/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/InstancePoolUtils.java b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/InstancePoolUtils.java new file mode 100644 index 0000000..973bdd3 --- /dev/null +++ b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/InstancePoolUtils.java @@ -0,0 +1,34 @@ +package com.linkedin.pinot.controller.helix.core.instance; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.apache.helix.model.InstanceConfig; + + +public class InstancePoolUtils { + private InstancePoolUtils() { + } + + public static Map<Integer, Set<String>> getGroupIdToInstancePoolMap(List<InstanceConfig> instanceConfigs, + InstanceRole role, String poolName) { + Map<Integer, Set<String>> groupIdToInstancePoolMap = new HashMap<>(); + for (InstanceConfig instanceConfig : instanceConfigs) { + // Skip disabled instances + if (!instanceConfig.getInstanceEnabled()) { + continue; + } + for (String tag : instanceConfig.getTags()) { + InstanceAttributes instanceAttributes = InstanceAttributes.fromTag(tag); + if (instanceAttributes != null && instanceAttributes.getRole() == role && instanceAttributes.getPoolName() + .equals(poolName)) { + int groupId = instanceAttributes.getGroupId(); + groupIdToInstancePoolMap.computeIfAbsent(groupId, k -> new HashSet<>()).add(instanceConfig.getInstanceName()); + } + } + } + return groupIdToInstancePoolMap; + } +} diff --git a/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/InstanceRole.java b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/InstanceRole.java new file mode 100644 index 0000000..9fa958a --- /dev/null +++ b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/InstanceRole.java @@ -0,0 +1,5 @@ +package com.linkedin.pinot.controller.helix.core.instance; + +public enum InstanceRole { + CONTROLLER, BROKER, OFFLINE, REALTIME, MINION +} diff --git a/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/assignment/AssignmentStrategy.java b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/assignment/AssignmentStrategy.java new file mode 100644 index 0000000..126b467 --- /dev/null +++ b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/assignment/AssignmentStrategy.java @@ -0,0 +1,4 @@ +package com.linkedin.pinot.controller.helix.core.instance.assignment; + +public interface AssignmentStrategy { +} diff --git a/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/constraint/instances/AllInstancesConstraint.java b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/constraint/instances/AllInstancesConstraint.java new file mode 100644 index 0000000..8ec83aa --- /dev/null +++ b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/constraint/instances/AllInstancesConstraint.java @@ -0,0 +1,22 @@ +package com.linkedin.pinot.controller.helix.core.instance.selection.constraint.instances; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + + +public class AllInstancesConstraint implements NumInstancesConstraint { + + @Override + public Map<Integer, List<String>> apply(Map<Integer, Set<String>> replicaIdToCandidateInstancesMap) { + Map<Integer, List<String>> replicaIdToSelectedInstancesMap = new HashMap<>(); + for (Map.Entry<Integer, Set<String>> entry : replicaIdToCandidateInstancesMap.entrySet()) { + List<String> allInstances = new ArrayList<>(entry.getValue()); + allInstances.sort(null); + replicaIdToSelectedInstancesMap.put(entry.getKey(), allInstances); + } + return replicaIdToSelectedInstancesMap; + } +} diff --git a/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/constraint/instances/FixedNumInstancesPerReplicaConstraint.java b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/constraint/instances/FixedNumInstancesPerReplicaConstraint.java new file mode 100644 index 0000000..642737f --- /dev/null +++ b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/constraint/instances/FixedNumInstancesPerReplicaConstraint.java @@ -0,0 +1,42 @@ +package com.linkedin.pinot.controller.helix.core.instance.selection.constraint.instances; + +import com.google.common.base.Preconditions; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + + +public class FixedNumInstancesPerReplicaConstraint implements NumInstancesConstraint { + private final int _numInstancesPerReplica; + + public FixedNumInstancesPerReplicaConstraint(int numInstancesPerReplica) { + _numInstancesPerReplica = numInstancesPerReplica; + } + + @Override + public Map<Integer, List<String>> apply(Map<Integer, Set<String>> replicaIdToCandidateInstancesMap) { + Map<Integer, List<String>> replicaIdToSelectedInstancesMap = new HashMap<>(); + for (Map.Entry<Integer, Set<String>> entry : replicaIdToCandidateInstancesMap.entrySet()) { + List<String> allInstances = new ArrayList<>(entry.getValue()); + int numInstances = allInstances.size(); + Preconditions.checkState(numInstances >= _numInstancesPerReplica); + + List<String> selectedInstances; + if (numInstances == _numInstancesPerReplica) { + selectedInstances = allInstances; + } else { + Collections.shuffle(allInstances); + selectedInstances = new ArrayList<>(_numInstancesPerReplica); + for (int i = 0; i < _numInstancesPerReplica; i++) { + selectedInstances.add(allInstances.get(i)); + } + } + selectedInstances.sort(null); + replicaIdToSelectedInstancesMap.put(entry.getKey(), selectedInstances); + } + return replicaIdToSelectedInstancesMap; + } +} diff --git a/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/constraint/instances/NumInstancesConstraint.java b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/constraint/instances/NumInstancesConstraint.java new file mode 100644 index 0000000..0d05820 --- /dev/null +++ b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/constraint/instances/NumInstancesConstraint.java @@ -0,0 +1,17 @@ +package com.linkedin.pinot.controller.helix.core.instance.selection.constraint.instances; + +import java.util.List; +import java.util.Map; +import java.util.Set; + + +public interface NumInstancesConstraint { + + /** + * Applies the number of instances constraint, and returns a map from replica Id to selected instances. + * + * @param replicaIdToCandidateInstancesMap Map from replica Id to candidate instances + * @return Map from replica Id to selected instances + */ + Map<Integer, List<String>> apply(Map<Integer, Set<String>> replicaIdToCandidateInstancesMap); +} diff --git a/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/constraint/replicagroup/CustomReplicaGroupConstraint.java b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/constraint/replicagroup/CustomReplicaGroupConstraint.java new file mode 100644 index 0000000..bf754e2 --- /dev/null +++ b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/constraint/replicagroup/CustomReplicaGroupConstraint.java @@ -0,0 +1,12 @@ +package com.linkedin.pinot.controller.helix.core.instance.selection.constraint.replicagroup; + +import java.util.Map; +import java.util.Set; + + +public class CustomReplicaGroupConstraint implements ReplicaGroupConstraint { + @Override + public Map<Integer, Set<String>> apply(Map<Integer, Set<String>> groupIdToInstancePoolMap) { + return null; + } +} diff --git a/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/constraint/replicagroup/DefaultReplicaGroupConstraint.java b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/constraint/replicagroup/DefaultReplicaGroupConstraint.java new file mode 100644 index 0000000..07bebd2 --- /dev/null +++ b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/constraint/replicagroup/DefaultReplicaGroupConstraint.java @@ -0,0 +1,43 @@ +package com.linkedin.pinot.controller.helix.core.instance.selection.constraint.replicagroup; + +import com.google.common.base.Preconditions; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + + +public class DefaultReplicaGroupConstraint implements ReplicaGroupConstraint { + private final int _numReplicas; + + public DefaultReplicaGroupConstraint(int numReplicas) { + _numReplicas = numReplicas; + } + + @Override + public Map<Integer, Set<String>> apply(Map<Integer, Set<String>> groupIdToInstancePoolMap) { + List<Integer> allGroups = new ArrayList<>(groupIdToInstancePoolMap.keySet()); + int numGroups = allGroups.size(); + Preconditions.checkState(numGroups >= _numReplicas); + + List<Integer> selectedGroups; + if (numGroups == _numReplicas) { + selectedGroups = allGroups; + } else { + Collections.shuffle(allGroups); + selectedGroups = new ArrayList<>(_numReplicas); + for (int i = 0; i < _numReplicas; i++) { + selectedGroups.add(allGroups.get(i)); + } + } + selectedGroups.sort(null); + + Map<Integer, Set<String>> replicaIdToCandidateInstancesMap = new HashMap<>(); + for (int i = 0; i < _numReplicas; i++) { + replicaIdToCandidateInstancesMap.put(i, groupIdToInstancePoolMap.get(selectedGroups.get(i))); + } + return replicaIdToCandidateInstancesMap; + } +} diff --git a/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/constraint/replicagroup/NoReplicaGroupConstraint.java b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/constraint/replicagroup/NoReplicaGroupConstraint.java new file mode 100644 index 0000000..dd1d879 --- /dev/null +++ b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/constraint/replicagroup/NoReplicaGroupConstraint.java @@ -0,0 +1,13 @@ +package com.linkedin.pinot.controller.helix.core.instance.selection.constraint.replicagroup; + +import java.util.Map; +import java.util.Set; + + +public class NoReplicaGroupConstraint implements ReplicaGroupConstraint { + + @Override + public Map<Integer, Set<String>> apply(Map<Integer, Set<String>> groupIdToInstancePoolMap) { + return null; + } +} diff --git a/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/constraint/replicagroup/ReplicaGroupConstraint.java b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/constraint/replicagroup/ReplicaGroupConstraint.java new file mode 100644 index 0000000..86b8f3f --- /dev/null +++ b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/constraint/replicagroup/ReplicaGroupConstraint.java @@ -0,0 +1,16 @@ +package com.linkedin.pinot.controller.helix.core.instance.selection.constraint.replicagroup; + +import java.util.Map; +import java.util.Set; + + +public interface ReplicaGroupConstraint { + + /** + * Applies the replica group constraint, and returns a map from replica Id to candidate instances. + * + * @param groupIdToInstancePoolMap Map from group Id to instance pool + * @return Map from replica Id to candidate instances + */ + Map<Integer, Set<String>> apply(Map<Integer, Set<String>> groupIdToInstancePoolMap); +} diff --git a/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/result/SelectionResult.java b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/result/SelectionResult.java new file mode 100644 index 0000000..4fc664b --- /dev/null +++ b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/result/SelectionResult.java @@ -0,0 +1,32 @@ +package com.linkedin.pinot.controller.helix.core.instance.selection.result; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.Nullable; + + +public class SelectionResult { + private final Map<Integer, List<String>> _replicaIdToInstancesMap; + + public SelectionResult() { + _replicaIdToInstancesMap = new HashMap<>(); + } + + public SelectionResult(Map<Integer, List<String>> replicaIdToInstancesMap) { + _replicaIdToInstancesMap = replicaIdToInstancesMap; + } + + public int getNumReplicas() { + return _replicaIdToInstancesMap.size(); + } + + public List<String> getInstances(int replicaId) { + return _replicaIdToInstancesMap.get(replicaId); + } + + public void setInstances(int replicaId, List<String> instances) { + _replicaIdToInstancesMap.set(replicaId, instances); + } +} diff --git a/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/result/SelectionResultUtils.java b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/result/SelectionResultUtils.java new file mode 100644 index 0000000..dcddd92 --- /dev/null +++ b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/result/SelectionResultUtils.java @@ -0,0 +1,20 @@ +package com.linkedin.pinot.controller.helix.core.instance.selection.result; + +import java.util.Map; +import org.apache.helix.ZNRecord; +import org.apache.helix.store.zk.ZkHelixPropertyStore; + + +public class SelectionResultUtils { + private SelectionResultUtils() { + } + + public static Map<String, SelectionResult> readFromZK(ZkHelixPropertyStore<ZNRecord> propertyStore, String resource) { + throw new UnsupportedOperationException(); + } + + public static boolean writeToZK(ZkHelixPropertyStore<ZNRecord> propertyStore, String resource, + Map<String, SelectionResult> selectionResults) { + throw new UnsupportedOperationException(); + } +} diff --git a/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/strategy/SelectionStrategy.java b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/strategy/SelectionStrategy.java new file mode 100644 index 0000000..c462627 --- /dev/null +++ b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/instance/selection/strategy/SelectionStrategy.java @@ -0,0 +1,12 @@ +package com.linkedin.pinot.controller.helix.core.instance.selection.strategy; + +import com.linkedin.pinot.controller.helix.core.instance.InstanceRole; +import com.linkedin.pinot.controller.helix.core.instance.selection.result.SelectionResult; +import java.util.Map; +import java.util.Set; + + +public interface SelectionStrategy { + + SelectionResult selectInstances(Map<Integer, Set<String>> groupIdToInstancePoolMap, ) +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org For additional commands, e-mail: commits-h...@pinot.apache.org