All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.dasasian.chok.master.DefaultDistributionPolicy Maven / Gradle / Ivy

There is a newer version: 1.7
Show newest version
/**
 * Copyright (C) 2014 Dasasian ([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.dasasian.chok.master;

import com.dasasian.chok.util.CircularList;
import org.apache.log4j.Logger;

import java.util.*;

/**
 * Simple deploy policy which distributes the shards in round robin style.
* Following features are supported:
* - initial shard distribution
* - shard distribution when under replicated
* - shard removal when over-replicated
*
* Missing feature:
* - shard/node rebalancing
*
* TODO jz: node load rebalancing */ public class DefaultDistributionPolicy implements IDeployPolicy { private final static Logger LOG = Logger.getLogger(DefaultDistributionPolicy.class); public Map> createDistributionPlan(final Map> currentShard2NodesMap, final Map> currentNode2ShardsMap, List aliveNodes, final int replicationLevel) { if (aliveNodes.size() == 0) { throw new IllegalArgumentException("no alive nodes to distribute to"); } Set shards = currentShard2NodesMap.keySet(); for (String shard : shards) { Set assignedNodes = new HashSet<>(replicationLevel); int neededDeployments = replicationLevel - countValues(currentShard2NodesMap, shard); assignedNodes.addAll(currentShard2NodesMap.get(shard)); // now assign new nodes based on round robin algorithm sortAfterFreeCapacity(aliveNodes, currentNode2ShardsMap); CircularList roundRobinNodes = new CircularList<>(aliveNodes); neededDeployments = chooseNewNodes(currentNode2ShardsMap, roundRobinNodes, shard, assignedNodes, neededDeployments); if (neededDeployments > 0) { LOG.warn("cannot replicate shard '" + shard + "' " + replicationLevel + " times, cause only " + roundRobinNodes.size() + " nodes connected"); } else if (neededDeployments < 0) { LOG.info("found shard '" + shard + "' over-replicated"); // TODO jz: maybe we should add a configurable threshold tha e.g. 10% // over replication is ok ? removeOverreplicatedShards(currentShard2NodesMap, currentNode2ShardsMap, shard, neededDeployments); } } return currentNode2ShardsMap; } private void sortAfterFreeCapacity(List aliveNodes, final Map> node2ShardsMap) { Collections.sort(aliveNodes, new Comparator() { @Override public int compare(String node1, String node2) { int size1 = node2ShardsMap.get(node1).size(); int size2 = node2ShardsMap.get(node2).size(); return (size1 < size2 ? -1 : (size1 == size2 ? 0 : 1)); } }); } private int chooseNewNodes(final Map> currentNode2ShardsMap, CircularList roundRobinNodes, String shard, Set assignedNodes, int neededDeployments) { String tailNode = roundRobinNodes.getTail(); String currentNode = null; while (neededDeployments > 0 && !tailNode.equals(currentNode)) { currentNode = roundRobinNodes.getNext(); if (!assignedNodes.contains(currentNode)) { if (LOG.isDebugEnabled()) { LOG.debug("assign " + shard + " to " + currentNode); } currentNode2ShardsMap.get(currentNode).add(shard); assignedNodes.add(currentNode); neededDeployments--; } } return neededDeployments; } private void removeOverreplicatedShards(final Map> currentShard2NodesMap, final Map> currentNode2ShardsMap, String shard, int neededDeployments) { while (neededDeployments < 0) { int maxShardServingCount = 0; String maxShardServingNode = null; List nodeNames = currentShard2NodesMap.get(shard); for (String node : nodeNames) { int shardCount = countValues(currentNode2ShardsMap, node); if (shardCount > maxShardServingCount) { maxShardServingCount = shardCount; maxShardServingNode = node; } } currentNode2ShardsMap.get(maxShardServingNode).remove(shard); neededDeployments++; } } private int countValues(Map> multiMap, String key) { List list = multiMap.get(key); if (list == null) { return 0; } return list.size(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy