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 0cec0992433d1031a033ab15a1800aef196fd3d2
Author: Xiaotian (Jackie) Jiang <[email protected]>
AuthorDate: Fri Nov 30 20:32:34 2018 -0800

    Initial commit on the interfaces
---
 .../pinot/common/config/AssignmentConfig.java      |  19 ++++
 .../core/assignment/instance/InstanceRole.java     |  20 ++++
 .../instance/InstanceSelectionResult.java          |  45 ++++++++
 .../instance/InstanceSelectionResultUtils.java     |  38 +++++++
 .../instance/InstanceSelectionStrategy.java        |  26 +++++
 .../core/assignment/instance/InstanceTags.java     | 116 ++++++++++++++++++++
 .../assignment/instance/InstanceTagsUtils.java     |  42 ++++++++
 .../instance/constraint/InstanceConstraint.java    |  30 ++++++
 .../constraint/NumInstancesConstraint.java         |  30 ++++++
 .../constraint/ReplicaGroupInstanceConstraint.java |  30 ++++++
 .../TagExactMatchInstanceConstraint.java           |  48 +++++++++
 .../segment/SegmentAssignmentStrategy.java         |  34 ++++++
 .../core/assignment/instance/InstanceTagsTest.java | 117 +++++++++++++++++++++
 13 files changed, 595 insertions(+)

diff --git 
a/pinot-common/src/main/java/com/linkedin/pinot/common/config/AssignmentConfig.java
 
b/pinot-common/src/main/java/com/linkedin/pinot/common/config/AssignmentConfig.java
new file mode 100644
index 0000000..51093dd
--- /dev/null
+++ 
b/pinot-common/src/main/java/com/linkedin/pinot/common/config/AssignmentConfig.java
@@ -0,0 +1,19 @@
+/**
+ * Copyright (C) 2014-2018 LinkedIn Corp. ([email protected])
+ *
+ * Licensed 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.
+ */
+package com.linkedin.pinot.common.config;
+
+public class AssignmentConfig {
+}
diff --git 
a/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/InstanceRole.java
 
b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/InstanceRole.java
new file mode 100644
index 0000000..8221a3c
--- /dev/null
+++ 
b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/InstanceRole.java
@@ -0,0 +1,20 @@
+/**
+ * Copyright (C) 2014-2018 LinkedIn Corp. ([email protected])
+ *
+ * Licensed 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.
+ */
+package com.linkedin.pinot.controller.helix.core.assignment.instance;
+
+public enum InstanceRole {
+  CONTROLLER, BROKER, SERVER, OFFLINE, REALTIME, MINION
+}
diff --git 
a/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/InstanceSelectionResult.java
 
b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/InstanceSelectionResult.java
new file mode 100644
index 0000000..5e12f6c
--- /dev/null
+++ 
b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/InstanceSelectionResult.java
@@ -0,0 +1,45 @@
+/**
+ * Copyright (C) 2014-2018 LinkedIn Corp. ([email protected])
+ *
+ * Licensed 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.
+ */
+package com.linkedin.pinot.controller.helix.core.assignment.instance;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+public class InstanceSelectionResult {
+  private final Map<Integer, List<String>> _replicaIdToInstancesMap;
+
+  public InstanceSelectionResult() {
+    _replicaIdToInstancesMap = new HashMap<>();
+  }
+
+  public InstanceSelectionResult(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.put(replicaId, instances);
+  }
+}
diff --git 
a/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/InstanceSelectionResultUtils.java
 
