Commit d9b11eb6 authored by Nils Richerzhagen's avatar Nils Richerzhagen
Browse files

Added MaxPeerCountChurnGenerator.

parent 151ba806
...@@ -322,14 +322,7 @@ public class CSVBasedChurnModel implements ChurnModel { ...@@ -322,14 +322,7 @@ public class CSVBasedChurnModel implements ChurnModel {
public long getStartTime(){ public long getStartTime(){
return startTime; return startTime;
} }
//
// /**
// * Returns if this churn interval stands for an online interval
// * @return
// */
// public boolean isOnline(){
// return this.online;
// }
} }
} }
...@@ -20,6 +20,9 @@ ...@@ -20,6 +20,9 @@
package de.tud.kom.p2psim.impl.churn; package de.tud.kom.p2psim.impl.churn;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Comparator; import java.util.Comparator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.LinkedList; import java.util.LinkedList;
...@@ -31,6 +34,8 @@ import java.util.Random; ...@@ -31,6 +34,8 @@ import java.util.Random;
import de.tud.kom.p2psim.api.churn.ChurnModel; import de.tud.kom.p2psim.api.churn.ChurnModel;
import de.tud.kom.p2psim.api.common.SimHost; import de.tud.kom.p2psim.api.common.SimHost;
import de.tud.kom.p2psim.api.network.SimNetInterface; import de.tud.kom.p2psim.api.network.SimNetInterface;
import de.tud.kom.p2psim.impl.scenario.DefaultConfigurator;
import de.tud.kom.p2psim.impl.simengine.Simulator;
import de.tudarmstadt.maki.simonstrator.api.Randoms; import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.Time; import de.tudarmstadt.maki.simonstrator.api.Time;
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor; import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
...@@ -38,131 +43,178 @@ import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor; ...@@ -38,131 +43,178 @@ import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
/** /**
* random arrival/leaving rate during simulation for a prefixed interval * random arrival/leaving rate during simulation for a prefixed interval
* *
* Session length fix und nur arrival/leaving rate in lower und upper bound randoms * Intervals for rates fix, peaks fix, darüber geben sich arrical/leaving rates.
*
* Session length fixund nur arrival/leaving rate in lower und upper bound
* randoms
*
*
* Bursts:
*
* Burst joining duration 10 minutes.
*
* Min session length 10 minutes.
* *
* @author Nils Richerzhagen * @author Nils Richerzhagen
* @version 1.0, Feb 18, 2015 * @version 1.0, Feb 18, 2015
*/ */
public class FluctuatingPeerCountChurnModel implements ChurnModel { public class FluctuatingPeerCountChurnModel implements ChurnModel {
private final String SEP = ","; private final String filename;
private Map<Long, Long> churnInfos; private final String commentsDelimiter = "#";
private final String SEP = ",";
private double upperFluctuationBound; private final long _burstJoinInterval = 10 * Time.MINUTE;
/** private final long _minBurstLength = 10 * Time.MINUTE;
*
*/ private LinkedList<ChurnInfo> churnInfos = new LinkedList<ChurnInfo>();
private double lowerFluctuationBound;
/** /**
* Maximum number of online clients for non-fluctuation phase. * Maximum number of online clients for non-fluctuation phase. Defined
* during configuration.
*/ */
private int maxPeersOnline; private final int defaultPeersOnline;
/** /**
* Inter-arrival time as specified during configuration * Inter-arrival time as specified during configuration
*/ */
// private final long initialInterArrivalTime; private final long initialInterArrivalTime;
/*
* Parameters a and b of exponential distribution defining session lengths
*/
private double a = 0.6378;
private double b = -0.05944;
/**
* Minimum session length as specified during configuration
*/
private long minSessionLength = 10 * Time.SECOND;
private List<SimHost> hosts; private List<SimHost> hosts;
private final Random random = Randoms.getRandom(FluctuatingPeerCountChurnModel.class);
private long lastJoin = -1;
private Map<Long, ClientSessionInfo> clientSessionInfos = new LinkedHashMap<Long, ClientSessionInfo>();
private PriorityQueue<ClientSessionInfo> clientsSortedByOfflineTime;
private final Random random = Randoms
.getRandom(FluctuatingPeerCountChurnModel.class);
private long lastJoin = -1;
@XMLConfigurableConstructor({ "maxPeersOnline", "upperFluctuationBound", "lowerFluctuationBound" }) // private Map<Long, ClientSessionInfo> clientSessionInfos = new LinkedHashMap<Long, ClientSessionInfo>();
public FluctuatingPeerCountChurnModel(int maxPeersOnline, double upperFluctuationBound, double lowerFluctuationBound) {
this.maxPeersOnline = maxPeersOnline;
this.upperFluctuationBound = upperFluctuationBound;
this.lowerFluctuationBound = lowerFluctuationBound;
private Map<SimHost, LinkedList<ClientChurnInfo>> clientChurnInfos;
// private PriorityQueue<ClientSessionInfo> clientsSortedByOfflineTime;
@XMLConfigurableConstructor({ "file", "defaultPeersOnline",
"interArrivalTime" })
public FluctuatingPeerCountChurnModel(String file, int defaultPeersOnline,
long interArrivalTime) {
this.filename = file;
this.defaultPeersOnline = defaultPeersOnline;
this.initialInterArrivalTime = interArrivalTime;
} }
@Override @Override
public long getNextUptime(SimHost host) { public long getNextUptime(SimHost host) {
long currentTime = Time.getCurrentTime(); long currentTime = Time.getCurrentTime();
if(!hosts.remove(host)){ LinkedList<ClientChurnInfo> churnInfos = clientChurnInfos.get(host);
/* return churnInfos.getFirst().joiningAt - currentTime;
* FIXME: Avoiding reusing peer instances.
*/
return 1000 * Time.HOUR;
} // ChurnInfo currentChurnInfo = null;
// TODO Current Fluctuation // if (!churnInfos.isEmpty()) {
if(clientsSortedByOfflineTime.size() < maxPeersOnline){ // currentChurnInfo = churnInfos.getFirst();
/* // /*
* Initially, join peers until the peer threshold is reached. // * ChurnInfo is old. Remove old one and overwrite currentChurnInfo
*/ // */
if (lastJoin < 0) { // if (currentChurnInfo.getEndTime() < currentTime) {
lastJoin = currentTime; // churnInfos.removeFirst();
} // currentChurnInfo = churnInfos.getFirst();
// }
// }
//
// /*
// * Join all clients until default (min) number of clients is achieved.
// */
// if (clientsSortedByOfflineTime.size() < defaultPeersOnline) {
// /*
// * Initially, join peers until the peer threshold is reached.
// */
// if (lastJoin < 0) {
// lastJoin = currentTime;
// }
// long currentJoin = lastJoin + initialInterArrivalTime; // long currentJoin = lastJoin + initialInterArrivalTime;
// ClientSessionInfo info = new ClientSessionInfo(currentJoin); // ClientSessionInfo info = new ClientSessionInfo(currentJoin);
// clientsSortedByOfflineTime.add(info); // clientsSortedByOfflineTime.add(info);
// clientSessionInfos.put(host.getHostId(), info); // clientSessionInfos.put(host.getHostId(), info);
// if (hasFlashcrowd && !flashCrowdFinished //
// && currentJoin > flashcrowdStart) { // lastJoin = currentJoin;
// currentJoin = flashcrowdStart; // return info.joiningAt - currentTime;
// inFlashcrowd = true; // }
//
//
// if (currentChurnInfo != null
// && currentChurnInfo.getStartTime() <= currentTime
// && (currentChurnInfo.getStartTime()
// + currentChurnInfo.getIntervalLength()) > currentTime) {
// /*
// * Is in next churn info: churnStart < currentTime < churnEnd
// *
// * Join or leave peers in a burst according to current churnInfo.
// *
// * Info: the peak is reached with the churnInfo - numberOfClients
// */
//
// long churnCrowdInterArrivalTime = currentChurnInfo
// .getIntervalLength()
// / (currentChurnInfo.getNumberOfClients()
// - defaultPeersOnline);
// long currentJoin = lastJoin + churnCrowdInterArrivalTime;
// ClientSessionInfo info = new ClientSessionInfo(currentJoin);
// clientSessionInfos.put(host.getHostId(), info);
//
// lastJoin = currentJoin;
// return info.joiningAt - currentTime;
//
// } else if (clientsSortedByOfflineTime.size() < defaultPeersOnline) {
// /*
// * Initially, join peers until the peer threshold is reached.
// */
// if (lastJoin < 0) {
// lastJoin = currentTime;
// } // }
// long currentJoin = lastJoin + initialInterArrivalTime;
// ClientSessionInfo info = new ClientSessionInfo(currentJoin);
// clientsSortedByOfflineTime.add(info);
// clientSessionInfos.put(host.getHostId(), info);
//
// lastJoin = currentJoin; // lastJoin = currentJoin;
// return info.joiningAt - currentTime; // return info.joiningAt - currentTime;
} // } else {
else{ // /*
/* // * After reaching the peer threshold, only peers that went offline
* After reaching the peer threshold, only peers that went offline // * are replaced to keep the threshold.
* are replaced to keep the threshold. // */
*/ // ClientSessionInfo nextToGoOffline = clientsSortedByOfflineTime
ClientSessionInfo nextToGoOffline = clientsSortedByOfflineTime // .poll();
.poll(); //
// if (nextToGoOffline == null) {
if (nextToGoOffline == null) { // throw new AssertionError();
throw new AssertionError(); // } else {
} else { // // Use the next time a peer goes offline as joining time.
// Use the next time a peer goes offline as joining time. // long currentJoin = nextToGoOffline.leavingAt;
long currentJoin = nextToGoOffline.leavingAt; // ClientSessionInfo info = new ClientSessionInfo(currentJoin);
ClientSessionInfo info = new ClientSessionInfo(currentJoin); // clientsSortedByOfflineTime.add(info);
clientsSortedByOfflineTime.add(info); // clientSessionInfos.put(host.getHostId(), info);
clientSessionInfos.put(host.getHostId(), info); //
// if (hasFlashcrowd && !flashCrowdFinished // lastJoin = currentJoin;
// && currentJoin > flashcrowdStart) { // return info.joiningAt - currentTime;
// currentJoin = flashcrowdStart; // }
// inFlashcrowd = true; // }
// }
lastJoin = currentJoin;
return info.joiningAt - currentTime;
}
}
return 0;
} }
@Override @Override
public long getNextDowntime(SimHost host) { public long getNextDowntime(SimHost host) {
LinkedList<ClientChurnInfo> churnInfos = clientChurnInfos.get(host);
// (churnInfos.removeFirst());
// return info.sessionLength;
return 0; return 0;
} }
@Override @Override
public void prepare(List<SimHost> churnHosts) { public void prepare(List<SimHost> churnHosts) {
hosts = new LinkedList<SimHost>(churnHosts); hosts = new LinkedList<SimHost>(churnHosts);
...@@ -174,57 +226,243 @@ public class FluctuatingPeerCountChurnModel implements ChurnModel { ...@@ -174,57 +226,243 @@ public class FluctuatingPeerCountChurnModel implements ChurnModel {
} }
} }
} }
clientsSortedByOfflineTime = new PriorityQueue<FluctuatingPeerCountChurnModel.ClientSessionInfo>( // clientsSortedByOfflineTime = new PriorityQueue<FluctuatingPeerCountChurnModel.ClientSessionInfo>(
(int) Math.ceil(hosts.size() / 10.0), COMP_OFFLINE_TIME); // (int) Math.ceil(hosts.size() / 10.0), COMP_OFFLINE_TIME);
parseTrace(filename);
computeChurnPerNode();
} }
// /**
// * Comparator used to sort client infos by offline time
// */
// private static final Comparator<ClientSessionInfo> COMP_OFFLINE_TIME = new Comparator<FluctuatingPeerCountChurnModel.ClientSessionInfo>() {
// @Override
// public int compare(ClientSessionInfo o1, ClientSessionInfo o2) {
// return ((Long) o1.leavingAt).compareTo(o2.leavingAt);
// }
// };
/** public long getSessionLength() {
* Comparator used to sort client infos by offline time // FIXME Hosts s
*/ return 3 * Time.HOUR;
private static final Comparator<ClientSessionInfo> COMP_OFFLINE_TIME = new Comparator<FluctuatingPeerCountChurnModel.ClientSessionInfo>() { }
@Override
public int compare(ClientSessionInfo o1, ClientSessionInfo o2) {
return ((Long) o1.leavingAt).compareTo(o2.leavingAt);
}
};
protected long getSessionLength(){ public int getDefaultPeersOnline() {
double rnd = random.nextDouble(); return defaultPeersOnline;
}
private void computeChurnPerNode(){
/**
* Compute a list (onlineStart, intervalLength) per host.
*/
clientChurnInfos = new LinkedHashMap<SimHost, LinkedList<ClientChurnInfo>>();
int count = 0;
for (SimHost host : hosts) {
count ++;
LinkedList<ClientChurnInfo> clientChurnInfos = new LinkedList<ClientChurnInfo>();
/*
* As long as the defaultNumberOfPeers is not achieved just fill list with one item per Host.
*/
if(count <= defaultPeersOnline){
if (lastJoin < 0) {
lastJoin = 0;
}
long currentJoin = lastJoin + initialInterArrivalTime;
lastJoin = currentJoin;
// FIXME Session length for nodes that stay online?
clientChurnInfos.add(new ClientChurnInfo(currentJoin, Simulator.getEndTime()));
}
/*
* Nodes that may go offline multiple times. Defined by churnInfos via csv file.
*/
else if(count > defaultPeersOnline){
for (ChurnInfo churnInfo : churnInfos) {
long currentStartTime = churnInfo.getStartTime();
long currentBurstLength = churnInfo.getBurstLength();
// when burst starts + x-ter Node times inter arrival rate
long currentJoin = currentStartTime + (count - defaultPeersOnline) * churnInfo.getInterArrivalRate();
assert currentJoin >= currentStartTime;
if(count <= churnInfo.getNumberOfClients()){
clientChurnInfos.add(new ClientChurnInfo(currentJoin, currentBurstLength));
}
}
}
// clientChurnInfos.put(host, clientChurnInfos);
System.out.println(host.getId().value() + " churnInfoAdded");
}
long sessionLength = (long) (Math.log(rnd / a) / b) * Time.MINUTE
+ (long) (rnd * Time.MINUTE);
}
private void parseTrace(String filename) {
System.out.println("==============================");
System.out.println("Reading trace from " + filename);
/* /*
* The minimum session length is limited to avoid too short sessions * This parser works for the following csv file structure.
*
* startTime, intervalLength, numberOfClients
*
*/ */
return Math.max(minSessionLength + (long) (rnd * Time.MINUTE), BufferedReader csv = null;
sessionLength); boolean entrySuccessfullyRead = false;
try {
csv = new BufferedReader(new FileReader(filename));
long previousEndTime = 0;
while (csv.ready()) {
String line = csv.readLine();
if (line.length() == 0 || line.startsWith(commentsDelimiter))
continue;
if (line.indexOf(SEP) > -1) {
String[] parts = line.split(SEP);
if (parts.length == 3) {
try {
long startTime = DefaultConfigurator.parseNumber(
parts[0].replaceAll("\\s+", ""),
Long.class);
long burstLength = DefaultConfigurator
.parseNumber(
parts[1].replaceAll("\\s+", ""),
Long.class);
int numberOfClients = DefaultConfigurator
.parseNumber(
parts[2].replaceAll("\\s+", ""),
Integer.class);
// Insanity Checks
assert startTime >= previousEndTime : "Start time for next fluctuation must be greater than previous end time.";
assert burstLength < _minBurstLength : "The minimal length of the burst must be at least 10m.";
previousEndTime = startTime + burstLength;
churnInfos.add(new ChurnInfo(startTime,
burstLength, numberOfClients));
entrySuccessfullyRead = true;
} catch (NumberFormatException e) {
// Ignore leading comments
if (entrySuccessfullyRead) {
// System.err.println("CSV ParseError " +
// line);
}
}
} else {
throw new AssertionError("To many/few columns in CSV.");
}
}
}
} catch (Exception e) {
System.err.println("Could not open " + filename);
throw new RuntimeException("Could not open " + filename);
} finally {
if (csv != null) {
try {
csv.close();
} catch (IOException e) {
//
}
}
}
} }
// /**
// * Client session information
// */
// private class ClientSessionInfo {
//
// public final long joiningAt;
//
// public final long leavingAt;
//
// public final long sessionLength;
//
// public ClientSessionInfo(long joiningAt) {
// this.sessionLength = getSessionLength();
// this.joiningAt = joiningAt;
// this.leavingAt = joiningAt + sessionLength;
// }
//
// }
public void setMinSessionLength(long minSessionLength) { /**
this.minSessionLength = minSessionLength; *
*/
private class ClientChurnInfo {
public final long joiningAt;
public final long leavingAt;
public ClientChurnInfo(long joiningAt, long sessionLength) {
this.joiningAt = joiningAt;
this.leavingAt = joiningAt + sessionLength;
}
} }
/** /**
* Client session information * Churn Info for the fluctuation intervals.
*
* @author Nils Richerzhagen
*/ */
private class ClientSessionInfo { private class ChurnInfo {
public final long joiningAt; /**
* The time the burst starts.
*/
private long startTime;
public final long leavingAt; /**
* The time the nodes stay online.
*/
private long burstLength;
public final long sessionLength; /**
* The max number of nodes that join during that burst.
*/
private int numberOfClients;
public ChurnInfo(long startTime, long burstLength,
int numberOfClients) {
this.startTime = startTime;
this.burstLength = burstLength;
this.numberOfClients = numberOfClients;
}
public ClientSessionInfo(long joiningAt) { public long getStartTime() {
this.sessionLength = getSessionLength(); return startTime;
this.joiningAt = joiningAt;
this.leavingAt = joiningAt + sessionLength;
} }
} public long getBurstLength() {
return burstLength;
}
public int getNumberOfClients() {
return numberOfClients;
}
//
// public long getEndTime() {
// return startTime + burstLength;
// }
/**
* Computed for the burst join window of 10 minutes.
*
* @return interArrivalRate
*/
public long getInterArrivalRate() {
return _burstJoinInterval / (numberOfClients - getDefaultPeersOnline());
}
}
} }
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* PeerfactSim.KOM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.churn;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.PriorityQueue;
import de.tud.kom.p2psim.api.common.SimHost;
import de.tud.kom.p2psim.api.network.SimNetInterface;
import de.tud.kom.p2psim.api.network.SimNetworkComponent;
import de.tud.kom.p2psim.impl.scenario.DefaultConfigurator;
import de.tud.kom.p2psim.impl.simengine.Simulator;
import de.tud.kom.p2psim.impl.util.oracle.GlobalOracle;
import de.tud.kom.p2psim.impl.util.toolkits.CollectionHelpers;
import de.tud.kom.p2psim.impl.util.toolkits.Predicates;
import de.tudarmstadt.maki.simonstrator.api.Event;
import de.tudarmstadt.maki.simonstrator.api.EventHandler;
import de.tudarmstadt.maki.simonstrator.api.Time;
import de.tudarmstadt.maki.simonstrator.api.component.GlobalComponent;
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
/**
* ChurnModel that follows a defined "trace" in a csv file. The trace must
* consist of the following parameters per line:
*
* startTime, intervalLength numberOfClients
*
* startTime - the time when the specified number of nodes is to be set.
*
* intervalLength - the time in which the specified number of nodes (startTime)
* must be achieved by the model. Those two together also form the inter
* join/leaving rate.
*
* numberOfClients - the number of clients to be achieved.
*
* The model checks for a minimum intervalLength of 10 minutes.
*
*
* @author Nils Richerzhagen
* @version 1.0, Nov 24, 2015
*/
public class MaxPeerCountChurnGenerator
implements EventHandler, GlobalComponent {
private static final int _PeerCountEvent = 1001;
private static final int _CHURN_START = 1002;
private static final int _CHURN_EVENT = 1003;
private static final int _CHURN_NOCHURN_HOSTS = 1004;
private final String commentsDelimiter = "#";
private final String SEP = ",";
private final long _minBurstLength = 10 * Time.MINUTE;
/**
* {@link ChurnInfo} from the csv file.
*/
private LinkedList<ChurnInfo> churnInfos = new LinkedList<ChurnInfo>();
private PriorityQueue<HostSessionInfo> onlineHostsSortedByOnlineTime;
private PriorityQueue<HostSessionInfo> offlineHostsSortedByOfflineTime;
/**
* Comparator used to sort client infos by offline time
*/
private static final Comparator<HostSessionInfo> COMP_TIME = new Comparator<MaxPeerCountChurnGenerator.HostSessionInfo>() {
@Override
public int compare(HostSessionInfo o1, HostSessionInfo o2) {
return ((Long) o1.timestamp).compareTo(o2.timestamp);
}
};
@XMLConfigurableConstructor({ "file" })
public MaxPeerCountChurnGenerator(String file) {
parseTrace(file);
}
/**
* Called by the configurator.
*
* @param churnStart
*/
public void setChurnStart(long churnStart) {
// Event.scheduleWithDelay(churnStart, this, null, _CHURN_START);
Event.scheduleImmediately(this, null, _CHURN_START);
}
public void initialize() {
for (ChurnInfo churnInfo : churnInfos) {
Event.scheduleWithDelay(churnInfo.getStartTime(), this, churnInfo,
_PeerCountEvent);
}
}
/**
* Start adapting on new churn rate, when next churnInfo is valid.
*/
private void configureMaxPeerCount(ChurnInfo currentChurnInfo) {
long currentTime = Simulator.getCurrentTime();
assert currentChurnInfo
.getStartTime() == currentTime : "The ChurnInfo to use is scheduled for the exact time, thus it should be the same.";
/*
* Wanted number > current number. --> need nodes = go online
*/
if (currentChurnInfo
.getNumberOfClients() >= onlineHostsSortedByOnlineTime.size()) {
int count = currentChurnInfo.getNumberOfClients()
- onlineHostsSortedByOnlineTime.size();
for (int i = 0; i < count; i++) {
/*
* Schedule the required number of hosts for going online
* churnEvent. Get oldest entry in sortedOffline list and put
* online.
*/
HostSessionInfo hostSessionInfo = offlineHostsSortedByOfflineTime
.poll();
assert hostSessionInfo != null : "HostSessionInfo shouldn't be null - means to few hosts were configured.";
ChurnEvent churnEvent = new ChurnEvent(hostSessionInfo.host,
true);
long currentJoin = i
* (currentChurnInfo.getBurstLength() / count);
Event.scheduleWithDelay(currentJoin, this, churnEvent,
_CHURN_EVENT);
}
}
/*
* Wanted number < currentNumber --> remove nodes = goOffline
*/
else if (currentChurnInfo
.getNumberOfClients() < onlineHostsSortedByOnlineTime.size()) {
int count = onlineHostsSortedByOnlineTime.size()
- currentChurnInfo.getNumberOfClients();
for (int i = 0; i < count; i++) {
/*
* Schedule the required number of hosts for going offline
* churnEvent. Get oldest entry in sortedOnline list and put
* offline.
*/
HostSessionInfo hostSessionInfo = onlineHostsSortedByOnlineTime
.poll();
assert hostSessionInfo != null : "HostSessionInfo shouldn't be null - means no hosts were online.";
ChurnEvent churnEvent = new ChurnEvent(hostSessionInfo.host,
false);
long currentLeave = i
* (currentChurnInfo.getBurstLength() / count);
Event.scheduleWithDelay(currentLeave, this, churnEvent,
_CHURN_EVENT);
}
} else {
throw new AssertionError();
}
}
@Override
public void eventOccurred(Object content, int type) {
if (type == _PeerCountEvent) {
ChurnInfo churnInfo = (ChurnInfo) content;
configureMaxPeerCount(churnInfo);
} else if (type == _CHURN_EVENT) {
long currentTime = Simulator.getCurrentTime();
ChurnEvent churnEvent = (ChurnEvent) content;
SimNetworkComponent net = churnEvent.host.getNetworkComponent();
if (churnEvent.goOnline) {
for (SimNetInterface netI : net.getSimNetworkInterfaces()) {
if (netI.isOffline()) {
netI.goOnline();
}
}
onlineHostsSortedByOnlineTime
.add(new HostSessionInfo(churnEvent.host, currentTime));
} else {
for (SimNetInterface netI : net.getSimNetworkInterfaces()) {
if (netI.isOnline()) {
netI.goOffline();
}
}
offlineHostsSortedByOfflineTime
.add(new HostSessionInfo(churnEvent.host, currentTime));
}
} else if (type == _CHURN_START) {
initialize();
List<SimHost> hosts = new ArrayList<SimHost>(this.filterHosts());
this.prepare(hosts);
offlineHostsSortedByOfflineTime = new PriorityQueue<HostSessionInfo>(
(int) Math.ceil(hosts.size() / 10.0), COMP_TIME);
onlineHostsSortedByOnlineTime = new PriorityQueue<HostSessionInfo>(
(int) Math.ceil(hosts.size() / 10.0), COMP_TIME);
long currentTime = Simulator.getCurrentTime();
for (SimHost host : hosts) {
offlineHostsSortedByOfflineTime
.add(new HostSessionInfo(host, currentTime));
}
} else if (type == _CHURN_NOCHURN_HOSTS) {
// Send no-churn-hosts online immediately
List<SimHost> nochurnhosts = (List<SimHost>) content;
for (SimHost host : nochurnhosts) {
for (SimNetInterface netI : host.getNetworkComponent()
.getSimNetworkInterfaces()) {
if (netI.isOffline()) {
netI.goOnline();
}
}
}
}
}
/**
* Send hosts offline! Should be used to start with churnHosts in offline
* state.
*
* @param hosts
*/
private void prepare(List<SimHost> hosts) {
for (SimHost host : hosts) {
for (SimNetInterface netI : host.getNetworkComponent()
.getSimNetworkInterfaces()) {
if (netI.isOnline()) {
netI.goOffline();
}
}
}
}
/**
* Gets all hosts and takes all churn affected hosts. Schedules the non
* affected host to go online immediately.
*
* @return
*/
private List<SimHost> filterHosts() {
List<SimHost> tmp = GlobalOracle.getHosts();
List<SimHost> filteredHosts = new LinkedList<SimHost>();
CollectionHelpers.filter(tmp, filteredHosts,
Predicates.IS_CHURN_AFFECTED);
List<SimHost> noChurn = new LinkedList<SimHost>();
noChurn.addAll(tmp);
noChurn.removeAll(filteredHosts);
Event.scheduleImmediately(this, noChurn, _CHURN_NOCHURN_HOSTS);
return filteredHosts;
}
/**
* Reads the file given by the configuration and parses the churn events.
*
* @param filename
*/
private void parseTrace(String filename) {
System.out.println("==============================");
System.out.println("Reading trace from " + filename);
/*
* This parser works for the following csv file structure.
*
* startTime, intervalLength numberOfClients
*
*/
BufferedReader csv = null;
boolean entrySuccessfullyRead = false;
try {
csv = new BufferedReader(new FileReader(filename));
long previousEndTime = 0;
while (csv.ready()) {
String line = csv.readLine();
if (line.length() == 0 || line.startsWith(commentsDelimiter))
continue;
if (line.indexOf(SEP) > -1) {
String[] parts = line.split(SEP);
if (parts.length == 3) {
try {
long startTime = DefaultConfigurator.parseNumber(
parts[0].replaceAll("\\s+", ""),
Long.class);
long burstLength = DefaultConfigurator.parseNumber(
parts[1].replaceAll("\\s+", ""),
Long.class);
int numberOfClients = DefaultConfigurator
.parseNumber(
parts[2].replaceAll("\\s+", ""),
Integer.class);
// Insanity Checks
assert startTime >= previousEndTime : "Start time for next fluctuation must be greater than previous end time.";
assert burstLength >= _minBurstLength : "The minimal length of the burst must be at least 10m.";
previousEndTime = startTime + burstLength;
churnInfos.add(new ChurnInfo(startTime, burstLength,
numberOfClients));
entrySuccessfullyRead = true;
} catch (NumberFormatException e) {
// Ignore leading comments
if (entrySuccessfullyRead) {
// System.err.println("CSV ParseError " +
// line);
}
}
} else {
throw new AssertionError("To many/few columns in CSV.");
}
}
}
} catch (Exception e) {
System.err.println("Could not open " + filename);
throw new RuntimeException("Could not open " + filename);
} finally {
if (csv != null) {
try {
csv.close();
} catch (IOException e) {
//
}
}
}
}
/**
*
* @author Nils Richerzhagen
* @version 1.0, Nov 25, 2015
*/
private class HostSessionInfo {
public final SimHost host;
public final long timestamp;
public HostSessionInfo(SimHost host, long timestamp) {
this.host = host;
this.timestamp = timestamp;
}
}
private class ChurnEvent {
public final SimHost host;
public final boolean goOnline;
ChurnEvent(SimHost host, boolean goOnline) {
this.host = host;
this.goOnline = goOnline;
}
}
/**
* Churn Info for the fluctuation intervals.
*
* @author Nils Richerzhagen
*/
private class ChurnInfo {
/**
* The time the burst starts.
*/
private long startTime;
/**
* The time the burst takes.
*/
private long burstLength;
/**
* The max number of nodes that join during that burst.
*/
private int numberOfClients;
public ChurnInfo(long startTime, long burstLength,
int numberOfClients) {
this.startTime = startTime;
this.burstLength = burstLength;
this.numberOfClients = numberOfClients;
}
public long getStartTime() {
return startTime;
}
public int getNumberOfClients() {
return numberOfClients;
}
public long getBurstLength() {
return burstLength;
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment