/*
* Copyright (c) 2005-2011 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 .
*
*/
package de.tud.kom.p2psim.impl.churn;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.math.MathException;
import org.apache.commons.math.distribution.ExponentialDistributionImpl;
import de.tud.kom.p2psim.api.churn.ChurnModel;
import de.tud.kom.p2psim.api.common.SimHost;
import de.tud.kom.p2psim.api.scenario.Configurator;
import de.tud.kom.p2psim.api.scenario.HostBuilder;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
public class ExponentialChurnModel implements ChurnModel {
public enum UserType {
TRANSIENT(MEAN_SESSION_LENGTH), NORMAL(10 * MEAN_SESSION_LENGTH), LONG_LASTING(
100 * MEAN_SESSION_LENGTH);
public final ExponentialDistributionImpl expDist;
private UserType(long length) {
double meanLength = Double.parseDouble(Long.toString(length));
expDist = new ExponentialDistributionImpl(meanLength);
Long.toString(length);
}
}
static long MEAN_SESSION_LENGTH;
// ----------------------------------
// Exponential settings for churn with a NON-Chord-Overlay:
// set churn factor to 0.1
// ----------------------------------
// double longLastingFraction = 0.10d;
//
// double normalFraction = 0.40d;
//
// double transientFraction = 0.50d;
//
// double longLastingCf = 0.75d;
//
// double normalCf = 0.5d;
//
// double transientCf;
// ----------------------------------
// Exponential settings for churn with a Chord-Overlay:
// set churn factor to 0.1
// ----------------------------------
double longLastingFraction = 0.10d;
double normalFraction = 0.40d;
double transientFraction = 0.50d;
double longLastingCf = 0.95d;
double normalCf = 0.85d;
double transientCf; // 0.85
Map hosts;
HostBuilder hostBuilder;
double churnFactor;
public int online;
public ExponentialChurnModel() {
this.hosts = new HashMap();
}
public long getNextDowntime(SimHost host) {
ChurnData data = this.hosts.get(host);
try {
data.setOnlineTime(Math.round(data.type.expDist
.inverseCumulativeProbability(Randoms.getRandom(
ExponentialChurnModel.class)
.nextDouble())));
// REFREX
/*
* double value = data.type.expDist
* .inverseCumulativeProbability(Simulator.getRandom()
* .nextDouble()); data.setOnlineTime((long) value);
*/
} catch (MathException e) {
e.printStackTrace();
}
return data.onlineTime;
}
public long getNextUptime(SimHost host) {
ChurnData data = this.hosts.get(host);
return data.offlineTime;
}
public void prepare(List churnHosts) {
this.calculateTransientCf();
assert (this.longLastingFraction + this.normalFraction
+ this.transientFraction <= 1d) : "Wrong fraction distribution";
double random;
for (SimHost host : churnHosts) {
random = Randoms.getRandom(ExponentialChurnModel.class)
.nextDouble();
if (random < this.longLastingFraction) {
hosts.put(host, new ChurnData(UserType.LONG_LASTING,
this.longLastingCf));
} else if ((random >= this.longLastingFraction)
&& (random < (this.normalFraction + this.longLastingFraction))) {
hosts.put(host, new ChurnData(UserType.NORMAL, this.normalCf));
} else {
hosts.put(host, new ChurnData(UserType.TRANSIENT,
this.transientCf));
}
}
}
private void calculateTransientCf() {
this.transientCf = (1 - this.churnFactor
- (this.longLastingCf * this.longLastingFraction) - (this.normalCf * this.normalFraction))
/ this.transientFraction;
if (transientCf < 0d || transientCf > 1d) {
throw new AssertionError(
"Cannot use desired churn factor. "
+ "Transient connection factor would be "
+ transientCf
+ " then, which is out of bounds. Modify the fraction instead.");
}
}
public void compose(Configurator config) {
hostBuilder = (HostBuilder) config
.getConfigurable(Configurator.HOST_BUILDER);
}
public void setMeanSessionLength(long length) {
MEAN_SESSION_LENGTH = length;
}
public void setChurnFactor(double factor) {
this.churnFactor = factor;
}
class ChurnData {
UserType type;
double cf;
long onlineTime;
long offlineTime;
public ChurnData(UserType type, double cf) {
this.type = type;
this.cf = cf;
}
void setOnlineTime(long time) {
this.onlineTime = time;
this.offlineTime = Math.round((time - cf * time) / cf);
}
}
@Override
public String toString() {
return "ExponentialChurnGenerator";
}
}