b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/InstanceSelectionResultUtils.java
new file mode 100644
index 0000000..1e22e58
--- /dev/null
+++ 
b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/InstanceSelectionResultUtils.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) 2014-2018 LinkedIn Corp. ([email protected])
+ *
+ * Licensed 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.
+ */
+package com.linkedin.pinot.controller.helix.core.assignment.instance;
+
+import java.util.Map;
+import org.apache.helix.ZNRecord;
+import org.apache.helix.store.zk.ZkHelixPropertyStore;
+
+
+public class InstanceSelectionResultUtils {
+  private InstanceSelectionResultUtils() {
+  }
+
+  public static Map<InstanceRole, InstanceSelectionResult> 
readFromZK(ZkHelixPropertyStore<ZNRecord> propertyStore,
+      String resource) {
+    //TODO: implement it
+    throw new UnsupportedOperationException();
+  }
+
+  public static boolean writeToZK(ZkHelixPropertyStore<ZNRecord> 
propertyStore, String resource,
+      Map<InstanceRole, InstanceSelectionResult> instanceSelectionResults) {
+    //TODO: implement it
+    throw new UnsupportedOperationException();
+  }
+}
diff --git 
a/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/InstanceSelectionStrategy.java
 
b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/InstanceSelectionStrategy.java
new file mode 100644
index 0000000..7ecd234
--- /dev/null
+++ 
b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/InstanceSelectionStrategy.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (C) 2014-2018 LinkedIn Corp. ([email protected])
+ *
+ * Licensed 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.
+ */
+package com.linkedin.pinot.controller.helix.core.assignment.instance;
+
+import com.linkedin.pinot.common.config.AssignmentConfig;
+import javax.annotation.Nullable;
+
+
+public interface InstanceSelectionStrategy {
+
+  InstanceSelectionResult selectInstances(AssignmentConfig assignmentConfig,
+      @Nullable InstanceSelectionResult existingSelectionResult);
+}
diff --git 
a/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/InstanceTags.java
 
