/** * Copyright (C) 2014-2016 LinkedIn Corp. (pinot-core@linkedin.com) * * 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.transport.config; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.configuration.Configuration; import com.linkedin.pinot.common.response.ServerInstance; import com.linkedin.pinot.transport.common.SegmentId; import com.linkedin.pinot.transport.common.SegmentIdSet; /** * Maintains static routing config of servers to partitions * * Relevant config for illustration: * * pinot.broker.routing.midas.numPartitions=2 * pinot.broker.routing.midas.serversForPartitions.default=localhost:9099 * pinot.broker.routing.midas.serversForPartitions.0=localhost:9099 * pinot.broker.routing.midas.serversForPartitions.1=localhost:9099 * * */ public class PerTableRoutingConfig { // Keys to load config private static final String NUM_NODES_PER_REPLICA = "numNodesPerReplica"; private static final String SERVERS_FOR_NODE = "serversForNode"; private static final String DEFAULT_SERVERS_FOR_NODE = "default"; private final Configuration _tableCfg; private int _numNodes; private List<ServerInstance> _defaultServers; private final Map<Integer, List<ServerInstance>> _nodeToInstancesMap; public PerTableRoutingConfig(Configuration cfg) { _tableCfg = cfg; _nodeToInstancesMap = new HashMap<Integer, List<ServerInstance>>(); _defaultServers = new ArrayList<ServerInstance>(); loadConfig(); } @SuppressWarnings("unchecked") private void loadConfig() { if (null == _tableCfg) { return; } _nodeToInstancesMap.clear(); _numNodes = _tableCfg.getInt(NUM_NODES_PER_REPLICA); for (int i = 0; i < _numNodes; i++) { List<String> servers = _tableCfg.getList(getKey(SERVERS_FOR_NODE, i + "")); if ((null != servers) && (!servers.isEmpty())) { List<ServerInstance> servers2 = getServerInstances(servers); _nodeToInstancesMap.put(i, servers2); } } List<String> servers = _tableCfg.getList(getKey(SERVERS_FOR_NODE, DEFAULT_SERVERS_FOR_NODE)); if ((null != servers) && (!servers.isEmpty())) { _defaultServers = getServerInstances(servers); } } private String getKey(String prefix, String suffix) { String s = prefix + "." + suffix; return s; } public int getNumNodes() { return _numNodes; } public List<ServerInstance> getDefaultServers() { return _defaultServers; } // // /** // * Builds a map needed for routing the partitions in the partition-group passed. // * There could be different set of servers for each partition in the passed partition-group. // * // * @param pg segmentSet for which the routing map needs to be built. // * @return // */ // public Map<SegmentIdSet, List<ServerInstance>> buildRequestRoutingMap() { // Map<SegmentIdSet, List<ServerInstance>> resultMap = new HashMap<SegmentIdSet, List<ServerInstance>>(); // // /** // * NOTE: After we removed the concept of partition, this needed rewriting. // * For now, The File-based routing config maps nodeIds to Instances instead of segments to instances. // * This is because, it becomes difficult for configuring all segments in routing config. Instead, // * we configure the number of nodes that constitute a replica-set. For each node, different instances // * (as comma-seperated list) is provided. we pick one instance from each node. // * // */ // for (Entry<Integer, List<ServerInstance>> e : _nodeToInstancesMap.entrySet()) { // SegmentId id = new SegmentId("" + e.getKey()); // SegmentIdSet idSet = new SegmentIdSet(); // idSet.addSegment(id); // resultMap.put(idSet, e.getValue()); // } // // // Add default // SegmentId id = new SegmentId("default"); // SegmentIdSet idSet = new SegmentIdSet(); // idSet.addSegment(id); // resultMap.put(idSet, _defaultServers); // return resultMap; // } /** * Builds a map needed for routing the partitions in the partition-group passed. * There could be different set of servers for each partition in the passed partition-group. * * @return */ public Map<ServerInstance, SegmentIdSet> buildRequestRoutingMap() { Map<ServerInstance, SegmentIdSet> resultMap = new HashMap<ServerInstance, SegmentIdSet>(); for (ServerInstance serverInstance : _defaultServers) { SegmentId id = new SegmentId("default"); SegmentIdSet idSet = new SegmentIdSet(); idSet.addSegment(id); resultMap.put(serverInstance, idSet); } return resultMap; } /** * Generate server instances from their string representations * @param servers * @return */ private static List<ServerInstance> getServerInstances(List<String> servers) { List<ServerInstance> servers2 = new ArrayList<ServerInstance>(); for (String s : servers) { servers2.add(new ServerInstance(s)); } return servers2; } public Map<Integer, List<ServerInstance>> getNodeToInstancesMap() { return _nodeToInstancesMap; } @Override public String toString() { return "PerTableRoutingConfig [_tableCfg=" + _tableCfg + ", _numNodes=" + _numNodes + ", _defaultServers=" + _defaultServers + ", _nodeToInstancesMap=" + _nodeToInstancesMap + "]"; } }