Files
scandocs/uni/masterarbeit/source/moversight/ms/placingstrategy/DynamicPeerPlacingStrategy.cc
2014-06-30 13:58:10 +02:00

496 lines
19 KiB
C++

/*
* File: DynamicPeerPlacingStrategy.cc
* Author: stubbfel
*
* Created on 13. Juli 2013, 14:37
*/
#include "DynamicPeerPlacingStrategy.h"
#include "metric/ClusterSizeBalanceMetric.h"
#include "metric/ResourceValueBalanceMetric.h"
#include "metric/ResourceClusterSizeBalanceMetric.h"
#include "ms/MemberRegister.h"
#include "common/Exception.h"
#include "ms/PeerState.h"
#include "Dispatcher.h"
#include <math.h>
#define DEBUG(msg) MOV_DEBUG<<" "<<msg<<std::endl;
namespace ubeeme {
namespace moversight {
const size_t DynamicPeerPlacingStrategy::ONE_MORE_PEER_OFFSET;
const size_t DynamicPeerPlacingStrategy::CURRENTPEERCOUNT_OFFSET;
/**
* @brief Constructor
* @param aRegister - reference of a certain memberregister
* @param (optional) metricType - type of the balance metric, default is the BALANCEMETRIC_CLUSTERSIZE
*/
DynamicPeerPlacingStrategy::DynamicPeerPlacingStrategy(MemberRegister& aRegister, PeerPlacingStrategyMetricType metricType) : PeerPlacingStrategy(aRegister), metric(NULL) {
setPlacingMetric(metricType);
}
/**
* @brief Copy-Constructor
* @param other : DynamicPeerPlacingStrategy
*/
DynamicPeerPlacingStrategy::DynamicPeerPlacingStrategy(const DynamicPeerPlacingStrategy & other) : PeerPlacingStrategy(other.memRegister) {
operator=(other);
}
/** Assignment operator
* @param other Object to assign from
* @return A reference to this
*/
DynamicPeerPlacingStrategy &
DynamicPeerPlacingStrategy::operator=(const DynamicPeerPlacingStrategy& other) {
if (this == &other) {
return *this;
}
metric = other.metric->clone();
metricType = other.metricType;
return *this;
}
/**
* Destructor
*/
DynamicPeerPlacingStrategy::~DynamicPeerPlacingStrategy() {
delete metric;
metric = NULL;
}
/**
* @brief overrides placePeer from @see PeerPlacingStrategy
* @param peer - peer which has to be insert in the network
*/
void
DynamicPeerPlacingStrategy::placePeer(Peer & peer) {
ClusterID clusterID;
const ClusterList & clusterList = memRegister.getClusters();
// check if a new cluster is necessary
if (isNewClusterRequired(clusterList, ONE_MORE_PEER_OFFSET)) {
clusterID = memRegister.createCluster();
}
else {
const Cluster & peerLocation = determinePeerLocation(clusterList, peer);
clusterID = peerLocation.getClusterID();
}
memRegister.addPeer(peer, clusterID);
const Cluster & cluster = memRegister.getClusters().getByID(clusterID);
PeerID oldMasterID = cluster.getMasterID();
PeerID masterID = metric->getBestMasterID(cluster);
if (masterID != oldMasterID) {
memRegister.selectMaster(clusterID, masterID);
}
balanceNetwork();
}
/**
* @brief overrides getClusterID from @see PeerPlacingStrategy
* @param pId - id of the peer
* @param srcClusterId - id of the source cluster
* @param destClusterId - id of the destination cluster
* @return True, if the move possible, false otherwise.
*/
bool
DynamicPeerPlacingStrategy::isMovePeerPossible(PeerID pId, ClusterID srcClusterId, ClusterID destClusterId) {
const ClusterList & clusterList = memRegister.getClusters();
if (clusterList.contains(srcClusterId) && clusterList.contains(destClusterId) && memRegister.contains(pId)) {
return true;
}
return false;
}
/**
* @brief overides getClusterID from @see PeerPlacingStrategy
*/
ClusterID
DynamicPeerPlacingStrategy::getClusterID() {
return memRegister.getLocalPeer().getClusterID();
}
/**
* @brief Method determine the location(cluster) of a peer
* @param clusterList - list of possible peer locations
* @param peer - peer which look for new location
* @return Cluster - possible new location of the peer
*/
Cluster
DynamicPeerPlacingStrategy::determinePeerLocation(const ClusterList & clusterList, Peer & peer) const {
// creates and sort cluster lists
metric->setupMetric(clusterList);
ClusterID clusterID = metric->getBestClusterIDForNewPeer();
return clusterList.getByID(clusterID);
}
/**
* @brief overrides determinePeerLocation from @see PeerPlacingStrategy. This class dont use this method
* @param csList The current group situation, described as cluster density.
* @return A cluster size object, which describes the best cluster to store the peer.
* The size of the cluster size object describes the situation before performing the peer placement.
*/
ClusterSize
DynamicPeerPlacingStrategy::determinePeerLocation(ClusterSizeList & csList) {
return csList.get(0);
}
/**
* @brief overrides determinePossibleNewMaster from @see PeerPlacingStrategy
* @param cID - id of the cluster, which look for a new Master
* @return Id of the new Master
*/
PeerID
DynamicPeerPlacingStrategy::determinePossibleNewMaster(ClusterID cID) {
const Cluster & cluster = memRegister.getCluster(cID);
PeerID masterID = cluster.getMasterID();
if (cluster.size() > BalanceMetric::SINGLEPEER_CLUSTER) {
// remove old master
Cluster workCopy(cluster);
workCopy.removePeer(masterID);
PeerID newMasterID = metric->getBestMasterID(workCopy);
if (newMasterID != UNDEFINED_PEER_ID) {
return newMasterID;
}
}
return masterID;
}
/**
* @brief method calculate the optimal Count of the froup depends of the peercount
* @param peerCount, peer count of a group
*/
size_t
DynamicPeerPlacingStrategy::calcOptimalClusterCount(size_t peerCount) const {
return static_cast<int> (sqrt(peerCount) + BalanceMetric::ROUND_HALF_UP);
}
/**
* @brief Method calculate if an new cluster is necessary
* @param clusterList - list of clusters
* @param peerCountOffset - useful, if for you want to know is a new cluster
* nessaccery when i add 2 more peer.
* @return true if a new cluster is necessary , otherwise false
*/
bool
DynamicPeerPlacingStrategy::isNewClusterRequired(const ClusterList & clusterList, size_t peerCountOffset) const {
// calc cluster and peercount
size_t peerCount = ClusterSizeBalanceMetric::calcPeerCount(clusterList) + peerCountOffset;
size_t clusterCount = clusterList.size();
// calc best cluster count
size_t optClusterCount = calcOptimalClusterCount(peerCount);
if (clusterCount == BalanceMetric::EMPTY_CLUSTER || optClusterCount > clusterCount) {
return true;
}
return false;
}
/**
* @brief Method calculute if its too many cluster in the clusternetwork
* @param clusterList - list of clusters
* @return true, if to many cluster in the clusterlist, otherwise false
*/
bool
DynamicPeerPlacingStrategy::isTooManyCluster(const ClusterList & clusterList) const {
// calc cluster and peercount
size_t peerCount = ClusterSizeBalanceMetric::calcPeerCount(clusterList);
size_t clusterCount = clusterList.size();
// calc best cluster count
size_t optClusterCount = calcOptimalClusterCount(peerCount);
if (optClusterCount < clusterCount) {
return true;
}
return false;
}
/**
* @brief overrides clone from @see PeerPlacingStrategy
* @return A copy instance of the current PeerPlacingStrategy
*/
PeerPlacingStrategy *
DynamicPeerPlacingStrategy::clone() const {
return new DynamicPeerPlacingStrategy(*this);
}
/**
* @brief method excute a loadbalancing
*/
void
DynamicPeerPlacingStrategy::balanceNetwork() const {
size_t maxNumberBalanceRound = calcMaxNumberBalanceRound();
forwardBalanceNetwork(maxNumberBalanceRound);
if (metric->canBackwardBalance()) {
backwardBalanceNetwork(maxNumberBalanceRound);
}
}
/**
* @brief method calculate maxium number of balance round
* @return maxium number of balance round
*/
size_t
DynamicPeerPlacingStrategy::calcMaxNumberBalanceRound() const {
const ClusterList & clusterList = memRegister.getClusters();
size_t peerCount = ClusterSizeBalanceMetric::calcPeerCount(clusterList);
return peerCount - clusterList.size();
}
/**
* @brief method excute a loadbalancing, mv peer froom less loaded cluster to most loaded cluster
* @param maxBalanceRound - the maxium number of balance round
*/
void
DynamicPeerPlacingStrategy::forwardBalanceNetwork(size_t & maxBalanceRound) const {
for (size_t i = 0; i < maxBalanceRound; i++) {
const ClusterList & clusterList = memRegister.getClusters();
// creates and sort cluster lists
metric->setupMetric(clusterList);
const ClusterList & ucList = metric->getUcList();
const ClusterList & ncList = metric->getNcList();
const ClusterList & ocList = metric->getOcList();
// check for overlouded cluster
if (ocList.size() < BalanceMetric::SINGLEPEER_CLUSTER) {
break;
}
// determine srcCluster
ClusterID srcClusterID = metric->getMostLoadedClusterID(ocList);
ClusterID dstClusterID;
// determine dstCluster
if (ucList.size() > BalanceMetric::EMPTY_CLUSTER) {
dstClusterID = metric->getLessLoadedClusterID(ucList);
}
else if (ncList.size() > BalanceMetric::EMPTY_CLUSTER) {
dstClusterID = metric->getLessLoadedClusterID(ncList);
}
else {
dstClusterID = metric->getLessLoadedClusterID(ocList);
}
Cluster srcCluster(clusterList.getByID(srcClusterID));
const Cluster & dstCluster = clusterList.getByID(dstClusterID);
// check if its balenceable
if (!metric->isLoadBalancingPossible(srcCluster, dstCluster)) {
break;
}
PeerID srcMasterID = srcCluster.getMasterID();
PeerID mvPeerID;
// determine movepeer
while (srcCluster.size() > BalanceMetric::EMPTY_CLUSTER) {
mvPeerID = metric->getMostLoadedPeerID(srcCluster);
if (srcMasterID == mvPeerID) {
srcCluster.removePeer(mvPeerID);
continue;
}
break;
}
memRegister.movePeer(mvPeerID, dstClusterID);
maxBalanceRound--;
// set newMaster
PeerID masterID = metric->getBestMasterID(dstCluster);
memRegister.selectMaster(dstClusterID, masterID);
}
}
/**
* @brief method excute a loadbalancing, mv peer froom most loaded cluster to less loaded cluster
* @param maxBalanceRound - the maxium number of balance round
*/
void
DynamicPeerPlacingStrategy::backwardBalanceNetwork(size_t & maxBalanceRound) const {
for (size_t i = 0; i < maxBalanceRound; i++) {
const ClusterList & clusterList = memRegister.getClusters();
// creates and sort cluster lists
metric->setupMetric(clusterList);
const ClusterList & ucList = metric->getUcList();
const ClusterList & ncList = metric->getNcList();
const ClusterList & ocList = metric->getOcList();
if (ucList.size() < BalanceMetric::SINGLEPEER_CLUSTER) {
return;
}
// determine srcCluster
ClusterID srcClusterID = metric->getLessLoadedClusterID(ucList);
ClusterID dstClusterID;
// determine dstCluster
if (ocList.size() > BalanceMetric::EMPTY_CLUSTER) {
dstClusterID = metric->getMostLoadedClusterID(ocList);
}
else if (ncList.size() > BalanceMetric::EMPTY_CLUSTER) {
dstClusterID = metric->getMostLoadedClusterID(ncList);
}
else {
dstClusterID = metric->getMostLoadedClusterID(ucList);
}
Cluster srcCluster(clusterList.getByID(srcClusterID));
const Cluster & dstCluster = clusterList.getByID(dstClusterID);
// check if its balenceable
if (!metric->isLoadBalancingPossible(srcCluster, dstCluster)) {
return;
}
PeerID srcMasterID = srcCluster.getMasterID();
PeerID mvPeerID;
// determine movepeer
while (srcCluster.size() > BalanceMetric::EMPTY_CLUSTER) {
mvPeerID = metric->getLessLoadedPeerID(srcCluster);
if (srcMasterID == mvPeerID && srcCluster.size() > BalanceMetric::SINGLEPEER_CLUSTER) {
srcCluster.removePeer(mvPeerID);
continue;
}
break;
}
memRegister.movePeer(mvPeerID, dstClusterID);
maxBalanceRound--;
// set newMaster
PeerID masterID = metric->getBestMasterID(dstCluster);
memRegister.selectMaster(dstClusterID, masterID);
}
}
/**
* @brief Method delete and balance the clusternetwork, if a peer has left the group
*/
void
DynamicPeerPlacingStrategy::peerLeft() const {
// get current clusterlist
const ClusterList & clusterList = memRegister.getClusters();
if (isTooManyCluster(clusterList)) {
//delete srcCluster
ClusterID srcClusterID = metric->getLessLoadedClusterID(clusterList);
deleteCluster(clusterList, srcClusterID);
}
else {
// add a new cluster
if (isNewClusterRequired(clusterList, CURRENTPEERCOUNT_OFFSET)) {
addCluster(clusterList);
}
}
// balance the network
balanceNetwork();
}
/**
* @brief Method a new cluster to the network and move one peer to them
*/
void
DynamicPeerPlacingStrategy::addCluster(const ClusterList & clusterList) const {
ClusterID newClusterID = memRegister.createCluster();
ClusterID oldClusterID = metric->getMostLoadedClusterID(clusterList);
const Cluster & oldCluster = clusterList.getByID(oldClusterID);
if (oldCluster.size() <= BalanceMetric::SINGLEPEER_CLUSTER) {
memRegister.getClusters().remove(newClusterID);
ClusterList workcopyClusterList(clusterList);
workcopyClusterList.remove(oldClusterID);
if (workcopyClusterList.size() > BalanceMetric::EMPTY_CLUSTER) {
addCluster(workcopyClusterList);
}
return;
}
PeerID mvPeerID = metric->getMostLoadedPeerID(oldCluster);
// move Peer
memRegister.movePeer(mvPeerID, newClusterID);
memRegister.selectMaster(newClusterID, mvPeerID);
}
/**
* @brief Method deletes a certain cluster and moves the peers to the other cluster
* @param clusterList - list of clusters, where the peers of the deleted cluster can be moved
* @param delClusterId - id of the cluster, which has to be deleted
*/
void
DynamicPeerPlacingStrategy::deleteCluster(const ClusterList & clusterList, ClusterID delClusterId) const {
// create workcopy
ClusterList workcopy(clusterList);
Cluster cluster = workcopy.getByID(delClusterId);
// remove cluster
workcopy.remove(delClusterId);
ClusterID dstClusterID = metric->getBestClusterIDForNewPeer(workcopy);
PeerID mvPeerID;
while (cluster.size() > BalanceMetric::EMPTY_CLUSTER) {
mvPeerID = metric->getMostLoadedPeerID(cluster);
// move Peer
memRegister.movePeer(mvPeerID, dstClusterID);
// refresh workcopy
workcopy.addPeer(cluster.getPeer(mvPeerID), dstClusterID);
cluster.removePeer(mvPeerID);
dstClusterID = metric->getBestClusterIDForNewPeer(workcopy);
}
}
/**
* @brief Method set the PlacingMetric
* @param metricType - type of the balance metric, default is the BALANCEMETRIC_CLUSTERSIZE
*/
void
DynamicPeerPlacingStrategy::setPlacingMetric(PeerPlacingStrategyMetricType metricType) {
if (metric != NULL) {
delete metric;
}
switch (metricType) {
case BALANCEMETRIC_CLUSTERSIZE:
metric = new ClusterSizeBalanceMetric();
break;
case BALANCEMETRIC_RESOURCEVALUECLUSTERSIZE:
metric = new ResourceClusterSizeBalanceMetric();
break;
case BALANCEMETRIC_RESOURCEVALUE:
metric = new ResourceValueBalanceMetric();
break;
default:
metric = new ClusterSizeBalanceMetric();
break;
}
metricType = metricType;
}
}
}