b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/InstanceTags.java
new file mode 100644
index 0000000..a242e85
--- /dev/null
+++ 
b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/InstanceTags.java
@@ -0,0 +1,116 @@
+/**
+ * Copyright (C) 2014-2018 LinkedIn Corp. ([email protected])
+ *
+ * Licensed 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.
+ */
+package com.linkedin.pinot.controller.helix.core.assignment.instance;
+
+import com.google.common.base.Preconditions;
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.Nullable;
+import org.apache.commons.lang3.EnumUtils;
+import org.apache.commons.lang3.StringUtils;
+
+
+public class InstanceTags {
+  private static final char TAG_DELIMITER = ';';
+  private static final char KEY_VALUE_DELIMITER = ':';
+  private static final char LEGACY_DELIMITER = '_';
+  private static final String UNTAGGED = "untagged";
+
+  public static final String ROLE_KEY = "role";
+  public static final String POOL_NAME_KEY = "poolName";
+  public static final String GROUP_ID_KEY = "groupId";
+
+  private final String _instanceName;
+  private final Map<String, String> _tags;
+
+  public InstanceTags(String instanceName, Map<String, String> tags) {
+    _instanceName = instanceName;
+    _tags = tags;
+  }
+
+  public static InstanceTags fromHelixTag(String instanceName, String 
helixTag) {
+    Map<String, String> tags = new HashMap<>();
+
+    // For backward-compatible
+    if (helixTag.indexOf(KEY_VALUE_DELIMITER) == -1) {
+      int delimiterIndex = helixTag.lastIndexOf(LEGACY_DELIMITER);
+      Preconditions.checkArgument(delimiterIndex != -1, "Invalid Helix tag: " 
+ helixTag);
+
+      String part1 = helixTag.substring(0, delimiterIndex);
+      String part2 = helixTag.substring(delimiterIndex + 1);
+      if (part2.equals(UNTAGGED)) {
+        // Untagged instances, e.g. broker_untagged, server_untagged, 
minion_untagged
+        InstanceRole role = InstanceRole.valueOf(part1.toUpperCase());
+        tags.put(ROLE_KEY, role.toString());
+        tags.put(POOL_NAME_KEY, UNTAGGED);
+        tags.put(GROUP_ID_KEY, Integer.toString(0));
+      } else {
+        // Tagged instances, e.g. poolName_OFFLINE, poolName_REALTIME, 
poolName_BROKER
+        String poolName = helixTag.substring(0, delimiterIndex);
+        String role = helixTag.substring(delimiterIndex + 1);
+        Preconditions.checkArgument(EnumUtils.isValidEnum(InstanceRole.class, 
role), "Invalid role: " + role);
+
+        tags.put(ROLE_KEY, role);
+        tags.put(POOL_NAME_KEY, poolName);
+        tags.put(GROUP_ID_KEY, Integer.toString(0));
+      }
+    } else {
+      // E.g. role:BROKER;poolName:brokerPool;groupId:0
+      String[] pairs = StringUtils.split(helixTag, TAG_DELIMITER);
+      for (String pair : pairs) {
+        String[] keyAndValue = StringUtils.split(pair, KEY_VALUE_DELIMITER);
+        Preconditions.checkArgument(keyAndValue.length == 2, "Invalid 
ket-value pair: " + pair);
+        tags.put(keyAndValue[0], keyAndValue[1]);
+      }
+    }
+
+    return new InstanceTags(instanceName, tags);
+  }
+
+  public static String toHelixTag(InstanceTags instanceTags) {
+    StringBuilder stringBuilder = new StringBuilder();
+    for (Map.Entry<String, String> entry : instanceTags._tags.entrySet()) {
+      
stringBuilder.append(entry.getKey()).append(KEY_VALUE_DELIMITER).append(entry.getValue()).append(TAG_DELIMITER);
+    }
+    return stringBuilder.substring(0, stringBuilder.length() - 1);
+  }
+
+  public String getInstanceName() {
+    return _instanceName;
+  }
+
+  @Nullable
+  public String getTag(String key) {
+    return _tags.get(key);
+  }
+
+  @Override
+  public int hashCode() {
+    return 37 * _instanceName.hashCode() + _tags.hashCode();
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (this == obj) {
+      return true;
+    }
+    if (obj instanceof InstanceTags) {
+      InstanceTags that = (InstanceTags) obj;
+      return _instanceName.equals(that._instanceName) && 
_tags.equals(that._tags);
+    }
+    return false;
+  }
+}
diff --git 
a/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/InstanceTagsUtils.java
 
b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/InstanceTagsUtils.java
new file mode 100644
index 0000000..df7b213
--- /dev/null
+++ 
b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/InstanceTagsUtils.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (C) 2014-2018 LinkedIn Corp. ([email protected])
+ *
+ * Licensed 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.
+ */
+package com.linkedin.pinot.controller.helix.core.assignment.instance;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.apache.helix.model.InstanceConfig;
+
+
+public class InstanceTagsUtils {
+  private InstanceTagsUtils() {
+  }
+
+  public static Set<InstanceTags> extractAllInstanceTags(List<InstanceConfig> 
instanceConfigs) {
+    Set<InstanceTags> instanceTagsSet = new HashSet<>();
+    for (InstanceConfig instanceConfig : instanceConfigs) {
+      // Skip disabled instances
+      if (!instanceConfig.getInstanceEnabled()) {
+        continue;
+      }
+      String instanceName = instanceConfig.getInstanceName();
+      for (String tag : instanceConfig.getTags()) {
+        instanceTagsSet.add(InstanceTags.fromHelixTag(instanceName, tag));
+      }
+    }
+    return instanceTagsSet;
+  }
+}
diff --git 
a/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/constraint/InstanceConstraint.java
 
b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/constraint/InstanceConstraint.java
new file mode 100644
index 0000000..c391bbd
--- /dev/null
+++ 
b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/constraint/InstanceConstraint.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (C) 2014-2018 LinkedIn Corp. ([email protected])
+ *
+ * Licensed 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.
+ */
+package 
com.linkedin.pinot.controller.helix.core.assignment.instance.constraint;
+
+import 
com.linkedin.pinot.controller.helix.core.assignment.instance.InstanceTags;
+import java.util.Map;
+import java.util.Set;
+
+
+public interface InstanceConstraint {
+  int UNASSIGNED_REPLICA_ID = -1;
+
+  /**
+   * Applies the instance constraint, and returns a map from replica Id to 
satisfied instances.
+   */
+  Map<Integer, Set<InstanceTags>> apply(Map<Integer, Set<InstanceTags>> 
replicaIdToInstanceTagsMap);
+}
diff --git 
a/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/constraint/NumInstancesConstraint.java
 
b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/constraint/NumInstancesConstraint.java
new file mode 100644
index 0000000..713d8c0
--- /dev/null
+++ 
b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/constraint/NumInstancesConstraint.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (C) 2014-2018 LinkedIn Corp. ([email protected])
+ *
+ * Licensed 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.
+ */
+package 
com.linkedin.pinot.controller.helix.core.assignment.instance.constraint;
+
+import 
com.linkedin.pinot.controller.helix.core.assignment.instance.InstanceTags;
+import java.util.Map;
+import java.util.Set;
+
+
+public class NumInstancesConstraint implements InstanceConstraint {
+
+  @Override
+  public Map<Integer, Set<InstanceTags>> apply(Map<Integer, Set<InstanceTags>> 
replicaIdToInstanceTagsMap) {
+    //TODO: implement it
+    throw new UnsupportedOperationException();
+  }
+}
diff --git 
a/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/constraint/ReplicaGroupInstanceConstraint.java
 
b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/constraint/ReplicaGroupInstanceConstraint.java
new file mode 100644
index 0000000..1efdf21
--- /dev/null
+++ 
b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/constraint/ReplicaGroupInstanceConstraint.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (C) 2014-2018 LinkedIn Corp. ([email protected])
+ *
+ * Licensed 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.
+ */
+package 
com.linkedin.pinot.controller.helix.core.assignment.instance.constraint;
+
+import 
com.linkedin.pinot.controller.helix.core.assignment.instance.InstanceTags;
+import java.util.Map;
+import java.util.Set;
+
+
+public class ReplicaGroupInstanceConstraint implements InstanceConstraint {
+
+  @Override
+  public Map<Integer, Set<InstanceTags>> apply(Map<Integer, Set<InstanceTags>> 
replicaIdToInstanceTagsMap) {
+    //TODO: implement it
+    throw new UnsupportedOperationException();
+  }
+}
diff --git 
a/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/constraint/TagExactMatchInstanceConstraint.java
 
b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/constraint/TagExactMatchInstanceConstraint.java
new file mode 100644
index 0000000..c6e79b8
--- /dev/null
+++ 
b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/instance/constraint/TagExactMatchInstanceConstraint.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright (C) 2014-2018 LinkedIn Corp. ([email protected])
+ *
+ * Licensed 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.
+ */
+package 
com.linkedin.pinot.controller.helix.core.assignment.instance.constraint;
+
+import 
com.linkedin.pinot.controller.helix.core.assignment.instance.InstanceTags;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+
+public class TagExactMatchInstanceConstraint implements InstanceConstraint {
+  private final Map<String, String> _exactMatchTags;
+
+  public TagExactMatchInstanceConstraint(Map<String, String> exactMatchTags) {
+    _exactMatchTags = exactMatchTags;
+  }
+
+  @Override
+  public Map<Integer, Set<InstanceTags>> apply(Map<Integer, Set<InstanceTags>> 
replicaIdToInstanceTagsMap) {
+    for (Set<InstanceTags> instanceTagsSet : 
replicaIdToInstanceTagsMap.values()) {
+      Iterator<InstanceTags> iterator = instanceTagsSet.iterator();
+      while (iterator.hasNext()) {
+        InstanceTags instanceTags = iterator.next();
+        for (Map.Entry<String, String> entry : _exactMatchTags.entrySet()) {
+          String tag = instanceTags.getTag(entry.getKey());
+          if (!entry.getValue().equals(tag)) {
+            iterator.remove();
+            break;
+          }
+        }
+      }
+    }
+    return replicaIdToInstanceTagsMap;
+  }
+}
diff --git 
a/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/segment/SegmentAssignmentStrategy.java
 
b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/segment/SegmentAssignmentStrategy.java
new file mode 100644
index 0000000..ab1de3c
--- /dev/null
+++ 
b/pinot-controller/src/main/java/com/linkedin/pinot/controller/helix/core/assignment/segment/SegmentAssignmentStrategy.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (C) 2014-2018 LinkedIn Corp. ([email protected])
+ *
+ * Licensed 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.
+ */
+package com.linkedin.pinot.controller.helix.core.assignment.segment;
+
+import com.linkedin.pinot.common.config.AssignmentConfig;
+import com.linkedin.pinot.common.metadata.segment.SegmentZKMetadata;
+import 
com.linkedin.pinot.controller.helix.core.assignment.instance.InstanceSelectionResult;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Nullable;
+
+
+public interface SegmentAssignmentStrategy {
+
+  Map<String, List<String>> assignNewSegment(AssignmentConfig 
assignmentConfig, SegmentZKMetadata segmentZKMetadata,
+      InstanceSelectionResult selectedInstances, @Nullable Map<String, 
List<String>> existingAssignmentResult);
+
+  Map<String, List<String>> rebalanceSegments(AssignmentConfig 
assignmentConfig,
+      List<SegmentZKMetadata> segmentZKMetadataList, InstanceSelectionResult 
selectedInstances,
+      Map<String, List<String>> existingAssignmentResult);
+}
diff --git 
a/pinot-controller/src/test/java/com/linkedin/pinot/controller/helix/core/assignment/instance/InstanceTagsTest.java
 
b/pinot-controller/src/test/java/com/linkedin/pinot/controller/helix/core/assignment/instance/InstanceTagsTest.java
new file mode 100644
index 0000000..a1ad642
--- /dev/null
+++ 
b/pinot-controller/src/test/java/com/linkedin/pinot/controller/helix/core/assignment/instance/InstanceTagsTest.java
@@ -0,0 +1,117 @@
+/**
+ * Copyright (C) 2014-2018 LinkedIn Corp. ([email protected])
+ *
+ * Licensed 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.
+ */
+package com.linkedin.pinot.controller.helix.core.assignment.instance;
+
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.*;
+
+
+public class InstanceTagsTest {
+
+  @Test
+  public void testUntaggedInstance() {
+    InstanceTags instanceTags = InstanceTags.fromHelixTag("instance", 
"controller_untagged");
+    assertEquals(instanceTags.getInstanceName(), "instance");
+    assertEquals(instanceTags.getTag(InstanceTags.ROLE_KEY), 
InstanceRole.CONTROLLER.toString());
+    assertEquals(instanceTags.getTag(InstanceTags.POOL_NAME_KEY), "untagged");
+    assertEquals(instanceTags.getTag(InstanceTags.GROUP_ID_KEY), "0");
+
+    instanceTags = InstanceTags.fromHelixTag("instance", "broker_untagged");
+    assertEquals(instanceTags.getInstanceName(), "instance");
+    assertEquals(instanceTags.getTag(InstanceTags.ROLE_KEY), 
InstanceRole.BROKER.toString());
+    assertEquals(instanceTags.getTag(InstanceTags.POOL_NAME_KEY), "untagged");
+    assertEquals(instanceTags.getTag(InstanceTags.GROUP_ID_KEY), "0");
+
+    instanceTags = InstanceTags.fromHelixTag("instance", "server_untagged");
+    assertEquals(instanceTags.getInstanceName(), "instance");
+    assertEquals(instanceTags.getTag(InstanceTags.ROLE_KEY), 
InstanceRole.SERVER.toString());
+    assertEquals(instanceTags.getTag(InstanceTags.POOL_NAME_KEY), "untagged");
+    assertEquals(instanceTags.getTag(InstanceTags.GROUP_ID_KEY), "0");
+
+    instanceTags = InstanceTags.fromHelixTag("instance", "minion_untagged");
+    assertEquals(instanceTags.getInstanceName(), "instance");
+    assertEquals(instanceTags.getTag(InstanceTags.ROLE_KEY), 
InstanceRole.MINION.toString());
+    assertEquals(instanceTags.getTag(InstanceTags.POOL_NAME_KEY), "untagged");
+    assertEquals(instanceTags.getTag(InstanceTags.GROUP_ID_KEY), "0");
+  }
+
+  @Test
+  public void testLegacyHelixTag() {
+    InstanceTags instanceTags = InstanceTags.fromHelixTag("instance", 
"controllerPool_CONTROLLER");
+    assertEquals(instanceTags.getInstanceName(), "instance");
+    assertEquals(instanceTags.getTag(InstanceTags.ROLE_KEY), 
InstanceRole.CONTROLLER.toString());
+    assertEquals(instanceTags.getTag(InstanceTags.POOL_NAME_KEY), 
"controllerPool");
+    assertEquals(instanceTags.getTag(InstanceTags.GROUP_ID_KEY), "0");
+
+    instanceTags = InstanceTags.fromHelixTag("instance", "brokerPool_BROKER");
+    assertEquals(instanceTags.getInstanceName(), "instance");
+    assertEquals(instanceTags.getTag(InstanceTags.ROLE_KEY), 
InstanceRole.BROKER.toString());
+    assertEquals(instanceTags.getTag(InstanceTags.POOL_NAME_KEY), 
"brokerPool");
+    assertEquals(instanceTags.getTag(InstanceTags.GROUP_ID_KEY), "0");
+
+    instanceTags = InstanceTags.fromHelixTag("instance", 
"offlineServerPool_OFFLINE");
+    assertEquals(instanceTags.getInstanceName(), "instance");
+    assertEquals(instanceTags.getTag(InstanceTags.ROLE_KEY), 
InstanceRole.OFFLINE.toString());
+    assertEquals(instanceTags.getTag(InstanceTags.POOL_NAME_KEY), 
"offlineServerPool");
+    assertEquals(instanceTags.getTag(InstanceTags.GROUP_ID_KEY), "0");
+
+    instanceTags = InstanceTags.fromHelixTag("instance", 
"realtimeServerPool_REALTIME");
+    assertEquals(instanceTags.getInstanceName(), "instance");
+    assertEquals(instanceTags.getTag(InstanceTags.ROLE_KEY), 
InstanceRole.REALTIME.toString());
+    assertEquals(instanceTags.getTag(InstanceTags.POOL_NAME_KEY), 
"realtimeServerPool");
+    assertEquals(instanceTags.getTag(InstanceTags.GROUP_ID_KEY), "0");
+
+    instanceTags = InstanceTags.fromHelixTag("instance", "minionPool_MINION");
+    assertEquals(instanceTags.getInstanceName(), "instance");
+    assertEquals(instanceTags.getTag(InstanceTags.ROLE_KEY), 
InstanceRole.MINION.toString());
+    assertEquals(instanceTags.getTag(InstanceTags.POOL_NAME_KEY), 
"minionPool");
+    assertEquals(instanceTags.getTag(InstanceTags.GROUP_ID_KEY), "0");
+  }
+
+  @Test
+  public void testKeyValuePairs() {
+    InstanceTags instanceTags = InstanceTags.fromHelixTag("instance", 
"key1:value1;key2:value2;key3:value3");
+    assertEquals(instanceTags.getInstanceName(), "instance");
+    assertEquals(instanceTags.getTag("key1"), "value1");
+    assertEquals(instanceTags.getTag("key2"), "value2");
+    assertEquals(instanceTags.getTag("key3"), "value3");
+  }
+
+  @Test
+  public void testIllegalHelixTag() {
+    try {
+      InstanceTags.fromHelixTag("instance", "illegalRole_untagged");
+      fail();
+    } catch (IllegalArgumentException e) {
+      // Expected
+    }
+
+    try {
+      InstanceTags.fromHelixTag("instance", "somePool_ILLEGALROLE");
+      fail();
+    } catch (IllegalArgumentException e) {
+      // Expected
+    }
+
+    try {
+      InstanceTags.fromHelixTag("instance", 
"illegal:key:value:pair;key:value");
+      fail();
+    } catch (IllegalArgumentException e) {
+      // Expected
+    }
+  }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to