Commit f4559a45 authored by Björn Richerzhagen's avatar Björn Richerzhagen
Browse files

initialized clean Simonstrator-PeerfactSim.KOM-repository to FINALLY get rid...

initialized clean Simonstrator-PeerfactSim.KOM-repository to FINALLY get rid of huge blob objects and ancient history that is not relevant to the simonstrator-branch of PeerfactSim.KOM
parents
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network.gnp.topology;
import java.util.ArrayList;
import de.tud.kom.p2psim.api.common.Position;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
/**
* This class implements a NetPosition for a GNP-Based calculation of round trip
* times. Therefore it includes methods for error estimation and methods for
* positioning by a downhill simplex algorithm in the GnpSpace class
*
* @author Gerald Klunker
* @version 0.1, 09.01.2008
*
*/
public class GnpPosition implements Position, Comparable<GnpPosition> {
private static final long serialVersionUID = -1103996725403557900L;
private double[] gnpCoordinates;
private GnpSpace gnpRef;
private Host hostRef;
private double error = -1.0;
/**
*
* @param gnpCoordinates
* coordinate array for new position
*/
public GnpPosition(double[] gnpCoordinates) {
super();
this.gnpCoordinates = gnpCoordinates;
}
/**
* Object will be initialized with a random position. Position must be
* random according to the downhill simplex
*
* @param noOfDimensions
* number of dimensions
* @param hostRef
* related Host object
* @param gnpRef
* related GnpSpace object
*/
public GnpPosition(int noOfDimensions, Host hostRef, GnpSpace gnpRef) {
super();
gnpCoordinates = new double[noOfDimensions];
this.hostRef = hostRef;
this.gnpRef = gnpRef;
for (int c = 0; c < gnpCoordinates.length; c++)
gnpCoordinates[c] = Randoms.getRandom(GnpPosition.class)
.nextDouble();
}
/**
*
* @param dimension
* @param maxDiversity
*/
public void diversify(double[][] dimension, double maxDiversity) {
for (int c = 0; c < this.gnpCoordinates.length; c++) {
double rand = (2 * maxDiversity * Math.random()) - maxDiversity;
gnpCoordinates[c] = gnpCoordinates[c] + (rand * dimension[c][2]);
}
error = -1.0;
}
/**
* reposition
*
* @param pos
* position in the coordinate array
* @param value
* new value at position pos
*/
public void setGnpCoordinates(int pos, double value) {
gnpCoordinates[pos] = value;
error = -1.0;
}
/**
*
* @return the related GnpSpace object
*/
private GnpSpace getGnpRef() {
return gnpRef;
}
/**
*
* @return the related Host object
*/
public Host getHostRef() {
return hostRef;
}
/**
*
* @return number of dimensions
*/
public int getNoOfDimensions() {
return gnpCoordinates.length;
}
/**
*
* @param pos
* position in the coordinate array
* @return value at position pos
*/
public double getGnpCoordinates(int pos) {
return gnpCoordinates[pos];
}
/**
* Calculates the sum of all errors according to the downhill simplex
* operator.
*
* @return error
*/
public double getDownhillSimplexError() {
if (error < 0.0) {
error = 0.0;
for (int c = 0; c < getGnpRef().getNumberOfMonitors(); c++) {
error += getDownhillSimplexError(getGnpRef()
.getMonitorPosition(c));
}
}
return error;
}
/**
* Calculates the error to a monitor according to the downhill simplex
* operator
*
* @param monitor
* @return error
*/
public double getDownhillSimplexError(GnpPosition monitor) {
double calculatedDistance = this.getDistance(monitor);
double measuredDistance = this.getMeasuredRtt(monitor);
if (Double.compare(measuredDistance, Double.NaN) == 0)
return 0.0;
double error = Math.pow((calculatedDistance - measuredDistance)
/ calculatedDistance, 2);
return error;
}
/**
* Calculates an error, that indicates the deviation of the measured vs. the
* calculated rtt.
*
* @param monitor
* @return error value
*/
public double getDirectionalRelativError(GnpPosition monitor) {
double calculatedDistance = this.getDistance(monitor);
double measuredDistance = this.getMeasuredRtt(monitor);
if (Double.compare(measuredDistance, Double.NaN) == 0)
return Double.NaN;
double error = (calculatedDistance - measuredDistance)
/ Math.min(calculatedDistance, measuredDistance);
return error;
}
/**
* Method must be overwrite to sort different GnpPositions in order of their
* quality.
*
* Is needed for the positioning with the downhill simplex
*
*/
public int compareTo(GnpPosition arg0) {
double val1 = this.getDownhillSimplexError();
double val2 = arg0.getDownhillSimplexError();
if (val1 < val2)
return -1;
if (val1 > val2)
return 1;
else
return 0;
}
/**
*
* @return Comma-separated list of coordinates
*/
public String getCoordinateString() {
if (gnpCoordinates.length == 0) {
return "";
} else {
String result = String.valueOf(gnpCoordinates[0]);
for (int c = 1; c < gnpCoordinates.length; c++)
result = result + "," + gnpCoordinates[c];
return result;
}
}
/**
*
* @param monitor
* @return measured rtt to monitor, nan if no rtt was measured
*/
public double getMeasuredRtt(GnpPosition monitor) {
return this.getHostRef().getRtt(monitor.getHostRef());
}
/**
* @return euclidean distance
*/
public double getDistance(Position point) {
GnpPosition coord = (GnpPosition) point;
double distance = 0.0;
for (int c = 0; c < gnpCoordinates.length; c++)
distance += Math.pow(
gnpCoordinates[c] - coord.getGnpCoordinates(c), 2);
return Math.sqrt(distance);
}
@Override
public double getAngle(Position target) {
throw new AssertionError(
"getAngle is not defined for this Position-Type");
}
@Override
public Position getTarget(double distance, double angle) {
throw new AssertionError(
"getTarget is not defined for this Position-Type");
}
@Override
public int getTransmissionSize() {
return 16; // 2 * double
}
/**
* Static method generates a new GnpPosition according to the downhill
* simplex operator
*
* @param solution
* @param moveToSolution
* @param moveFactor
* @return new position
*/
public static GnpPosition getMovedSolution(GnpPosition solution,
GnpPosition moveToSolution, double moveFactor) {
GnpPosition returnValue = new GnpPosition(solution.getNoOfDimensions(),
solution.getHostRef(), solution.getGnpRef());
for (int c = 0; c < solution.getNoOfDimensions(); c++) {
double newCoord = (moveToSolution.getGnpCoordinates(c) - solution
.getGnpCoordinates(c))
* moveFactor + solution.getGnpCoordinates(c);
returnValue.setGnpCoordinates(c, newCoord);
}
return returnValue;
}
/**
* Static method generates a new GnpPosition according to the downhill
* simplex operator
*
* @param solution
* @param moveToSolution
* @param moveFactor
* @return new position
*/
public static GnpPosition getCenterSolution(ArrayList<GnpPosition> solutions) {
GnpPosition returnValue = new GnpPosition(solutions.get(0)
.getNoOfDimensions(), solutions.get(0).getHostRef(), solutions
.get(0).getGnpRef());
for (int d = 0; d < solutions.size(); d++) {
for (int c = 0; c < solutions.get(0).getNoOfDimensions(); c++) {
returnValue.setGnpCoordinates(c, returnValue
.getGnpCoordinates(c)
+ solutions.get(d).getGnpCoordinates(c));
}
}
for (int c = 0; c < returnValue.getNoOfDimensions(); c++) {
returnValue.setGnpCoordinates(c, returnValue.getGnpCoordinates(c)
/ solutions.size());
}
return returnValue;
}
public GnpPosition clone() {
return new GnpPosition(gnpCoordinates);
}
}
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network.gnp.topology;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import org.apache.commons.math.stat.StatUtils;
import org.apache.log4j.Logger;
import de.tud.kom.p2psim.impl.util.logging.SimLogger;
/**
* Implements the downhill simplx algorithm for positioning host in an
* multi-dimensional space, so that the difference betwen the measured rtts and
* the calculated euclidean distance is minimized.
*
* @author Gerald Klunker
* @version 0.1, 09.01.2008
*
*/
public class GnpSpace implements Comparable<GnpSpace> {
private static Logger log = SimLogger.getLogger(GnpSpace.class);
private static final long serialVersionUID = 6941552219570807190L;
private HostMap mapRef;
private int noOfDimensions;
private HashMap<Integer, GnpPosition> coordinateIndex;
private GnpPosition[] monitorPositions;
/*
* Attributes for statistical analysis of measured to calculated errors
*/
private double[] relativeErrorDistribution = new double[0];
private LinkedList<Double>[] directionalRelativeErrors = new LinkedList[0];
private HashSet<Host>[] hostsByRelativeError = new HashSet[0];
private double maxRelativeError = 0;
/*
* Status information about current calculation and progress will be used by
* a gui-thread
*/
public static int calculationStepStatus = 0;
public static int calculationProgressStatus = 0;
public static boolean calculationInProgress = false;
/**
*
* @param noOfDimensions
* number of dimensions of the generated gnp space
* @param mapRef
* reference to the related HostMap
*/
public GnpSpace(int noOfDimensions, HostMap mapRef) {
super();
this.mapRef = mapRef;
this.noOfDimensions = noOfDimensions;
this.coordinateIndex = new HashMap<Integer, GnpPosition>();
this.monitorPositions = new GnpPosition[mapRef.getNoOfMonitors()];
int c = 0;
for (Host monitor : mapRef.getMonitorIndex().values()) {
monitorPositions[c] = new GnpPosition(noOfDimensions, monitor, this);
c++;
}
}
/**
*
* @return number of monitor positions
*/
protected int getNumberOfMonitors() {
return monitorPositions.length;
}
/**
*
* @param monitorIndex
* internal index of monitor
* @param monitor
* new monitor position
*/
private void setMonitorPosition(int monitorIndex, GnpPosition monitor) {
monitorPositions[monitorIndex] = monitor;
}
/**
*
* @param monitorIndex
* @return position of monitor with internal index monitorIndex
*/
protected GnpPosition getMonitorPosition(int monitorIndex) {
return monitorPositions[monitorIndex];
}
/**
*
* @return related HostMap object
*/
protected HostMap getMapRef() {
return mapRef;
}
/**
* Calcuates the dimension of the gnp space.
*
* @return array[x][y] x:pos in coordinate array, y=0: minimum of all
* values, y=1: maximum of all values , y=2: max - min value
*/
private double[][] getDimension() {
double[][] returnvalue = new double[this.noOfDimensions][3];
double min;
double max;
for (int c = 0; c < this.noOfDimensions; c++) {
min = this.monitorPositions[0].getGnpCoordinates(c);
max = min;
for (int d = 1; d < this.getNumberOfMonitors(); d++) {
double current = this.monitorPositions[d].getGnpCoordinates(c);
min = (min < current) ? min : current;
max = (max > current) ? max : current;
}
returnvalue[c][0] = min;
returnvalue[c][1] = max;
returnvalue[c][2] = max - min;
}
return returnvalue;
}
/**
*
* @return number of dimensions of the gnp space
*/
private int getNoOfDimensions() {
return this.noOfDimensions;
}
/**
* Removes the gnp position of a host
*
* @param hostIP
*/
protected void removePosition(long hostIP) {
this.coordinateIndex.remove(hostIP);
}
/*
* ======================================================================
* The following Methods implements methods for the statistical analysis of
* the quality of positions according to the measured rtts.
* ======================================================================
*/
/**
* Iterates through all Positions to calculate statistical data like -
* statistic 1: maximum relative error - statistic 2: directional relative
* errors grouped by rtt - statistic 3: hosts grouped by maximum relative
* error - statistic 4: distribution of relative errors
*/
public void builtStatisticalData() {
// set calculation status to 3 (calculation of statistical data)
calculationStepStatus = 3;
maxRelativeError = 0;
directionalRelativeErrors = new LinkedList[21];
hostsByRelativeError = new HashSet[21];
ArrayList<Double> relativeErrorsList = new ArrayList<Double>(4000000);
for (int d = 0; d < hostsByRelativeError.length; d++)
hostsByRelativeError[d] = new HashSet<Host>();
for (int d = 0; d < directionalRelativeErrors.length; d++)
directionalRelativeErrors[d] = new LinkedList<Double>();
calculationProgressStatus = 0;
for (GnpPosition host : coordinateIndex.values()) {
calculationProgressStatus++;
double maxError = 0;
for (GnpPosition monitor : monitorPositions) {
double measuredDistace = host.getMeasuredRtt(monitor);
if (measuredDistace > 0) {
double directionalRelativeError = host
.getDirectionalRelativError(monitor);
double relativeError = Math.abs(directionalRelativeError);
relativeErrorsList.add(relativeError);
// statistic 1: maximum relative error
if (maxError < relativeError)
maxError = relativeError;
// statistic 2: directional relative errors grouped by rtt
int groupID = (int) Math.floor(measuredDistace / 50);
if (groupID < 20)
directionalRelativeErrors[groupID]
.add(directionalRelativeError);
else
directionalRelativeErrors[20]
.add(directionalRelativeError);
}
// statistic 3: hosts grouped by maximum relative error
int groupID = (int) Math.floor(maxError * 10);
if (groupID >= 20)
hostsByRelativeError[20].add(host.getHostRef());
else
hostsByRelativeError[groupID].add(host.getHostRef());
}
// statistic 1: maximum relative error
if (maxRelativeError < maxError)
maxRelativeError = maxError;
}
// statistic 4: distribution of relative errors
double[] relativeErrorsArray = new double[relativeErrorsList.size()];
for (int c = 0; c < relativeErrorsList.size(); c++)
relativeErrorsArray[c] = relativeErrorsList.get(c);
relativeErrorDistribution = new double[100];
for (int c = 1; c < 100; c++)
relativeErrorDistribution[c] = StatUtils.percentile(
relativeErrorsArray, c);
// set calculation status to 0 (no calculation)
calculationStepStatus = 0;
}
/**
*
* @return array with distribution of relativ errors of all positions.
* index: 0-100%
*/
public double[] getRelativeErrorDistribution() {
return relativeErrorDistribution;
}
/**
*
* @return array of lists, that contains error values. index x=0: 0-50ms,
* x=1: 50-100ms, ... x=20: >1000ms
*/
public LinkedList<Double>[] getDirectionalRelativeErrorsGroupedByRtt() {
return directionalRelativeErrors;
}
/**
*
* @return array of sets, that contains host with related relative errors of
* a certain amount. index x=0: error 0-0.1, x=1: error 0.1-0.2 ...
* x=20 error > 2
*/
public HashSet<Host>[] getHostsGroupedByMaxRelativeError() {
return hostsByRelativeError;
}
/**
*
* @return maximum relative error within tis gnp space
*/
public double getMaximumRelativeError() {
return maxRelativeError;
}
/*
* ======================================================================
* The following Methods implements 2 downhill simplex algorithms for the
* optimization of positions of monitors and host in the gnp space
* ======================================================================
*/
/**
* Run this method to generate GNP Positions for Monitors and Hosts
*/
public static GnpSpace getGnp(int noOfDimensions, int monitorResheduling,
int hostResheduling, HostMap mapRef) {
// positioning of monitors
GnpSpace gnp = getGnpWithDownhillSimplex(noOfDimensions,
monitorResheduling, mapRef);
// positionning of ordinary hosts
gnp.insertCoordinates(hostResheduling);
return gnp;
}
/**
*
* @param noOfDimensions
* number of Dimensions must be smaller than number of Monitors
* @param monitorResheduling
* number of rescheduling the downhill simplex
* @param mapRef
* reference to HostMap
* @return optimized positions for Monitors
*/
private static GnpSpace getGnpWithDownhillSimplex(int noOfDimensions,
int monitorResheduling, HostMap mapRef) {
GnpSpace.calculationStepStatus = 1;
GnpSpace.calculationInProgress = true;
double alpha = 1.0;
double beta = 0.5;
double gamma = 2;
double maxDiversity = 0.5;
// N + 1 initial random Solutions
int dhs_N = mapRef.getNoOfMonitors();
ArrayList<GnpSpace> solutions = new ArrayList<GnpSpace>(dhs_N + 1);
for (int c = 0; c < dhs_N + 1; c++)
solutions.add(new GnpSpace(noOfDimensions, mapRef));
// best and worst solution
GnpSpace bestSolution = Collections.min(solutions);
GnpSpace worstSolution = Collections.max(solutions);
double bestError = bestSolution.getObjectiveValueMonitor();
double worstError = worstSolution.getObjectiveValueMonitor();
for (int z = 0; z < monitorResheduling; z++) {
GnpSpace.calculationProgressStatus = z;
// resheduling
int count = 0;
for (GnpSpace gnp : solutions) {
if (gnp != bestSolution) {
GnpPosition monitor = gnp.getMonitorPosition(count);
monitor.diversify(gnp.getDimension(), maxDiversity);
count++;
}
}
// best and worst solution
bestSolution = Collections.min(solutions);
worstSolution = Collections.max(solutions);
bestError = bestSolution.getObjectiveValueMonitor();
worstError = worstSolution.getObjectiveValueMonitor();
// stop criterion
while (worstError - bestError > 0.00001 && calculationInProgress) {
// move to center ...
GnpSpace center = GnpSpace.getCenterSolution(solutions);
GnpSpace newSolution1 = GnpSpace.getMovedSolution(
worstSolution, center, 1 + alpha);
double newError1 = newSolution1.getObjectiveValueMonitor();
if (newError1 <= bestError) {
int IndexOfWorstSolution = solutions.indexOf(worstSolution);
GnpSpace newSolution2 = GnpSpace.getMovedSolution(
worstSolution, center, 1 + alpha + gamma);
double newError2 = newSolution2.getObjectiveValueMonitor();
if (newError2 <= newError1) {
solutions.set(IndexOfWorstSolution, newSolution2);
bestError = newError2;
} else {
solutions.set(IndexOfWorstSolution, newSolution1);
bestError = newError1;
}
bestSolution = solutions.get(IndexOfWorstSolution);
} else if (newError1 < worstError) {
int IndexOfWorstSolution = solutions.indexOf(worstSolution);
solutions.set(IndexOfWorstSolution, newSolution1);
} else { // ... or contract around best solution
for (int c = 0; c < solutions.size(); c++) {
if (solutions.get(c) != bestSolution)
solutions.set(c, GnpSpace.getMovedSolution(
solutions.get(c), bestSolution, beta));
}
bestSolution = Collections.min(solutions);
bestError = bestSolution.getObjectiveValueMonitor();
}
worstSolution = Collections.max(solutions);
worstError = worstSolution.getObjectiveValueMonitor();
}
}
// Set the Coordinate Reference to the Peer
for (int c = 0; c < bestSolution.getNumberOfMonitors(); c++) {
bestSolution.getMonitorPosition(c).getHostRef()
.setPositionReference(bestSolution.getMonitorPosition(c));
}
// GnpSpace.calculationStepStatus = 0;
// GnpSpace.calculationInProgress = false;
return bestSolution;
}
/**
* Calculates good positions for all Hosts in Map
*
* @param monitorResheduling
* number of rescheduling the downhill simplex
*/
private void insertCoordinates(int monitorResheduling) {
GnpSpace.calculationStepStatus = 2;
coordinateIndex.clear();
HashMap<Integer, Host> peers = this.getMapRef().getHostIndex();
int c = 0;
for (Host host : peers.values()) {
GnpSpace.calculationProgressStatus = c;
if (host.getHostType() == Host.HOST) {
GnpPosition coord = this.insertCoordinateDownhillSimplex(host,
monitorResheduling);
coordinateIndex.put(host.getIpAddress(), coord);
c++;
if (c % 1000 == 0)
log.debug(c + " of " + peers.size()
+ " are positioned in gnp");
}
if (!calculationInProgress)
return;
}
GnpSpace.calculationStepStatus = 0;
GnpSpace.calculationInProgress = false;
}
/**
* Calculates a good positions for the host
*
* @param host
* to position
* @param monitorResheduling
* number of rescheduling the downhill simplex
* @return gnp position for peer
*/
private GnpPosition insertCoordinateDownhillSimplex(Host host,
int monitorResheduling) {
double alpha = 1.0;
double beta = 0.5;
double gamma = 2;
double maxDiversity = 0.5;
// N + 1 initial random Solutions
ArrayList<GnpPosition> solutions = new ArrayList<GnpPosition>(
noOfDimensions + 1);
for (int c = -1; c < noOfDimensions; c++) {
GnpPosition coord = new GnpPosition(noOfDimensions, host, this);
solutions.add(coord);
}
// best and worst solution
GnpPosition bestSolution = Collections.min(solutions);
GnpPosition worstSolution = Collections.max(solutions);
double bestError = bestSolution.getDownhillSimplexError();
double worstError = worstSolution.getDownhillSimplexError();
double newError = 0.0;
for (int z = 0; z < monitorResheduling; z++) {
// resheduling
for (GnpPosition coord : solutions) {
if (coord != bestSolution) {
coord.diversify(this.getDimension(), maxDiversity);
}
}
// best and worst solution
bestSolution = Collections.min(solutions);
worstSolution = Collections.max(solutions);
bestError = bestSolution.getDownhillSimplexError();
worstError = worstSolution.getDownhillSimplexError();
// stop criterion
while (worstError - bestError > 0.000001 && calculationInProgress) {
// move to center ...
GnpPosition center = GnpPosition.getCenterSolution(solutions);
GnpPosition newSolution1 = GnpPosition.getMovedSolution(
worstSolution, center, 1 + alpha);
newError = newSolution1.getDownhillSimplexError();
if (newError <= bestError) {
GnpPosition newSolution2 = GnpPosition.getMovedSolution(
worstSolution, center, 1 + alpha + gamma);
int IndexOfWorstSolution = solutions.indexOf(worstSolution);
if (newSolution2.getDownhillSimplexError() <= newError) {
solutions.set(IndexOfWorstSolution, newSolution2);
} else {
solutions.set(IndexOfWorstSolution, newSolution1);
}
bestSolution = solutions.get(IndexOfWorstSolution);
bestError = bestSolution.getDownhillSimplexError();
} else if (newError < worstError) {
int IndexOfWorstSolution = solutions.indexOf(worstSolution);
solutions.set(IndexOfWorstSolution, newSolution1);
} else { // ... or contract around best solution
for (int c = 0; c < solutions.size(); c++) {
if (solutions.get(c) != bestSolution)
solutions.set(c, GnpPosition.getMovedSolution(
solutions.get(c), bestSolution, beta));
}
bestSolution = Collections.min(solutions);
bestError = bestSolution.getDownhillSimplexError();
}
worstSolution = Collections.max(solutions);
worstError = worstSolution.getDownhillSimplexError();
}
}
// Set the Coordinate Reference to the Peer
host.setPositionReference(bestSolution);
return bestSolution;
}
/**
* objective function for monitor downhill simplex
*
* @return summation of monitor error values
*/
private double getObjectiveValueMonitor() {
double value = 0.0;
for (int i = 0; i < this.getNumberOfMonitors() - 1; i++) {
for (int j = i + 1; j < this.getNumberOfMonitors(); j++) {
value = value
+ monitorPositions[i]
.getDownhillSimplexError(monitorPositions[j]);
}
}
return value;
}
/**
* Method must be overwrite to sort different GnpSpaces in order of the
* quality of monitor positions.
*
* Is needed for the positioning of monitors with the downhill simplex
*
*/
public int compareTo(GnpSpace gnp) {
double val1 = this.getObjectiveValueMonitor();
double val2 = gnp.getObjectiveValueMonitor();
if (val1 < val2)
return -1;
if (val1 > val2)
return 1;
else
return 0;
}
/**
* Static method generates a new GnpSpace according to the downhill simplex
* operator
*
* @param solutions
* @return center solution
*/
private static GnpSpace getCenterSolution(ArrayList<GnpSpace> solutions) {
GnpSpace returnValue = new GnpSpace(solutions.get(0)
.getNoOfDimensions(), solutions.get(0).getMapRef());
for (int c = 0; c < returnValue.getNumberOfMonitors(); c++) {
ArrayList<GnpPosition> coords = new ArrayList<GnpPosition>();
for (int d = 0; d < solutions.size(); d++) {
coords.add(solutions.get(d).getMonitorPosition(c));
}
returnValue.setMonitorPosition(c, GnpPosition
.getCenterSolution(coords));
}
return returnValue;
}
/**
* Static method generates a new GnpSpace according to the downhill simplex
* operator
*
* @param solution
* @param moveToSolution
* @param moveFactor
* @return moved solution
*/
private static GnpSpace getMovedSolution(GnpSpace solution,
GnpSpace moveToSolution, double moveFactor) {
GnpSpace returnValue = new GnpSpace(solution.getNoOfDimensions(),
solution.getMapRef());
for (int c = 0; c < returnValue.getNumberOfMonitors(); c++) {
returnValue.setMonitorPosition(c, GnpPosition.getMovedSolution(
solution.getMonitorPosition(c), moveToSolution
.getMonitorPosition(c), moveFactor));
}
return returnValue;
}
}
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network.gnp.topology;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import de.tud.kom.p2psim.impl.network.IPv4NetID;
import de.tud.kom.p2psim.impl.network.gnp.geoip.IspLookupService;
import de.tud.kom.p2psim.impl.util.measurement.AvgAccumulator;
/**
* Host objects holds and manage information about their location on earth and
* gnp space and about measured rtts to monitors
*
* @author Gerald Klunker
* @version 0.1, 09.01.2008
*
*/
public class Host implements Serializable {
private static final long serialVersionUID = 5135831087205329917L;
/**
* Set to "true" to allow to ask for country names (leo@relevantmusic.de). Setting to "false" saves memory.
*/
private static boolean useCountryNames = false;
public static int MONITOR = 1;
public static int HOST = 2;
private int ipAddress = 0;
private int type;
private String countryCode;
private String region;
private String city;
private String isp;
private String area;
private boolean locatable = false;
private double latitude = Double.NaN;
private double longitude = Double.NaN;
private HashMap<Host, List<Double>> rttToMonitors = new HashMap<Host, List<Double>>();
private HashMap<Host, Double> cumulatedRTTs = null;
private HostMap mapRef;
public GnpPosition coordinateRef;
/**
* Stays null unless USE_COUNTRY_NAMES is set to "true". Setting it to false saves memory
*/
private String countryName = null;
public static void setUseCountryNames(boolean useThem) {
useCountryNames = useThem;
}
public static boolean issetUseCountryNames() {
return useCountryNames;
}
/**
* Returns the country name. Will throw an exception unless setUseCountryNames was set to true while the node was constructed.
* @return
*/
public String getCountryName() {
if (!useCountryNames) throw new IllegalStateException("Country names are not set. Please call the static method 'Host.setUseCountryNames(true)' " +
"before any Host is being constructed. Not calling it saves memory.");
return countryName;
}
/**
*
* @param ipAddress
* of the host
* @param mapRef
* reference to the related HostMap Object
*/
public Host(int ipAddress, HostMap mapRef) {
super();
this.ipAddress = ipAddress;
this.mapRef = mapRef;
}
/**
* adds a measured rtt to monitor. if there is still a rtt, it will be
* replaced, if the new one is smaller
*
* @param host
* @param rtt
* measured rtt
*/
public void addRtt(Host monitor, double rtt) {
if (cumulatedRTTs != null) throw new IllegalStateException("RTTs were already cumulated.");
List<Double> rtts = rttToMonitors.get(monitor);
if (rtts == null) {
rtts = new ArrayList<Double>(10);
rttToMonitors.put(monitor, rtts);
}
rtts.add(rtt);
}
protected void cumulateRTTsCond() {
if (cumulatedRTTs != null) return; //already cumulated
cumulatedRTTs = new HashMap<Host, Double>();
for (Entry<Host, List<Double>> e : rttToMonitors.entrySet()) {
List<Double> rtts = e.getValue();
avgPingAttemptsPerNode.addToTotal(rtts.size());
double cumulationResult = currentStrategy.cumulate(rtts);
cumulatedRTTs.put(e.getKey(), cumulationResult);
}
}
/**
* set a measured rtt to monitor.
*
* @param host
* @param rtt
* measured rtt
*/
public void setRtt(Host monitor, double rtt) {
cumulateRTTsCond();
cumulatedRTTs.put(monitor, rtt);
}
/**
*
* @param monitor
* @return measured rtt from host to monitor
*/
public double getRtt(Host monitor) {
cumulateRTTsCond();
Double rtt = cumulatedRTTs.get(monitor);
return (rtt == null)?Double.NaN:rtt;
}
/**
* remove them measured rtt from host to monitor
*
* @param monitor
*/
protected void removeRTT(Host monitor) {
rttToMonitors.remove(monitor);
}
/**
*
* @return set of monitors with a measured rtt to host
*/
protected Set<Host> getMeasuredMonitors() {
return rttToMonitors.keySet();
}
/**
*
* @return latitude
*/
public double getLatitude() {
return latitude;
}
/**
*
* @return longitude
*/
public double getLongitude() {
return longitude;
}
/**
*
* @return longitude
*/
public String getArea() {
return area;
}
/**
*
* @return 2-digits country code
*/
public String getCountryCode() {
return countryCode;
}
/**
* @return region name
*/
public String getRegion() {
return region;
}
/**
* @return city name
*/
public String getCity() {
return city;
}
/**
* @return isp name
*/
public String getISP() {
return isp;
}
/**
*
* @return ip-address as 32bit value
*/
public int getIpAddress() {
return ipAddress;
}
/**
*
* @param peerType
* (1:monitor, 2:host)
*/
protected void setHostType(int peerType) {
this.type = peerType;
}
/**
*
* @return type of host (1:monitor, 2:host)
*/
public int getHostType() {
return type;
}
/**
*
* @param coordinateRef
* reference to the related gnp position
*/
protected void setPositionReference(GnpPosition coordinateRef) {
this.coordinateRef = coordinateRef;
}
/**
*
* @return reference to the related gnp position, null, if no position was
* calculated
*/
protected GnpPosition getGnpPositionReference() {
return coordinateRef;
}
static int isNotLocatable = 0;
static int ccNotFound = 0;
static int cityNotFound = 0;
static int regionNotFound = 0;
public static void printLocatorStats() {
System.out.println("Locator stats: Hosts not locatable: " + isNotLocatable + ", city not found: " + cityNotFound + ", region not found: " + regionNotFound);
}
/**
* Try to locate the host on earth using the geolocator
*
* @param locator
*/
public void setLocation(Geolocator locator, IspLookupService service) {
this.locatable = false;
boolean ipFound = locator.search(ipAddress);
boolean ccFound = locator.getCountryCode() != null;
boolean cityFound = locator.getCityName() != null;
boolean regionFound = locator.getRegionName() != null;
// if (locator.search(ipAddress) && locator.getCountryCode() != null && locator.getCityName() != null && locator.getRegionName() != null && service.getISP(ipAddress) != null) {
if (ipFound && ccFound && cityFound && regionFound) {
this.countryCode = locator.getCountryCode();
if (useCountryNames) this.countryName = locator.getCountryName();
this.region = locator.getRegionName();
this.latitude = locator.getLatitude();
this.longitude = locator.getLongitude();
this.city = locator.getCityName();
if (service != null)
this.isp = service.getISP(ipAddress);
this.mapRef.getCountryLookup().addCountryFromGeoIP(countryCode, locator.getCountryName());
this.area = this.mapRef.getCountryLookup().getPingErRegionName(countryCode);
if (this.area != null)
this.locatable = true;
} else {
this.latitude = Double.NaN;
this.longitude = Double.NaN;
}
if (!this.locatable) {
if (!ipFound) isNotLocatable++;
if (!ccFound) ccNotFound++;
if (!cityFound) cityNotFound++;
if (!regionFound) regionNotFound++;
}
}
/**
*
* @return true, if host was located on a longitude/latitude
*/
public boolean isLocatable() {
return locatable;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
String returnString = "";
returnString += IPv4NetID.intToIP(ipAddress);
returnString += "\t(" + this.getCountryCode() + ")";
return returnString;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ipAddress;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Host other = (Host) obj;
if (ipAddress != other.ipAddress)
return false;
return true;
}
protected static CumulateRTTStrategy currentStrategy = new RTTCumulationStrategies.Minimum();
static AvgAccumulator avgPingAttemptsPerNode = new AvgAccumulator();
public interface CumulateRTTStrategy {
/**
* Cumulates the given rtts from multiple ping attempts.
* @param rtts
* @return Double.NaN, if rtts is empty or not cumulatable, else the cumulated value
*/
public Double cumulate(List<Double> rtts);
}
public static void setRTTCumulationStrategy(
CumulateRTTStrategy s) {
currentStrategy = s;
}
public static double getAvgPingAttemptsPerNode() {
return avgPingAttemptsPerNode.getAverage();
}
}
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network.gnp.topology;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.dom4j.tree.DefaultDocument;
import org.dom4j.tree.DefaultElement;
import de.tud.kom.p2psim.impl.network.IPv4NetID;
import de.tud.kom.p2psim.impl.network.gnp.geoip.IspLookupService;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB.City;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB.Continent;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB.Country;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB.PingErRegion;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB.Region;
import de.tud.kom.p2psim.impl.util.logging.SimLogger;
/**
* This class holds all informations needed to built an xml-Host File for the
* simulations with the GnpNetLayer and GnpLatencyModel
*
* @author Gerald Klunker
* @version 0.1, 05.02.2008
*
*/
public class HostMap {
private static Logger log = SimLogger.getLogger(HostMap.class);
private static final String GROUP_WORLD = "World";
private static final String COUNTRY_UNLOCATABLE = "#UNLOCATABLE_COUNTRY";
private static final String REGION_UNLOCATABLE = "#UNLOCATABLE_REGION";
private static final String PINGER_REGION_UNLOCATABLE = "#PINGER_REGION_UNLOCATABLE";
// importet Files
private HashMap<String, HashSet<Host>> skitterFiles = new HashMap<String, HashSet<Host>>();
private File geolocationFile;
private IspLookupService ispService;
// Host Index and Groups
private HashMap<Integer, Host> monitorIndex = new HashMap<Integer, Host>();
private HashMap<Integer, Host> hostIndex = new HashMap<Integer, Host>();
private ArrayList<Host>[][][] quickLookup;
private HashMap<String, Set<Host>> groups = new HashMap<String, Set<Host>>();
// Country - Region - PingEr dictionary
private PingErLookup pingErLookup = new PingErLookup();
private CountryLookup countryLookup = new CountryLookup();
private GnpSpace gnpRef;
/**
* import Hosts and RTTs from a CAIDA skitter File
*
* @param skitterFile
*/
public void importSkitterFile(File skitterFile, boolean oldFormat) {
try {
log.info("Importing skitter file: " + skitterFile.getAbsolutePath());
skitterFiles.put(skitterFile.getAbsolutePath(), new HashSet<Host>());
FileReader inputFile = new FileReader(skitterFile);
BufferedReader input = new BufferedReader(inputFile);
int validLines = 0;
String line = input.readLine();
while (line != null) {
if (line.length() < 1024) {
int commentbegin = line.indexOf("#");
String line2parse = commentbegin < 0?line:line.substring(0, commentbegin); //ignore comments
//System.out.println("Line to parse is: " + line2parse);
if (!"".equals(line2parse.trim())) {
if(oldFormat?parseLineOldFormat(line2parse, skitterFile):parseLineNewFormat(line2parse, skitterFile)) validLines++;
}
} else {
//sometimes weird long lines occur when the file is corrupted:
log.error("The weird long line with length " + line.length() + "' could not be parsed in skitter file " + skitterFile);
}
line = input.readLine();
}
System.gc();
System.out.println("Imported " + validLines + " valid entries from skitter file " + skitterFile + ".");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private boolean parseLineOldFormat(String line, File skitterFile) {
int monitorIP;
int peerIP;
double rtt;
Host currentMonitor;
Host currentPeer;
String[] tokens = line.split("\\s+");
if (tokens[0].equals("C") || tokens[0].equals("I")) {
if (tokens.length >= 5) {
String mo = tokens[1];
String pe = tokens[2];
String rt = tokens[4];
monitorIP = IPv4NetID.ipToInt(mo);
peerIP = IPv4NetID.ipToInt(pe);
rtt = Double.valueOf(rt);
currentMonitor = hostIndex.get(monitorIP);
if (currentMonitor == null) {
currentMonitor = new Host(monitorIP, this);
monitorIndex.put(monitorIP, currentMonitor);
hostIndex.put(monitorIP, currentMonitor);
}
if (!monitorIndex.containsValue(currentMonitor)) {
monitorIndex.put(monitorIP, currentMonitor);
}
currentMonitor.setHostType(Host.MONITOR);
currentPeer = hostIndex.get(peerIP);
if (currentPeer == null) {
currentPeer = new Host(peerIP, this);
currentPeer.setHostType(Host.HOST);
hostIndex.put(peerIP, currentPeer);
}
currentPeer.addRtt(currentMonitor, rtt);
skitterFiles.get(skitterFile.getAbsolutePath()).add(currentPeer);
return true;
} else log.error("The line '" + line + "' did not contain enough elements. in skitter file " + skitterFile);
}
return false;
}
private boolean parseLineNewFormat(String line, File skitterFile) {
int monitorIP;
int peerIP;
double rtt;
Host currentMonitor;
Host currentPeer;
String[] tokens = line.split("\\s+");
//System.out.println(StringToolkit.arrayToString(tokens, "|"));
if (tokens[0].equals("T") && tokens.length >= 7) {
if (tokens[6].equals("R") && tokens.length >= 8) {
String mo = tokens[1];
String pe = tokens[2];
String rt = tokens[7];
monitorIP = IPv4NetID.ipToInt(mo);
peerIP = IPv4NetID.ipToInt(pe);
rtt = Double.valueOf(rt);
currentMonitor = hostIndex.get(monitorIP);
if (currentMonitor == null) {
currentMonitor = new Host(monitorIP, this);
monitorIndex.put(monitorIP, currentMonitor);
hostIndex.put(monitorIP, currentMonitor);
}
if (!monitorIndex.containsValue(currentMonitor)) {
monitorIndex.put(monitorIP, currentMonitor);
}
currentMonitor.setHostType(Host.MONITOR);
currentPeer = hostIndex.get(peerIP);
if (currentPeer == null) {
currentPeer = new Host(peerIP, this);
currentPeer.setHostType(Host.HOST);
hostIndex.put(peerIP, currentPeer);
}
currentPeer.addRtt(currentMonitor, rtt);
skitterFiles.get(skitterFile.getAbsolutePath()).add(currentPeer);
//System.out.println("Successfully loaded value.");
return true;
} else log.error("The line '" + line + "' did not contain enough elements. in skitter file " + skitterFile);
}
return false;
}
/**
* import PingER summary report File
*
* @param file
*/
public void importPingErMinimumRtt(File file) {
log.debug("Importing MinimumRtt PingER-Summary-Report-File: " + file.getAbsolutePath());
pingErLookup.loadFromTSV(file, PingErLookup.DataType.MIN_RTT);
}
/**
* import PingER summary report File
*
* @param file
*/
public void importPingErAverageRtt(File file) {
log.debug("Importing AverageRtt PingER-Summary-Report-File: " + file.getAbsolutePath());
pingErLookup.loadFromTSV(file, PingErLookup.DataType.AVERAGE_RTT);
}
/**
* import PingER summary report File
*
* @param file
*/
public void importPingErDelayVariation(File file) {
log.debug("Importing DelayVariation PingER-Summary-Report-File: " + file.getAbsolutePath());
pingErLookup.loadFromTSV(file, PingErLookup.DataType.VARIATION_RTT);
}
/**
* import PingER summary report File
*
* @param file
*/
public void importPingErPacketLoss(File file) {
log.debug("Importing PacketLoss PingER-Summary-Report-File: " + file.getAbsolutePath());
pingErLookup.loadFromTSV(file, PingErLookup.DataType.PACKET_LOSS);
}
/**
*
* @return country dictionary
*/
public CountryLookup getCountryLookup() {
return countryLookup;
}
/**
*
* @return pingerEr lookup table
*/
public PingErLookup getPingErLookup() {
return pingErLookup;
}
/**
*
* @param longitude
* @param latitude
* @return set of the nearest hosts to longitude/latitude position
*/
public Set<Host> getNearestHosts(double longitude, double latitude) {
HashSet<Host> result = new HashSet<Host>();
int index0 = (int) Math.floor(HostMap.getGeographicalDistance(90, 0, latitude, longitude) / 1000.0);
int index1 = (int) Math.floor(HostMap.getGeographicalDistance(0, 0, latitude, longitude) / 1000.0);
int index2 = (int) Math.floor(HostMap.getGeographicalDistance(0, 90, latitude, longitude) / 1000.0);
PeerComparatorDistance comparator = new PeerComparatorDistance();
comparator.setPosition(latitude, longitude);
Host peer = null;
if (quickLookup != null && quickLookup[index0][index1][index2] != null) {
for (Host p : quickLookup[index0][index1][index2]) {
if (peer == null) {
peer = p;
} else if (comparator.compare(peer, p) == 1) {
peer = p;
}
}
for (Host p : quickLookup[index0][index1][index2]) {
if (comparator.compare(peer, p) == 0)
result.add(p);
}
}
return result;
}
/**
* rebuilt an array of hosts for fast finding of nearest hosts
*/
private void builtQuickLookup() {
quickLookup = new ArrayList[21][21][21];
int index0 = 0;
int index1 = 0;
int index2 = 0;
Set<Integer> ips = this.hostIndex.keySet();
for (Integer ip : ips) {
index0 = (int) Math.floor(HostMap.getGeographicalDistance(90, 0, hostIndex.get(ip).getLatitude(), hostIndex.get(ip).getLongitude()) / 1000.0);
index1 = (int) Math.floor(HostMap.getGeographicalDistance(0, 0, hostIndex.get(ip).getLatitude(), hostIndex.get(ip).getLongitude()) / 1000.0);
index2 = (int) Math.floor(HostMap.getGeographicalDistance(0, 90, hostIndex.get(ip).getLatitude(), hostIndex.get(ip).getLongitude()) / 1000.0);
if (quickLookup[index0][index1][index2] == null)
quickLookup[index0][index1][index2] = new ArrayList<Host>();
quickLookup[index0][index1][index2].add(hostIndex.get(ip));
}
}
/**
*
* @return reference to the related GNP Space object
*/
public GnpSpace getGnpRef() {
return gnpRef;
}
/**
*
* @param gnp
* reference to the related GNP Space object
*/
public void setGnpRef(GnpSpace gnp) {
gnpRef = gnp;
}
/**
*
* @return map of importet skitter files and hosts
*/
public HashMap<String, HashSet<Host>> getImportedSkitterFiles() {
return skitterFiles;
}
/**
* counts the number of hosts with a certain number of measured RTTs [0]:
* number of Hosts with 0 measured RTTs, [1] number of Hosts with 1 measured
* RTTs ...
*
* @return map from number of measured RTTs to number of related hosts
*/
public int[] getConnectivityOfHosts() {
int[] counter = new int[getNoOfMonitors() + 1];
for (Host host : hostIndex.values()) {
if (host.getHostType() == Host.HOST)
counter[host.getMeasuredMonitors().size()]++;
}
return counter;
}
/**
*
* @param groupName
* @return Set of Host related to the Group
*/
public Collection<Host> getGroup(String groupName) {
if (groups.containsKey(groupName))
return groups.get(groupName);
else
return new HashSet<Host>();
}
/**
*
* @return map of groupnames to related hosts
*/
public HashMap<String, Set<Host>> getGroups() {
return groups;
}
/**
*
* @param groupName
* @param host
*/
public void addHostToGroup(String groupName, Host host) {
String name = groupName.replace(" ", "");
if (!groups.containsKey(name))
groups.put(name, new HashSet<Host>());
groups.get(name).add(host);
}
/**
*
* @param groupName
* @param hosts
* set of hosts
*/
public void addHostToGroup(String groupName, Collection<Host> hosts) {
String name = groupName.replace(" ", "");
if (!groups.containsKey(name))
groups.put(name, new HashSet<Host>());
groups.get(name).addAll(hosts);
}
/**
*
* @param groupName
* @param grid
*/
public void addHostToGroup(String groupName, boolean grid[][]) {
Set<Host>[][] peerGrid = getHostGrid(grid.length, grid[0].length);
for (int x = 0; x < grid.length; x++) {
for (int y = 0; y < grid[x].length; y++) {
if (grid[x][y]) {
addHostToGroup(groupName, peerGrid[x][y]);
}
}
}
}
/**
*
* @param resLon
* number of horizontal divisions
* @param resLat
* number of vertical divisions
* @return hosts grouped by their geographical position
*/
private Set<Host>[][] getHostGrid(int resLon, int resLat) {
Set<Host>[][] peerGrid = new HashSet[resLon][resLat];
int posLon;
int posLat;
double stepLon = 360 / (double) resLon;
double stepLat = 180 / (double) resLat;
for (Host host : hostIndex.values()) {
posLon = (int) Math.floor((180 + host.getLongitude()) / stepLon);
posLat = (int) Math.floor((90 + host.getLatitude()) / stepLat);
if (peerGrid[posLon][posLat] == null)
peerGrid[posLon][posLat] = new HashSet<Host>();
peerGrid[posLon][posLat].add(host);
}
return peerGrid;
}
/**
*
* @param groupName
*/
public void removeGroup(String groupName) {
groups.remove(groupName);
}
/**
*
* @param groupNames
* set of group names
*/
public void removeGroup(Set<String> groupNames) {
for (String name : groupNames)
removeGroup(name);
}
/**
* reduce the number of hosts in a group
*
* @param groupName
* @param noOfHosts
*/
public void scaleGroup(String groupName, int newSize) {
Set<Host> oldGroup = groups.get(groupName);
Set<Host> newGroup = new HashSet<Host>();
while (newGroup.size() < newSize && oldGroup.size() > 0) {
Host[] hosts = oldGroup.toArray(new Host[0]);
for (int c = 0; c < newSize - newGroup.size(); c++) {
int random = (int) Math.floor(Math.random() * hosts.length);
newGroup.add(hosts[random]);
oldGroup.remove(hosts[random]);
}
}
oldGroup.clear();
oldGroup.addAll(newGroup);
}
/**
* generate groups with the name of GeoIP country names
*/
public void builtCountryGroups() {
log.debug("Built Country Groups");
for (Host host : hostIndex.values()) {
String country = countryLookup.getGeoIpCountryName(host.getCountryCode());
if (country == null)
country = COUNTRY_UNLOCATABLE;
this.addHostToGroup(country, host);
}
}
/**
* generate groups with the name of GeoIP country names
*/
public void builtRegionGroups() {
for (Host host : hostIndex.values()) {
String region = host.getRegion();
if (region == null)
region = REGION_UNLOCATABLE;
this.addHostToGroup(region, host);
}
}
/**
* generate groups with the name of PingER region names
*/
public void builtPingerGroups() {
log.debug("Built PingEr Groups");
for (Host host : hostIndex.values()) {
String country = countryLookup.getPingErRegionName(host.getCountryCode());
if (country == null)
country = PINGER_REGION_UNLOCATABLE;
this.addHostToGroup(country, host);
}
}
/**
* built a group with all hosts
*/
public void builtWorldGroups() {
log.debug("Built World Group");
this.addHostToGroup(GROUP_WORLD, hostIndex.values());
}
/**
*
* @return number of hosts in this map
*/
public int getNoOfHosts() {
return hostIndex.size();
}
/**
*
* @return number of monitors in this map
*/
public int getNoOfMonitors() {
return monitorIndex.size();
}
/**
*
* @param file
* filename of a GeoIP binary database
*/
public void setGeolocationDatabase(File file) {
geolocationFile = file;
}
public void setIspLocationDatabase(String db) {
ispService = new IspLookupService(db);
}
/**
*
* @return filename of the current GeoIP database
*/
public File getGeolocationDatabase() {
return geolocationFile;
}
/**
* position all hosts with the current GeoIP database
*/
public void setLocationOfHosts() {
if (geolocationFile == null) {
return;
}
Geolocator locator = new GeolocatorGeoIP(geolocationFile);
for (Host host : hostIndex.values()) {
host.setLocation(locator, ispService);
}
builtQuickLookup();
// distanceVsRttPlot("test100", null, 100);
}
/**
*
* @return map from 2-digits country code to the related hosts
*/
public HashMap<String, HashSet<Host>> getLocations() {
HashMap<String, HashSet<Host>> locations = new HashMap<String, HashSet<Host>>();
locations.put("# LOCATABLE", new HashSet<Host>());
locations.put("# UNLOCATABLE", new HashSet<Host>());
for (Host host : hostIndex.values()) {
if (host.isLocatable()) {
if (!locations.containsKey(host.getCountryCode()))
locations.put(host.getCountryCode(), new HashSet<Host>());
locations.get(host.getCountryCode()).add(host);
locations.get("# LOCATABLE").add(host);
} else {
locations.get("# UNLOCATABLE").add(host);
}
}
return locations;
}
/**
*
* @return map from ip to related monitor Host object
*/
public HashMap<Integer, Host> getMonitorIndex() {
return monitorIndex;
}
/**
*
* @return map from ip to related Host object
*/
public HashMap<Integer, Host> getHostIndex() {
return hostIndex;
}
/**
* make the measured inter-monitor RTTs adjacency matrix symmetrical. => RTT
* A->B = RTT B->A assumtion is needed within the GNP coordinate model.
*/
public void makeSymmetrical() {
for (Host monitorA : monitorIndex.values()) {
for (Host monitorB : monitorIndex.values()) {
if (monitorA == monitorB) {
monitorA.removeRTT(monitorB);
} else {
double rtt1 = monitorA.getRtt(monitorB);
double rtt2 = monitorB.getRtt(monitorA);
double newRtt = Double.NaN;
if (rtt1 > 0 && rtt2 > 0)
newRtt = (rtt1 + rtt2) / 2;
else if (rtt1 > 0)
newRtt = rtt1;
else if (rtt2 > 0)
newRtt = rtt2;
monitorA.setRtt(monitorB, newRtt);
monitorB.setRtt(monitorA, newRtt);
}
}
}
}
/**
*
* @param p1
* host 1
* @param p2
* host 2
* @return distance in km
*/
private static double getGeographicalDistance(Host p1, Host p2) {
return HostMap.getGeographicalDistance(p1.getLatitude(), p1.getLongitude(), p2.getLatitude(), p2.getLongitude());
}
/**
*
* @param latitude1
* host 1
* @param longitude1
* host 1
* @param latitude2
* host 2
* @param longitude2
* host 2
* @return distance in km
*/
private static double getGeographicalDistance(double latitude1, double longitude1, double latitude2, double longitude2) {
GeographicPosition pos1 = new GeographicPosition(longitude1, latitude1);
GeographicPosition pos2 = new GeographicPosition(longitude2, latitude2);
return pos1.getDistance(pos2);
}
/**
* unlocatable on the globe (unkonw ip, proxy, satelite)
*
* @return number of unlocatable hosts
*/
public int getNoOfUnlocatableHosts() {
int unlocatedPeers = 0;
int unlocatedMonitors = 0;
Set<Integer> ips = this.hostIndex.keySet();
for (Integer ip : ips) {
unlocatedPeers += (hostIndex.get(ip).isLocatable()) ? 0 : 1;
unlocatedMonitors += (hostIndex.get(ip).isLocatable() || hostIndex.get(ip).getHostType() == Host.HOST) ? 0 : 1;
}
return unlocatedPeers - unlocatedMonitors;
}
/**
*
* @param monitor
*/
public void removeMonitor(Host monitor) {
this.monitorIndex.remove(monitor.getIpAddress());
this.hostIndex.remove(monitor.getIpAddress());
for (Host host : hostIndex.values()) {
host.removeRTT(monitor);
}
this.builtQuickLookup();
}
/**
*
* Removes the given set of hosts from the map.
*
* @param hosts
* set of hosts
*/
public void removeHosts(Set<Host> hosts) {
for (Host host : hosts) {
// if (host.getHostType() == Host.HOST) {
if (this.getGnpRef() != null)
this.getGnpRef().removePosition(host.getIpAddress());
this.hostIndex.remove(host.getIpAddress());
// }
}
for (Set<Host> group : groups.values())
group.removeAll(hosts);
countryLookup.keepCountries(getLocations().keySet());
this.builtQuickLookup();
}
/**
* SEEMS TO remove all hosts that were pinged by exactly noOfConnections
* distinct monitors.
*
* removes all hosts that have noOfConnections measured RTTs
*
* @param noOfConnections
*/
public void removeHosts(int noOfConnections) {
Set<Host> hosts = new HashSet<Host>();
for (Host host : hostIndex.values()) {
if (host.getMeasuredMonitors().size() == noOfConnections)
hosts.add(host);
}
removeHosts(hosts);
}
/**
* remove all hosts that have at least one measured RTT with a error bigger
* than the argument. Removing that errors will improve the quality of the
* Gnp Space.
*
* @param error
* relative error
*/
public void removeHostsWithMaximumRelativeError(double error) {
HashSet<Host> delete = new HashSet<Host>();
for (Host host : hostIndex.values()) {
for (int c = 0; c < gnpRef.getNumberOfMonitors(); c++) {
double relError = Math.abs(host.getGnpPositionReference().getDirectionalRelativError(gnpRef.getMonitorPosition(c)));
if (relError >= error) {
delete.add(host);
break;
}
}
}
removeHosts(delete);
}
/**
* SEEMS TO only keep the 'noOfMonitorsToKeep' monitor hosts in the GNP space that have the
* maximum distance between each other, the other ones are being deleted.
*
* keeps the maximum separated monitors
*
* @param noOfMonitorsToKeep
*/
public void removeMonitorsKeepMaximumSparation(int noOfMonitorsToKeep) {
ArrayList<Host> maxSeperatedPeers = getMaximumSeparatedMonitors(noOfMonitorsToKeep);
ArrayList<Host> deleteMonitors = new ArrayList<Host>();
for (Host monitor : monitorIndex.values()) {
if (!maxSeperatedPeers.contains(monitor))
deleteMonitors.add(monitor);
}
for (Host monitor : deleteMonitors) {
this.removeMonitor(monitor);
}
}
/**
*
*
* @param noOfMonitors
* @return maximum separated monitors
*/
private ArrayList<Host> getMaximumSeparatedMonitors(int noOfMonitors) {
ArrayList<ArrayList<Host>> allCombinations = getMonitorCombinations(noOfMonitors);
int posWithMax = 0;
double valueMax = 0.0;
for (int c = 0; c < allCombinations.size(); c++) {
double currentDistance = getInterMonitorDistance(allCombinations.get(c));
if (currentDistance > valueMax) {
valueMax = currentDistance;
posWithMax = c;
}
}
return allCombinations.get(posWithMax);
}
/**
*
* @param monitors
* @return sum measured RTTs between monitors
*/
private double getInterMonitorDistance(ArrayList<Host> monitors) {
double result = 0.0;
for (int c = 0; c < monitors.size() - 1; c++)
for (int d = c + 1; d < monitors.size(); d++)
result += monitors.get(c).getRtt(monitors.get(d));
return result;
}
/**
*
* @param size
* @return all combinations of monitors with size "size"
*/
private ArrayList<ArrayList<Host>> getMonitorCombinations(int size) {
ArrayList<Host> monitors = new ArrayList<Host>();
monitors.addAll(monitorIndex.values());
Collections.sort(monitors, new PeerComparatorNoOfConnections());
return builtRecursive(new ArrayList<Host>(), size, monitors, 0);
}
/**
* recursive built of all combinations of monitors with size "size"
*
* @param current
* @param max
* @param monitors
* @param posInMonitors
* @return array of combinations
*/
private ArrayList<ArrayList<Host>> builtRecursive(ArrayList<Host> current, int max, ArrayList<Host> monitors, int posInMonitors) {
ArrayList<ArrayList<Host>> result = new ArrayList<ArrayList<Host>>();
if (current.size() == max) {
result.add(current);
return result;
} else {
for (int c = posInMonitors; c < monitors.size() - (max - current.size()); c++) {
ArrayList<Host> copy = (ArrayList<Host>) current.clone();
copy.add(monitors.get(c));
result.addAll(builtRecursive(copy, max, monitors, c + 1));
}
return result;
}
}
/**
* generate two files with distance - rtt pairs, that can be used with
* gnuplot
*
* filename.txt1 plots each measured host - monitor RTT filename.txt2
* aggregates distances within a range and calculates the average RTT
*
* @param filename
* @param steps
* number of divisions within the 0 - 20000km for aggregated plot
*/
public void distanceVsRttPlot(String filename, Host monitor, int steps) {
try {
double[] test1 = new double[steps];
int[] test2 = new int[steps];
FileWriter all = new FileWriter(filename + ".txt1");
for (Host host : hostIndex.values()) {
for (Host mon : host.getMeasuredMonitors()) {
double distance = getGeographicalDistance(host, mon);
double rtt = host.getRtt(mon);
all.write(distance + " " + rtt + "\n");
int pos = (int) Math.floor((distance / 20000.0) * steps);
test1[pos] += rtt;
test2[pos]++;
}
}
all.close();
all = new FileWriter(filename + ".txt2");
for (int c = 0; c < steps; c++) {
double x = (c * (20000.0 / steps)) + (20000.0 / (2 * steps));
double y = test1[c] / test2[c];
all.write(x + " " + y + "\n");
}
all.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* saves host postion location, GNP position, groups, GNP Space, PingER
* Lookup table in an xml file used within the simulation
*
* @param file
*/
public void exportToXml(File file) {
log.debug("Export Hosts to an XML File");
try {
OutputFormat format = OutputFormat.createPrettyPrint();
OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
XMLWriter writer = new XMLWriter(out, format);
writer.write(getDocument());
writer.close();
} catch (IOException e) {
System.out.println(e);
}
}
/**
*
* @return xml Document Object of relevant Class Attributes
*/
private Document getDocument() {
Set<Host> hosts = new HashSet<Host>();
// "GroupLookup" Element
log.debug("Generate XML-Element \"GroupLookup\"");
DefaultElement groups = new DefaultElement("GroupLookup");
for (String group : this.groups.keySet()) {
log.debug(" - Export Group: " + group);
hosts.addAll(this.groups.get(group));
DefaultElement peerXml = new DefaultElement("Group");
peerXml.addAttribute("id", group);
peerXml.addAttribute("maxsize", String.valueOf(this.groups.get(group).size()));
String ip = "";
int x = 0;
int blockSize = 1000;
// IP Block of 1000, too long blocks leads to hangUp ??
for (Host host : this.groups.get(group)) {
x++;
ip += "," + host.getIpAddress();
if (x % blockSize == 0) {
ip = ip.substring(1);
DefaultElement ips = new DefaultElement("IPs");
ips.addAttribute("value", ip);
peerXml.add(ips);
ip = "";
}
}
if (ip.length() > 0) {
ip = ip.substring(1);
DefaultElement ips = new DefaultElement("IPs");
ips.addAttribute("value", ip);
peerXml.add(ips);
}
groups.add(peerXml);
}
// "Hosts" Element
log.debug("Generate XML-Element \"Hosts\"");
DefaultElement peers = new DefaultElement("Hosts");
for (Host host : hosts) {
DefaultElement peer = new DefaultElement("Host");
peer.addAttribute("ip", String.valueOf(host.getIpAddress()));
String area = (host.getArea() != null) ? host.getArea() : "--";
peer.addAttribute("continentalArea", area);
String countryCode = (host.getCountryCode() != null) ? host.getCountryCode() : "--";
peer.addAttribute("countryCode", countryCode);
String region = (host.getRegion() != null) ? host.getRegion() : "--";
peer.addAttribute("region", region);
String city = (host.getCity() != null) ? host.getCity() : "--";
peer.addAttribute("city", city);
String isp = (host.getISP() != null) ? host.getISP() : "--";
peer.addAttribute("isp", isp);
peer.addAttribute("longitude", String.valueOf(host.getLongitude()));
peer.addAttribute("latitude", String.valueOf(host.getLatitude()));
String coordinates = (host.getGnpPositionReference() != null) ? host.getGnpPositionReference().getCoordinateString() : "0";
peer.addAttribute("coordinates", coordinates);
peers.add(peer);
}
// "PingErLookup" Elements
log.debug("Generate XML-Element \"PingErLookup\"");
Element pingEr = pingErLookup.exportToXML();
// "CountryLookup" Element
log.debug("Generate XML-Element \"CountryLookup\"");
Element country = countryLookup.exportToXML();
DefaultDocument document = new DefaultDocument(new DefaultElement("gnp"));
document.getRootElement().add(groups);
document.getRootElement().add(peers);
document.getRootElement().add(pingEr);
document.getRootElement().add(country);
return document;
}
public void insertIntoRelationalDB(NetMeasurementDB db) {
Map<Host, NetMeasurementDB.Host> hostsScanned = new HashMap<Host, NetMeasurementDB.Host>();
for (String group : this.groups.keySet()) {
Set<Host> hosts = this.groups.get(group);
List<NetMeasurementDB.Host> dbHosts = new ArrayList<NetMeasurementDB.Host>(hosts.size());
for (Host h : hosts) {
NetMeasurementDB.Host host = hostsScanned.get(h);
if (host == null) {
String countryStr = h.getCountryName();
String pingErRegionStr = countryLookup.getPingErRegionName(countryStr);
assert pingErRegionStr != null : "No PingEr region found for country " + countryStr;
City city = getCity(db, h.getCity(), h.getRegion(), countryStr, h.getCountryCode(), h.getArea(), pingErRegionStr);
GnpPosition pos = h.getGnpPositionReference();
List<Double> gnpCoords;
if (pos != null) {
int dims = pos.getNoOfDimensions();
gnpCoords = new ArrayList<Double>(dims);
for (int i= 0; i<dims; i++) gnpCoords.add(pos.getGnpCoordinates(i));
} else {
gnpCoords = Collections.emptyList();
}
host = db.new Host(h.getIpAddress(), city, h.getLatitude(), h.getLongitude(), gnpCoords);
hostsScanned.put(h, host);
}
dbHosts.add(host);
}
db.new Group(group, dbHosts);
}
pingErLookup.insertIntoRelationalDB(db);
}
public static City getCity(NetMeasurementDB db, String cityStr, String regionStr, String countryStr, String countryCode, String continentStr, String pingErRgName) {
//the host never occured in a group before. Putting it into the DB.
//FIXME: some cities or regions occur multiple times but in different regions/countries, we will have to separate them! Infers problem of DB structure.
City city = db.getStringAddrObjFromStr(City.class, cityStr);
if (city == null) {
Region region = db.getStringAddrObjFromStr(Region.class, regionStr);
if (region == null) {
Country country = db.getStringAddrObjFromStr(Country.class, countryStr);
if (country == null) {
Continent continent = db.getStringAddrObjFromStr(Continent.class, continentStr);
if (continent == null) continent = db.new Continent(continentStr);
PingErRegion pErRegion = db.getStringAddrObjFromStr(PingErRegion.class, pingErRgName);
if (pErRegion == null) pErRegion = db.new PingErRegion(pingErRgName);
country = db.new Country(countryStr, continent, pErRegion, countryCode);
}
region = db.new Region(regionStr, country);
}
city = db.new City(cityStr, region);
}
return city;
}
/**
* Comparator implementation for sorting of Host with the geographical
* distance to a given position
*/
private class PeerComparatorDistance implements Comparator<Host> {
double latitude;
double longitude;
public void setPosition(double latitude, double longitude) {
this.latitude = latitude;
this.longitude = longitude;
}
public int compare(Host peer1, Host peer2) {
double distance1 = HostMap.getGeographicalDistance(peer1.getLatitude(), peer1.getLongitude(), latitude, longitude);
double distance2 = HostMap.getGeographicalDistance(peer2.getLatitude(), peer2.getLongitude(), latitude, longitude);
if (distance1 < distance2)
return -1;
else if (distance1 > distance2)
return 1;
else
return 0;
}
}
/**
* Comparator implementation for sorting of Host with the number of measured
* RTTs per Host.
*/
private class PeerComparatorNoOfConnections implements Comparator<Host> {
public int compare(Host peer1, Host peer2) {
int coonections1 = peer1.getMeasuredMonitors().size();
int coonections2 = peer2.getMeasuredMonitors().size();
if (coonections1 < coonections2)
return 1;
else if (coonections1 > coonections2)
return -1;
else
return 0;
}
}
}
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network.gnp.topology;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.apache.log4j.Logger;
import org.dom4j.Element;
import org.dom4j.tree.DefaultElement;
import umontreal.iro.lecuyer.probdist.LognormalDist;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB.Country;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB.GlobalSummaryRelation;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB.PingErRegion;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB.RegionRegionSummaryRelation;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB.SummaryRelation;
import de.tud.kom.p2psim.impl.util.logging.SimLogger;
/**
* This Class Implements a container for the PingER summary reports used as a
* lookup table for rtt, packet loss and jitter distribution
*
* @author Gerald Klunker
* @version 0.1, 05.02.2008
*
*/
public class PingErLookup {
private static Logger log = SimLogger.getLogger(PingErLookup.class);
private HashMap<String, String> files = new HashMap<String, String>();
public enum DataType {
MIN_RTT, AVERAGE_RTT, VARIATION_RTT, PACKET_LOSS
}
private HashMap<String, HashMap<String, LinkProperty>> data = new HashMap<String, HashMap<String, LinkProperty>>();
private LinkProperty averageLinkProperty;
/**
*
* @param from
* PingEr Country or Region String
* @param to
* PingEr Country or Region String
* @return minimum RTT
*/
public double getMinimumRtt(String from, String to) {
return data.get(from).get(to).minRtt;
}
/**
*
* @param from
* PingEr Country or Region String
* @param to
* PingEr Country or Region String
* @return average RTT
*/
public double getAverageRtt(String from, String to) {
return data.get(from).get(to).averageRtt;
}
/**
*
* @param from
* PingEr Country or Region String
* @param to
* PingEr Country or Region String
* @return IQR of RTT
*/
public double getRttVariation(String from, String to) {
return data.get(from).get(to).delayVariation;
}
/**
*
* @param from
* PingEr Country or Region String
* @param to
* PingEr Country or Region String
* @return packet Loss Rate in Percent
*/
public double getPacktLossRate(String from, String to) {
return data.get(from).get(to).packetLoss;
}
/**
*
* @param ccFrom
* 2-digits Country Code
* @param ccTo
* 2-digits Country Code
* @param cl
* GeoIP to PingEr Dictionary
* @return log-normal jitter distribution
*/
public LognormalDist getJitterDistribution(String ccFrom, String ccTo,
CountryLookup cl) {
return getLinkProperty(ccFrom, ccTo, cl).getJitterDistribution();
}
/**
*
* @param ccFrom
* 2-digits Country Code
* @param ccTo
* 2-digits Country Code
* @param cl
* GeoIP to PingEr Dictionary
* @return minimum RTT
*/
public double getMinimumRtt(String ccFrom, String ccTo, CountryLookup cl) {
return getLinkProperty(ccFrom, ccTo, cl).minRtt;
}
/**
*
* @param ccFrom
* 2-digits Country Code
* @param ccTo
* 2-digits Country Code
* @param cl
* GeoIP to PingEr Dictionary
* @return average RTT
*/
public double getAverageRtt(String ccFrom, String ccTo, CountryLookup cl) {
return getLinkProperty(ccFrom, ccTo, cl).averageRtt;
}
/**
*
* @param ccFrom
* 2-digits Country Code
* @param ccTo
* 2-digits Country Code
* @param cl
* GeoIP to PingEr Dictionary
* @return packet Loss Rate in Percent
*/
public double getPacktLossRate(String ccFrom, String ccTo, CountryLookup cl) {
return getLinkProperty(ccFrom, ccTo, cl).packetLoss;
}
/**
*
* @param from
* PingEr Country or Region String
* @param to
* PingEr Country or Region String
* @return LinkProperty object that contains all PingEr informations for a
* link
*/
private LinkProperty getLinkProperty(String from, String to) {
return data.get(from).get(to);
}
/**
* Method will search the available PingER Data for best fit with ccFrom and
* ccTo. If there is no Country-Country connections other possibilities are
* testet like Country-Region, Region-Country, Region-Region also in
* opposite direction. If there is no PingEr Data for the pair a
* World-Average Link Property will be returned.
*
* @param ccFrom
* 2-digits Country Code
* @param ccTo
* 2-digits Country Code
* @param cl
* GeoIP to PingEr Dictionary
* @return LinkProperty object that contains all PingEr informations for a
* link
*/
private LinkProperty getLinkProperty(String ccFrom, String ccTo,
CountryLookup cl) {
String countrySender = cl.getPingErCountryName(ccFrom);
String countryReceiver = cl.getPingErCountryName(ccTo);
String regionSender = cl.getPingErRegionName(ccFrom);
String regionReceiver = cl.getPingErRegionName(ccTo);
if (contains(countrySender, countryReceiver))
return getLinkProperty(countrySender, countryReceiver);
if (contains(countrySender, regionReceiver))
return getLinkProperty(countrySender, regionReceiver);
if (contains(regionSender, countryReceiver))
return getLinkProperty(regionSender, countryReceiver);
if (contains(regionSender, regionReceiver))
return getLinkProperty(regionSender, regionReceiver);
if (contains(countryReceiver, countrySender))
return getLinkProperty(countryReceiver, countrySender);
if (contains(countryReceiver, regionSender))
return getLinkProperty(countryReceiver, regionSender);
if (contains(regionReceiver, countrySender))
return getLinkProperty(regionReceiver, countrySender);
if (contains(regionReceiver, regionSender))
return getLinkProperty(regionReceiver, regionSender);
log.debug("Using World-Average Link Propertiess for " + ccFrom + "->"
+ ccTo);
return getAverageLinkProperty();
}
/**
*
* @param from
* PingEr Country or Region String
* @param to
* PingEr Country or Region String
* @return true if there are PinEr Data for the pair
*/
private boolean contains(String from, String to) {
if (data.containsKey(from)) {
if (data.get(from).containsKey(to)) {
return true;
}
}
return false;
}
/**
*
* @param from
* PingEr Country or Region String
* @param to
* PingEr Country or Region String
* @param value
* @param dataType
*/
private void setData(String from, String to, double value, DataType dataType) {
if (!data.containsKey(from))
data.put(from, new HashMap<String, LinkProperty>());
if (!data.containsKey(to))
data.put(to, new HashMap<String, LinkProperty>());
if (!data.get(from).containsKey(to))
data.get(from).put(to, new LinkProperty());
LinkProperty values = data.get(from).get(to);
if (dataType == DataType.MIN_RTT)
values.minRtt = value;
else if (dataType == DataType.AVERAGE_RTT)
values.averageRtt = value;
else if (dataType == DataType.VARIATION_RTT)
values.delayVariation = value;
else if (dataType == DataType.PACKET_LOSS)
values.packetLoss = value;
}
/**
* Loads the Class Attributes from an XML Element
*
* @param element
*/
public void loadFromXML(Element element) {
for (Iterator<Element> iter = element.elementIterator("SummaryReport"); iter
.hasNext();) {
Element variable = iter.next();
String regionFrom = variable.attributeValue("from");
String regionTo = variable.attributeValue("to");
double minRtt = Double.parseDouble(variable
.attributeValue("minimumRtt"));
double averageRtt = Double.parseDouble(variable
.attributeValue("averageRtt"));
double delayVariation = Double.parseDouble(variable
.attributeValue("delayVariation"));
double packetLoss = Double.parseDouble(variable
.attributeValue("packetLoss"));
setData(regionFrom, regionTo, minRtt, DataType.MIN_RTT);
setData(regionFrom, regionTo, averageRtt, DataType.AVERAGE_RTT);
setData(regionFrom, regionTo, delayVariation,
DataType.VARIATION_RTT);
setData(regionFrom, regionTo, packetLoss, DataType.PACKET_LOSS);
}
}
/**
* Export the Class Attributes to an XML Element
*
* @param element
*/
public Element exportToXML() {
DefaultElement pingEr = new DefaultElement("PingErLookup");
Set<String> fromKeys = data.keySet();
for (String from : fromKeys) {
Set<String> toKeys = data.get(from).keySet();
for (String to : toKeys) {
DefaultElement pingErXml = new DefaultElement("SummaryReport");
pingErXml.addAttribute("from", from);
pingErXml.addAttribute("to", to);
pingErXml.addAttribute("minimumRtt", String
.valueOf(getMinimumRtt(from, to)));
pingErXml.addAttribute("averageRtt", String
.valueOf(getAverageRtt(from, to)));
pingErXml.addAttribute("delayVariation", String
.valueOf(getRttVariation(from, to)));
pingErXml.addAttribute("packetLoss", String
.valueOf(getPacktLossRate(from, to)));
pingEr.add(pingErXml);
}
}
return pingEr;
}
/**
* Loads PingEr Summary Reports in CVS-Format as provided on the PingER
* Website
*
* @param file
* @param dataType
*/
public void loadFromTSV(File file, DataType dataType) {
String[][] data = parseTsvFile(file);
for (int i = 1; i < data.length - 1; i++) { // To
for (int j = 1; j < data[i].length; j++) { // From
if (!data[i][j].equals("."))
setData(data[0][j].replace('+', ' '), data[i][0].replace(
'+', ' '), Double.parseDouble(data[i][j]), dataType);
}
}
files.put(file.getName(), dataType.name());
}
/**
*
* @param file
* @return TSV-File Data in an 2-dimensional String Array
*/
private String[][] parseTsvFile(File file) {
ArrayList<String[]> tempResult = new ArrayList<String[]>();
String[][] result = new String[1][1];
try {
FileReader inputFile = new FileReader(file);
BufferedReader input = new BufferedReader(inputFile);
String line = input.readLine();
while (line != null) {
tempResult.add(line.split("\t"));
line = input.readLine();
}
} catch (IOException e) {
e.printStackTrace();
}
return tempResult.toArray(result);
}
/**
*
* @return world-average LinkProperty Object
*/
private LinkProperty getAverageLinkProperty() {
if (averageLinkProperty == null) {
int counter = 0;
averageLinkProperty = new LinkProperty();
Set<String> fromKeys = data.keySet();
for (String from : fromKeys) {
Set<String> toKeys = data.get(from).keySet();
for (String to : toKeys) {
averageLinkProperty.minRtt += getMinimumRtt(from, to);
averageLinkProperty.averageRtt += getAverageRtt(from, to);
averageLinkProperty.delayVariation += getRttVariation(from,
to);
averageLinkProperty.packetLoss += getPacktLossRate(from, to);
counter++;
}
}
averageLinkProperty.minRtt /= counter;
averageLinkProperty.averageRtt /= counter;
averageLinkProperty.delayVariation /= counter;
averageLinkProperty.packetLoss /= counter;
}
return averageLinkProperty;
}
/**
*
* @return loaded PingEr TSV-Files (map: File -> DataType)
*/
public HashMap<String, String> getFiles() {
return files;
}
/**
*
* @return reference to the PingER Adjacency List (used by the GUI only)
*/
public HashMap<String, HashMap<String, LinkProperty>> getData() {
return data;
}
/**
* This class encapsulates the PingER summary Data for one aggregated
* Country/Region to Country/Region link.
*
* The calculation of the log-normal jitter distribution is implemented
* within this class.
*
*/
public class LinkProperty {
protected double minRtt = 0;
protected double averageRtt = 0;
protected double delayVariation = 0; // IQR
protected double packetLoss = 0;
private LognormalDist jitterDistribution;
/**
*
* @return log_normal jitter distribution calculated with the iqr and
* expectet jitter
*/
public LognormalDist getJitterDistribution() {
if (jitterDistribution == null) {
JitterParameter optimized = getJitterParameterDownhillSimplex(
averageRtt - minRtt, delayVariation);
jitterDistribution = new LognormalDist(optimized.m, optimized.s);
log
.debug("Set lognormal Jitter-Distribution with Average Jitter of "
+ optimized.getAverageJitter()
+ " ("
+ (averageRtt - minRtt)
+ ") and an IQR of "
+ optimized.getIQR()
+ " ("
+ delayVariation
+ ")");
}
return jitterDistribution;
}
/**
* Implemenation of a downhill simplex algortihm that finds the
* log-normal parameters mu and sigma that minimized the error between
* measured expectation and iqr and the resulting expectation and iqr.
*
* @param expectation
* value
* @param iqr
* variation
* @return JitterParameter object with the log-normal parameter mu and
* sigma
*/
private JitterParameter getJitterParameterDownhillSimplex(
double expectation, double iqr) {
ArrayList<JitterParameter> solutions = new ArrayList<JitterParameter>();
solutions.add(new JitterParameter(0.1, 0.1, expectation, iqr));
solutions.add(new JitterParameter(0.1, 5.0, expectation, iqr));
solutions.add(new JitterParameter(5.0, 0.1, expectation, iqr));
Collections.sort(solutions);
// 100 interations are enough for good results
for (int c = 0; c < 100; c++) {
JitterParameter newSolution = getNewParameter1(solutions,
expectation, iqr);
if (newSolution != null
&& newSolution.getError() < solutions.get(0).getError()) {
JitterParameter newSolution2 = getNewParameter2(solutions,
expectation, iqr);
if (newSolution2 != null
&& newSolution2.getError() < newSolution.getError()) {
solutions.remove(2);
solutions.add(newSolution2);
} else {
solutions.remove(2);
solutions.add(newSolution);
}
} else if (newSolution != null
&& newSolution.getError() < solutions.get(2).getError()) {
solutions.remove(2);
solutions.add(newSolution);
} else {
solutions.get(1).m = solutions.get(1).m + 0.5
* (solutions.get(0).m - solutions.get(1).m);
solutions.get(2).m = solutions.get(2).m + 0.5
* (solutions.get(0).m - solutions.get(2).m);
solutions.get(1).s = solutions.get(1).s + 0.5
* (solutions.get(0).s - solutions.get(1).s);
solutions.get(2).s = solutions.get(2).s + 0.5
* (solutions.get(0).s - solutions.get(2).s);
}
Collections.sort(solutions);
}
return solutions.get(0);
}
/**
* movement of factor 2 to center of solutions
*
* @param solutions
* @param expectation
* @param iqr
* @return moved solution
*/
private JitterParameter getNewParameter1(
ArrayList<JitterParameter> solutions, double expectation,
double iqr) {
double middleM = (solutions.get(0).m + solutions.get(1).m + solutions
.get(2).m) / 3.0;
double middleS = (solutions.get(0).s + solutions.get(1).s + solutions
.get(2).s) / 3.0;
double newM = middleM + (solutions.get(0).m - solutions.get(2).m);
double newS = middleS + (solutions.get(0).s - solutions.get(2).s);
if (newS > 0)
return new JitterParameter(newM, newS, expectation, iqr);
else
return null;
}
/**
* movement of factor 3 to center of solutions
*
* @param solutions
* @param expectation
* @param iqr
* @return moved solution
*/
private JitterParameter getNewParameter2(
ArrayList<JitterParameter> solutions, double expectation,
double iqr) {
double middleM = (solutions.get(0).m + solutions.get(1).m + solutions
.get(2).m) / 3.0;
double middleS = (solutions.get(0).s + solutions.get(1).s + solutions
.get(2).s) / 3.0;
double newM = middleM + 2
* (solutions.get(0).m - solutions.get(2).m);
double newS = middleS + 2
* (solutions.get(0).s - solutions.get(2).s);
if (newS > 0)
return new JitterParameter(newM, newS, expectation, iqr);
else
return null;
}
@Override
public String toString() {
String min = (minRtt == -1) ? "-" : String.valueOf(minRtt);
String average = (averageRtt == -1) ? "-" : String
.valueOf(averageRtt);
String delayVar = (delayVariation == -1) ? "-" : String
.valueOf(delayVariation);
String loss = (packetLoss == -1) ? "-" : String.valueOf(packetLoss);
return min + " / " + average + " / " + delayVar + " / " + loss;
}
/**
* Container the log-normal distribution parameters. Used in the
* Downhill Simplex method.
*
*/
private class JitterParameter implements Comparable<JitterParameter> {
double m;
double s;
double ew;
double iqr;
public JitterParameter(double m, double s, double ew, double iqr) {
this.m = m;
this.s = s;
this.ew = ew;
this.iqr = iqr;
}
/**
* error will be minimized within the downhill simplx algorithm
*
* @return error (variation between measured expectation and iqr and
* the resulting log-normal expectation and iqr.
*/
public double getError() {
LognormalDist jitterDistribution = new LognormalDist(m, s);
double error1 = Math.pow((iqr - (jitterDistribution
.inverseF(0.75) - jitterDistribution.inverseF(0.25)))
/ iqr, 2);
double error2 = Math.pow((ew - Math.exp(m
+ (Math.pow(s, 2) / 2.0)))
/ ew, 2);
return error1 + error2;
}
public int compareTo(JitterParameter p) {
double error1 = this.getError();
double error2 = p.getError();
if (error1 < error2)
return -1;
else if (error1 > error2)
return 1;
else
return 0;
}
/**
*
* @return expectation value of the log-normal distribution
*/
public double getAverageJitter() {
return Math.exp(m + (Math.pow(s, 2) / 2.0));
}
/**
*
* @return iqr of the log-normal distribution
*/
public double getIQR() {
LognormalDist jitterDistribution = new LognormalDist(m, s);
return jitterDistribution.inverseF(0.75)
- jitterDistribution.inverseF(0.25);
}
@Override
public String toString() {
LognormalDist jitterDistribution = new LognormalDist(m, s);
double iqr1 = jitterDistribution.inverseF(0.75)
- jitterDistribution.inverseF(0.25);
double ew1 = Math.exp(m + (Math.pow(s, 2) / 2.0));
return "m: " + m + " s: " + s + " Error: " + getError()
+ " iqr: " + iqr1 + " ew: " + ew1;
}
}
}
/**
*
* @author leo@relevantmusic.de
* @param db
*/
public void insertIntoRelationalDB(NetMeasurementDB db) {
Set<String> fromKeys = data.keySet();
int succRelationsCounter = 0;
int failRelationsCounter = 0;
for (String from : fromKeys) {
Country ctFrom = db.getStringAddrObjFromStr(Country.class, from);
PingErRegion regFrom = db.getStringAddrObjFromStr(PingErRegion.class, from);
Set<String> toKeys = data.get(from).keySet();
for (String to : toKeys) {
double minRtt = getMinimumRtt(from, to);
double avgRtt = getAverageRtt(from, to);
double delVar = getRttVariation(from, to);
double pLoss = getPacktLossRate(from, to);
//System.out.println("Handling PingER entry " + from + ", " + to);
Country ctTo = db.getStringAddrObjFromStr(Country.class, to);
PingErRegion regTo = db.getStringAddrObjFromStr(PingErRegion.class, to);
boolean anyRelationAdded = false;
if (ctFrom != null && ctTo != null) {
SummaryRelation rel = db.getSummaryRelFrom(ctFrom, ctTo);
if (rel != null) log.debug("Conflict. Found " + rel + " at country " + ctFrom + " and country " + ctTo + " where a new entry should be placed.");
db.new CountryCountrySummaryRelation(ctFrom, ctTo, minRtt, avgRtt, delVar, pLoss);
anyRelationAdded = true;
}
if (ctFrom != null && regTo != null) {
SummaryRelation rel = db.getSummaryRelFrom(ctFrom, regTo);
if (rel != null) log.debug("Conflict. Found " + rel + " at country " + ctFrom + " and region " + regTo + " where a new entry should be placed.");
db.new CountryRegionSummaryRelation(ctFrom, regTo, minRtt, avgRtt, delVar, pLoss);
anyRelationAdded = true;
}
if (regFrom != null && ctTo != null) {
SummaryRelation rel = db.getSummaryRelFrom(regFrom, ctTo);
if (rel != null) log.debug("Conflict. Found " + rel + " at region " + regFrom + " and country " + ctTo + " where a new entry should be placed.");
db.new RegionCountrySummaryRelation(regFrom, ctTo, minRtt, avgRtt, delVar, pLoss);
anyRelationAdded = true;
}
if (regFrom != null && regTo != null) {
SummaryRelation rel = db.getSummaryRelFrom(regFrom, regTo);
if (rel != null) log.debug("Conflict. Found " + rel + " at region " + regFrom + " and region " + regTo + " where a new entry should be placed.");
db.new RegionRegionSummaryRelation(regFrom, regTo, minRtt, avgRtt, delVar, pLoss);
anyRelationAdded = true;
}
//assert anyRelationAdded : getWarning(relationsCounter, from, ctFrom, regFrom, to, ctTo, regTo);
if (!anyRelationAdded) {
log.warn(getWarning(succRelationsCounter, from, ctFrom, regFrom, to, ctTo, regTo));
failRelationsCounter ++;
} else {
succRelationsCounter++;
}
}
}
createGlobalSumRel(db);
log.info("Successfully put " + succRelationsCounter + " entries into the database. Failed relations: " + failRelationsCounter);
}
private void createGlobalSumRel(NetMeasurementDB db) {
List<RegionRegionSummaryRelation> objs = db.getAllObjects(RegionRegionSummaryRelation.class);
int sz = objs.size();
if (objs.size() == 0) throw new AssertionError("Can not create a global summary relation when no region-region summary relations are available.");
double avgRttAcc = 0;
double minRttAcc = 0;
double dVarAcc = 0;
double pLossAcc = 0;
for (SummaryRelation sumRel : objs) {
avgRttAcc += sumRel.getAvgRtt();
minRttAcc += sumRel.getMinRtt();
dVarAcc += sumRel.getdVar();
pLossAcc += sumRel.getpLoss();
}
GlobalSummaryRelation sumRel = db.new GlobalSummaryRelation(minRttAcc/sz, avgRttAcc/sz, dVarAcc/sz, pLossAcc/sz);
log.info("Created a global summary relation with minRtt=" + sumRel.getMinRtt() + ", avgRtt=" + sumRel.getAvgRtt() + ", dVar=" + sumRel.getdVar() + ", pLoss=" + sumRel.getpLoss());
}
private String getWarning(int relationsCounter, String from, Country ctFrom,
PingErRegion regFrom, String to, Country ctTo, PingErRegion regTo) {
return "No PingER summary relation could be found that matches the countries or regions in the database: " +
"Entry strings were: from=" + from + " to=" + to + ". Found ctFrom=" + (ctFrom != null) + " ctTo=" + (ctTo != null) + " regFrom=" + (regFrom != null) + " regTo=" + (regTo != null) +
"Successfully" +" added " + relationsCounter + " relations until now.";
}
}
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network.gnp.topology;
import java.util.List;
import de.tud.kom.p2psim.impl.network.gnp.topology.Host.CumulateRTTStrategy;
import de.tud.kom.p2psim.impl.util.toolkits.CollectionHelpers;
public class RTTCumulationStrategies {
public static class Minimum implements CumulateRTTStrategy {
@Override
public Double cumulate(List<Double> rtts) {
if (rtts.isEmpty()) return Double.NaN;
double minimum = Double.MAX_VALUE;
for (double rtt : rtts) {
if (rtt < minimum) minimum = rtt;
}
return minimum;
}
}
public static class Average implements CumulateRTTStrategy {
@Override
public Double cumulate(List<Double> rtts) {
if (rtts.isEmpty()) return Double.NaN;
double acc = 0d;
for (double rtt : rtts) acc += rtt;
return acc/rtts.size();
}
}
public static class Median implements CumulateRTTStrategy {
@Override
public Double cumulate(List<Double> rtts) {
return CollectionHelpers.getQuantile(rtts, 0.5d);
}
}
}
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network.modular;
import java.util.HashMap;
import java.util.Map;
import de.tud.kom.p2psim.api.analyzer.MessageAnalyzer.Reason;
import de.tud.kom.p2psim.api.analyzer.NetlayerAnalyzer;
import de.tud.kom.p2psim.api.network.NetLayer;
import de.tud.kom.p2psim.impl.network.AbstractSubnet;
import de.tud.kom.p2psim.impl.network.modular.livemon.NetLayerLiveMonitoring;
import de.tud.kom.p2psim.impl.transport.AbstractTransMessage;
import de.tud.kom.p2psim.impl.util.BackToXMLWritable;
import de.tudarmstadt.maki.simonstrator.api.Monitor;
import de.tudarmstadt.maki.simonstrator.api.Time;
import de.tudarmstadt.maki.simonstrator.api.component.core.MonitorComponent.AnalyzerNotAvailableException;
import de.tudarmstadt.maki.simonstrator.api.component.network.NetID;
/**
* Base class for Subnets within the modular Net-Layer. This allows for
* different subnet implementations if a subnet should not make the "big cloud"
* assumption but instead rely on some kind of topology and routing.
*
* @author Leo Nobach, modified by Bjoern Richerzhagen (v 1.1)
* @version 1.1, 04/13/2011
*/
public abstract class AbstractModularSubnet extends AbstractSubnet implements
BackToXMLWritable {
//private static Logger log = SimLogger.getLogger(AbstractModularSubnet.class);
/**
* Used strategies
*/
private IStrategies strategies;
/**
* Whether to deliver messages in the right order or not
*/
private boolean inOrderDelivery = false;
/**
* List of all NetLayers
*/
private Map<NetID, ModularNetLayer> allNetLayers = new HashMap<NetID, ModularNetLayer>();
/**
* Needed for creation of a subnet from config.xml, strategies should be
* provided via setStrategies
*/
public AbstractModularSubnet() {
// nothing to do here
}
/**
* Create a new Subnet with the provided strategies
*
* @param strategies
*/
public AbstractModularSubnet(IStrategies strategies) {
this();
setStrategies(strategies);
}
/**
* Convenience function for a check of PLoss-Strategy and assignment of
* Log-Messages and Monitor-Events
*
* @return
*/
protected boolean shallBeDropped(ModularNetMessage msg,
ModularNetLayer nlSender, ModularNetLayer nlReceiver) {
boolean shallBeDropped = getStrategies().getPLossStrategy().shallDrop(
msg, nlSender, nlReceiver, getDB());
if (shallBeDropped) {
if (msg.getPayload() != null
&& msg.getPayload() instanceof AbstractTransMessage) {
int assignedMsgId = determineTransMsgNumber(msg);
((AbstractTransMessage) msg.getPayload())
.setCommId(assignedMsgId);
}
//log.debug("Dropping message " + msg
// + ", because of the packet loss strategy that is used.");
NetLayerLiveMonitoring.getSubnetMsgDrop().droppedMessage();
try {
Monitor.get(NetlayerAnalyzer.class).netMsgEvent(msg,
nlSender.getHost(), Reason.DROP);
} catch (AnalyzerNotAvailableException e) {
// nothing to do
}
return true;
} else {
NetLayerLiveMonitoring.getSubnetMsgDrop().noDropMessage();
return false;
}
}
/**
* Calculate the Receive-Time and delay+jitter
*
* @param msg
* @param nlSender
* @param nlReceiver
* @return
*/
protected long getRcvTime(ModularNetMessage msg, ModularNetLayer nlSender,
ModularNetLayer nlReceiver) {
long delay = getStrategies().getLatencyStrategy()
.getMessagePropagationDelay(msg, nlSender, nlReceiver, getDB());
long jitter = getStrategies().getJitterStrategy().getJitter(delay, msg,
nlSender, nlReceiver, getDB());
return getRcvTime(msg, delay, jitter, nlReceiver);
}
/**
* Provide Delay and Jitter and get the receive-Time
*
* @param msg
* @param delay
* @param jitter
* @param nlReceiver
* @return
*/
protected long getRcvTime(ModularNetMessage msg, long delay, long jitter,
ModularNetLayer nlReceiver) {
long rcvTime;
if (getUseInOrderDelivery()) {
rcvTime = Math.max(nlReceiver.getLastSchRcvTime() + 1,
Time.getCurrentTime() + delay + jitter);
nlReceiver.setLastSchRcvTime(rcvTime);
} else {
rcvTime = Time.getCurrentTime() + delay + jitter;
}
//log.debug("Delaying message " + msg + ": delay=" + delay
// + ", jitter=" + jitter);
return rcvTime;
}
/**
* On registration a netLayer automatically is online without calling
* "goOnline" (possibly a bug). Fixed: added call to goOnline in
* ModularNetLayer
*/
@Override
public void registerNetLayer(NetLayer net) {
allNetLayers.put(net.getNetID(), (ModularNetLayer) net);
}
/**
* Load a set of strategies for this subnet
*
* @param strategies
*/
public void setStrategies(IStrategies strategies) {
this.strategies = strategies;
}
/**
* Called if a NetLayer goes online.
*
* @param net
*/
protected abstract void netLayerWentOnline(NetLayer net);
/**
* Called if a NetLayer goes offline.
*
* @param net
*/
protected abstract void netLayerWentOffline(NetLayer net);
/**
* get the NetLayer of a given NetID
*
* @param id
* @return The NetLayer or null, if there is no Host with the given ID
*/
public ModularNetLayer getNetLayer(NetID id) {
ModularNetLayer nl = allNetLayers.get(id);
return nl;
}
/**
* Get used Strategies
*
* @return
*/
public IStrategies getStrategies() {
return strategies;
}
/**
* Deliver messages in Order, if true
*
* @param useInOrderDelivery
*/
public void setUseInOrderDelivery(boolean useInOrderDelivery) {
this.inOrderDelivery = useInOrderDelivery;
}
/**
* Are messages delivered in order?
*
* @return
*/
public boolean getUseInOrderDelivery() {
return this.inOrderDelivery;
}
}
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network.modular;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.log4j.Logger;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB.Host;
import de.tud.kom.p2psim.impl.util.logging.SimLogger;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
/**
* If the hosts in the XML configuration file are not grouped by region names (useRegionGroups="false"),
* this component will allow the net layer factory to get random hosts from the network measurement
* database.
*
* @author Leo Nobach
*
*/
public class DBHostListManager {
private static Logger log = SimLogger.getLogger(DBHostListManager.class);
private List<Host> hostList;
int hostPointer = 0;
public DBHostListManager(NetMeasurementDB db) {
this.hostList = getShuffledHostList(db);
}
/**
* Returns a shuffled host list from the given network measurement database.
* @param db
* @return
*/
public static List<NetMeasurementDB.Host> getShuffledHostList(NetMeasurementDB db) {
long startTime = System.nanoTime();
log.debug("Starting shuffling the host list in the measurement database.");
List<NetMeasurementDB.Host> result = new ArrayList<NetMeasurementDB.Host>(db.getAllObjects(NetMeasurementDB.Host.class));
Collections.shuffle(result, Randoms.getRandom(DBHostListManager.class));
double shufflingTime = (System.nanoTime() - startTime) * 0.000001;
log.debug("Shuffled host list in " + shufflingTime + " ms");
return result;
}
/**
* Returns the next available host from a shuffled host list.
* @return
*/
public NetMeasurementDB.Host getNextHost() {
if (hostPointer >= hostList.size()) throw new IllegalStateException("No more hosts in the host list database.");
Host result = hostList.get(hostPointer);
hostPointer++;
return result;
}
}
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network.modular;
import de.tud.kom.p2psim.impl.network.modular.st.FragmentingStrategy;
import de.tud.kom.p2psim.impl.network.modular.st.JitterStrategy;
import de.tud.kom.p2psim.impl.network.modular.st.LatencyStrategy;
import de.tud.kom.p2psim.impl.network.modular.st.PLossStrategy;
import de.tud.kom.p2psim.impl.network.modular.st.PacketSizingStrategy;
import de.tud.kom.p2psim.impl.network.modular.st.PositioningStrategy;
import de.tud.kom.p2psim.impl.network.modular.st.TrafficControlStrategy;
/**
* The set of strategies used by the current NetLayer
* @author
*
*/
public interface IStrategies {
public PacketSizingStrategy getPacketSizingStrategy();
public TrafficControlStrategy getTrafficControlStrategy();
public PLossStrategy getPLossStrategy();
public LatencyStrategy getLatencyStrategy();
public PositioningStrategy getPositioningStrategy();
public FragmentingStrategy getFragmentingStrategy();
public JitterStrategy getJitterStrategy();
}
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network.modular;
import java.util.Collection;
import org.apache.log4j.Logger;
import de.tud.kom.p2psim.api.analyzer.MessageAnalyzer.Reason;
import de.tud.kom.p2psim.api.common.Position;
import de.tud.kom.p2psim.api.common.SimHost;
import de.tud.kom.p2psim.api.network.BandwidthImpl;
import de.tud.kom.p2psim.api.network.NetMessage;
import de.tud.kom.p2psim.api.network.NetMessageListener;
import de.tud.kom.p2psim.api.network.NetMsgEvent;
import de.tud.kom.p2psim.api.network.NetProtocol;
import de.tud.kom.p2psim.api.transport.TransProtocol;
import de.tud.kom.p2psim.impl.network.AbstractNetLayer;
import de.tud.kom.p2psim.impl.network.IPv4Message;
import de.tud.kom.p2psim.impl.network.IPv4NetID;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB.City;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB.Country;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB.Region;
import de.tud.kom.p2psim.impl.network.modular.livemon.NetLayerLiveMonitoring;
import de.tud.kom.p2psim.impl.network.modular.st.FragmentingStrategy;
import de.tud.kom.p2psim.impl.network.modular.st.JitterStrategy;
import de.tud.kom.p2psim.impl.network.modular.st.LatencyStrategy;
import de.tud.kom.p2psim.impl.network.modular.st.PLossStrategy;
import de.tud.kom.p2psim.impl.network.modular.st.PacketSizingStrategy;
import de.tud.kom.p2psim.impl.network.modular.st.PositioningStrategy;
import de.tud.kom.p2psim.impl.network.modular.st.TrafficControlStrategy;
import de.tud.kom.p2psim.impl.network.modular.st.TrafficControlStrategy.IReceiveContext;
import de.tud.kom.p2psim.impl.network.modular.st.TrafficControlStrategy.ISendContext;
import de.tud.kom.p2psim.impl.transport.AbstractTransMessage;
import de.tud.kom.p2psim.impl.util.logging.SimLogger;
import de.tudarmstadt.maki.simonstrator.api.Message;
import de.tudarmstadt.maki.simonstrator.api.component.network.Bandwidth;
import de.tudarmstadt.maki.simonstrator.api.component.network.NetID;
/**
* <p>
* The Modular Network layer aims at being most flexible by allowing every
* aspect of a network layer to be modeled on its own - as a module. Like
* "building blocks", these modules can be customized in the simulator
* configuration file and put together to form the whole network layer.
* </p>
*
* <p>
* The Modular Network Layer currently supports modules of the type
* <ul>
* <li>Fragmenting
* <li>Jitter
* <li>Latency
* <li>Packet Sizing
* <li>Packet Loss
* <li>Positioning
* <li>Traffic Control
* </ul>
* </p>
*
* <p>
* For information how to configure a modular network layer, please consult
* ModularNetLayerFactory.
* </p>
* <p>
* To understand particular module types and to write a module yourself, please
* consult its abstract strategy class.
* </p>
*
* @see FragmentingStrategy
* @see JitterStrategy
* @see LatencyStrategy
* @see PacketSizingStrategy
* @see PLossStrategy
* @see PositioningStrategy
* @see TrafficControlStrategy
* @see ModularNetLayerFactory
* @author Leo Nobach
*
*/
public class ModularNetLayer extends AbstractNetLayer {
static Logger log = SimLogger.getLogger(ModularNetLayer.class);
private AbstractModularSubnet subnet;
/**
* Creates a new Modular Network layer. This should be only called from the
* ModularNetLayerFactory
*
* @param subnet
* @param maxBW
* @param hostMeta
* @param position
* @param id
* @param device
* Device-Type of this Host
*/
ModularNetLayer(SimHost host, AbstractModularSubnet subnet,
BandwidthImpl maxBW, NetMeasurementDB.Host hostMeta, Position position,
IPv4NetID id) {
super(host, id, maxBW, position, hostMeta);
this.subnet = subnet;
}
@Override
public void initialize() {
subnet.registerNetLayer(this);
goOnline();
super.initialize();
}
public String toString() {
if (hostMeta != null) {
City city = hostMeta.getCity();
Region region = city.getRegion();
Country country = region.getCountry();
return "ModNetLayer(" + getNetID() + ", " + city + ", " + region
+ ", "
+ country + ")";
}
return "ModNetLayer(" + getLocalInetAddress() + " (no location info))";
}
@Override
protected boolean isSupported(TransProtocol protocol) {
return protocol.equals(TransProtocol.UDP);
}
Object trafCtrlMetadata = null;
/**
* Convenience method for send()
*
* @param netMsg
* @param receiver
*/
private void sendNetMessage(NetMessage netMsg, NetID receiver) {
if (this.isOnline()) {
NetLayerLiveMonitoring.getOfflineMsgDrop().noDropMessage();
subnet.getStrategies()
.getTrafficControlStrategy()
.onSendRequest(this.new SendContextImpl(), netMsg, receiver);
}
}
/**
* Convenience method for send()
*
* @param msg
* @param receiver
*/
private void dropOfflineNetMessage(Message msg, NetID receiver) {
NetMessage netMsg = new IPv4Message(msg, receiver,
this.getLocalInetAddress());
//log.debug("Dropping message " + msg + ", because sender " + this
// + " is offline.");
NetLayerLiveMonitoring.getOfflineMsgDrop().droppedMessage();
if (hasAnalyzer) {
netAnalyzerProxy.netMsgEvent(netMsg, getHost(), Reason.DROP);
}
}
@Override
public void send(Message msg, NetID receiver, NetProtocol protocol) {
if (msg instanceof AbstractTransMessage) {
if (protocol != NetProtocol.IPv4)
throw new AssertionError(
"Currently, the simulator only supports IPv4. "
+ msg.getClass().getSimpleName());
if (this.isOnline()) {
TransProtocol usedTransProtocol = ((AbstractTransMessage) msg)
.getProtocol();
if (this.isSupported(usedTransProtocol)) {
NetMessage netMsg = new ModularNetMessage(msg, receiver,
getNetID(), subnet.getStrategies(),
NetProtocol.IPv4);
// IPv6 currently not supported
sendNetMessage(netMsg, receiver);
if (((AbstractTransMessage) msg).getCommId() == -1) {
int assignedMsgId = subnet.determineTransMsgNumber(msg);
((AbstractTransMessage) msg).setCommId(assignedMsgId);
}
} else
throw new IllegalArgumentException("Transport protocol "
+ usedTransProtocol
+ " not supported by this NetLayer implementation.");
} else {
int assignedMsgId = subnet.determineTransMsgNumber(msg);
((AbstractTransMessage) msg).setCommId(assignedMsgId);
dropOfflineNetMessage(msg, receiver);
}
} else {
throw new AssertionError(
"Can only send messages of class AbstractTransMessage or "
+ "subclasses of it through the network layer, but the message class was "
+ msg.getClass().getSimpleName());
}
}
class SendContextImpl implements ISendContext {
@Override
public Object getTrafCtrlMetadata() {
return trafCtrlMetadata;
}
@Override
public void setTrafCtrlMetadata(Object trafCtrlMetadata) {
ModularNetLayer.this.trafCtrlMetadata = trafCtrlMetadata;
}
@Override
public void sendSubnet(NetMessage netMsg) {
NetLayerLiveMonitoring.getTrafCtrlMsgDrop().noDropMessage();
if (hasAnalyzer) {
netAnalyzerProxy.netMsgEvent(netMsg, getHost(), Reason.SEND);
}
ModularNetLayer.this.getSubnet().send(netMsg);
}
@Override
public void dropMessage(NetMessage netMsg) {
//log.debug("Dropping message " + netMsg + ", because the sender's ("
// + ModularNetLayer.this
// + ") traffic control mechanism has decided it.");
NetLayerLiveMonitoring.droppedMessageTrafCtrl(netMsg);
if (hasAnalyzer) {
netAnalyzerProxy.netMsgEvent(netMsg, getHost(), Reason.DROP);
}
}
@Override
public Bandwidth getMaxBW() {
return ModularNetLayer.this.getMaxBandwidth();
}
}
// TODO
@Override
@Deprecated
public void receive(NetMessage message) {
throw new IllegalStateException(
"The method receive(NetMessage) is deprecated in the Modular Network Layer.");
}
/**
* Receiving a Message without additional information on the Subnet-Context.
* This is only used by the SimpleModularSubnet, as it has no Topology or
* Channels.
*
* @param message
* @param netLayerOfSender
*/
public void receive(ModularNetMessage message,
ModularNetLayer netLayerOfSender) {
ReceiveContextImpl ctx = new ReceiveContextImpl(
netLayerOfSender.getMaxBandwidth(), getMaxBandwidth());
subnet.getStrategies().getTrafficControlStrategy()
.onReceive(ctx, message);
}
class ReceiveContextImpl implements IReceiveContext {
private Bandwidth senderBW;
private Bandwidth receiverBW;
public ReceiveContextImpl(Bandwidth senderBW, Bandwidth receiverBW) {
this.senderBW = senderBW;
this.receiverBW = receiverBW;
}
@Override
public Object getTrafCtrlMetadata() {
return trafCtrlMetadata;
}
@Override
public void setTrafCtrlMetadata(Object trafCtrlMetadata) {
ModularNetLayer.this.trafCtrlMetadata = trafCtrlMetadata;
}
@Override
public void arrive(NetMessage message) {
NetLayerLiveMonitoring.getTrafCtrlMsgDrop().noDropMessage();
if (ModularNetLayer.this.isOnline()) {
NetLayerLiveMonitoring.getOfflineMsgDrop().noDropMessage();
NetLayerLiveMonitoring.getRoutingMsgDrop().noDropMessage();
NetID myID = getNetID();
if (hasAnalyzer) {
netAnalyzerProxy.netMsgEvent(message, getHost(),
Reason.RECEIVE);
}
NetMsgEvent event = new NetMsgEvent(message,
ModularNetLayer.this);
Collection<NetMessageListener> msgListeners = getNetMsgListeners();
if (msgListeners == null || msgListeners.isEmpty()) {
if (hasAnalyzer) {
netAnalyzerProxy.netMsgEvent(message, getHost(),
Reason.RECEIVE);
}
log.warn(this + "Cannot deliver message "
+ message.getPayload() + " at netID=" + myID
+ " as no message msgListeners registered");
} else {
for (NetMessageListener listener : msgListeners) {
listener.messageArrived(event);
}
}
} else {
//log.debug("Dropping message " + message + ", because receiver "
// + this + " is offline.");
NetLayerLiveMonitoring.getOfflineMsgDrop().droppedMessage();
if (hasAnalyzer) {
netAnalyzerProxy.netMsgEvent(message, getHost(),
Reason.DROP);
}
}
}
@Override
public void dropMessage(NetMessage netMsg) {
NetLayerLiveMonitoring.getTrafCtrlMsgDrop().droppedMessage();
//log.debug("Dropping message " + netMsg
// + ", because the receiver's (" + ModularNetLayer.this
// + ") traffic control mechanism has decided it.");
if (hasAnalyzer) {
netAnalyzerProxy.netMsgEvent(netMsg, getHost(), Reason.DROP);
}
}
@Override
public Bandwidth getMaxBW() {
return receiverBW;
}
@Override
public Bandwidth getBandwidthOfSender() {
return senderBW;
}
}
/**
* Get the subnet this NetLayer operates on
*
* @return
*/
public AbstractModularSubnet getSubnet() {
return subnet;
}
private long lastSchRcvTime = -1;
protected long getLastSchRcvTime() {
return lastSchRcvTime;
}
public void setLastSchRcvTime(long lastSchRcvTime) {
this.lastSchRcvTime = lastSchRcvTime;
}
@Override
public void goOffline() {
super.goOffline();
getSubnet().netLayerWentOffline(this);
}
@Override
public void goOnline() {
super.goOnline();
getSubnet().netLayerWentOnline(this);
}
}
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network.modular;
import org.apache.log4j.Logger;
import de.tud.kom.p2psim.api.common.SimHost;
import de.tud.kom.p2psim.impl.network.AbstractNetLayerFactory;
import de.tud.kom.p2psim.impl.network.AbstractSubnet;
import de.tud.kom.p2psim.impl.network.IPv4NetID;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB;
import de.tud.kom.p2psim.impl.network.modular.livemon.NetLayerLiveMonitoring;
import de.tud.kom.p2psim.impl.network.modular.st.FragmentingStrategy;
import de.tud.kom.p2psim.impl.network.modular.st.JitterStrategy;
import de.tud.kom.p2psim.impl.network.modular.st.LatencyStrategy;
import de.tud.kom.p2psim.impl.network.modular.st.PLossStrategy;
import de.tud.kom.p2psim.impl.network.modular.st.PacketSizingStrategy;
import de.tud.kom.p2psim.impl.network.modular.st.PositioningStrategy;
import de.tud.kom.p2psim.impl.network.modular.st.TrafficControlStrategy;
import de.tud.kom.p2psim.impl.network.modular.subnet.SimpleModularSubnet;
import de.tud.kom.p2psim.impl.util.BackToXMLWritable;
import de.tud.kom.p2psim.impl.util.logging.SimLogger;
import de.tudarmstadt.maki.simonstrator.api.Event;
import de.tudarmstadt.maki.simonstrator.api.EventHandler;
import de.tudarmstadt.maki.simonstrator.api.Host;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
/**
* Component factory for the Modular Network Layer. In this component, strategy
* modules are selected that are used by the modular network layer class.
*
* You can configure different strategies in the PeerfactSim.KOM XML
* configuration file. An example:
*
* <pre>
* &lt;NetLayer class="de.tud.kom.p2psim.impl.network.modular.ModularNetLayerFactory" downBandwidth="5000.0" upBandwidth="5000.0" useRegionGroups="false" useInOrderDelivery="true" preset="PingER"&gt;
* &lt;BandwidthDetermination class="de.tud.kom.p2psim.impl.network.bandwidthDetermination.OECDReportBandwidthDetermination"/&gt;
* &lt;MeasurementDB class="de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB" file="data/mod_measured_data.xml"/&gt;
* &lt;Subnet class="de.tud.kom.p2psim.impl.network.modular.subnet.SimpleModularSubnet"&gt;
* &lt;PacketSizing class="de.tud.kom.p2psim.impl.network.modular.st.packetSizing.IPv4Header"/&gt;
* &lt;Fragmenting class="de.tud.kom.p2psim.impl.network.modular.st.fragmenting.IPv4Fragmenting"/&gt;
* &lt;TrafficControl class="de.tud.kom.p2psim.impl.network.modular.st.trafCtrl.BoundedTrafficQueue" maxTimeSend="3s" maxTimeReceive="3s"/&gt;
* &lt;PLoss class="de.tud.kom.p2psim.impl.network.modular.st.ploss.PingERPacketLoss"/&gt;
* &lt;Latency class="de.tud.kom.p2psim.impl.network.modular.st.latency.PingErLatency"/&gt;
* &lt;Jitter class="de.tud.kom.p2psim.impl.network.modular.st.jitter.PingErJitter"/&gt;
* &lt;Positioning class="de.tud.kom.p2psim.impl.network.modular.st.positioning.GeographicalPositioning"/&gt;
* &lt;/NetLayer&gt;
* </pre>
*
* @see de.tud.kom.p2psim.impl.network.modular.ModularNetLayer
* @author Leo Nobach
*
*/
public class ModularNetLayerFactory extends AbstractNetLayerFactory implements
BackToXMLWritable {
private static Logger log = SimLogger
.getLogger(ModularNetLayerFactory.class);
private StrategiesImpl strategies = new StrategiesImpl();
private AbstractModularSubnet subnet = new SimpleModularSubnet(strategies);
public boolean useRegionGroups = false;
/**
* Only used when useRegionGroups is set to true
*/
public DBHostListManager dbHostList = null;
private String presetName;
public ModularNetLayerFactory() {
NetLayerLiveMonitoring.register();
Presets.getDefaultPreset().set(this);
Event.scheduleImmediately(new EventHandler() {
@Override
public void eventOccurred(Object se, int type) {
onSimulationStart();
}
}, null, 0);
}
@Override
public ModularNetLayer createComponent(Host planeHost) {
SimHost host = (SimHost) planeHost;
String groupStr = host.getProperties().getGroupID();
NetMeasurementDB.Host hostMeta;
if (db != null) {
subnet.setDB(db);
if (useRegionGroups) {
// In case of a DB presence, look up the host's specific
// metadata there
NetMeasurementDB.Group g = db.getStringAddrObjFromStr(
NetMeasurementDB.Group.class, groupStr);
if (g == null)
throw new IllegalArgumentException(
"There is no group named '" + groupStr + "'");
hostMeta = g.tGetNextMember();
} else {
// The hosts are not grouped by their region name, we will
// return random hosts in the world for each group.
if (dbHostList == null)
dbHostList = new DBHostListManager(db);
hostMeta = dbHostList.getNextHost();
}
} else {
hostMeta = null;
}
IPv4NetID id;
if (hostMeta != null) {
id = new IPv4NetID(IPv4NetID.intToLong(hostMeta.getId()));
} else {
id = new IPv4NetID(IPv4NetID.intToLong(Randoms.getRandom(
ModularNetLayerFactory.class)
.nextInt()));
}
return new ModularNetLayer(host, subnet, getBandwidth(id), hostMeta,
getStrategies().getPositioningStrategy().getPosition(host, db,
hostMeta), id);
}
/**
* Executed at the start of the simulation via a simulation event at time 0.
*/
void onSimulationStart() {
if (db != null) {
log.debug(db.getStats());
dbHostList = null;
db.release();
System.gc();
}
log.info("Fully written out, the modular net layer configuration would look like this:\n"
+ getWrittenBackNetLayer());
}
/**
* Returns the network layer configuration written back to the XML
* configuration format.
*
* @return
*/
public String getWrittenBackNetLayer() {
return BackToXMLWritable.BackWriter.getWrittenBackDoc("NetLayer", this);
}
public void setSubnet(AbstractModularSubnet subnet) {
this.subnet = subnet;
this.subnet.setStrategies(getStrategies());
}
public IStrategies getStrategies() {
return strategies;
}
public class StrategiesImpl implements IStrategies {
// Defaults
PacketSizingStrategy packetSizing = null;
TrafficControlStrategy trafCtrl = null;
PLossStrategy pLoss = null;
LatencyStrategy latency = null;
PositioningStrategy positioning = null;
FragmentingStrategy frag = null;
JitterStrategy jit = null;
@Override
public PacketSizingStrategy getPacketSizingStrategy() {
return packetSizing;
}
@Override
public TrafficControlStrategy getTrafficControlStrategy() {
return trafCtrl;
}
@Override
public PLossStrategy getPLossStrategy() {
return pLoss;
}
@Override
public LatencyStrategy getLatencyStrategy() {
return latency;
}
@Override
public PositioningStrategy getPositioningStrategy() {
return positioning;
}
@Override
public FragmentingStrategy getFragmentingStrategy() {
return frag;
}
@Override
public JitterStrategy getJitterStrategy() {
return jit;
}
}
public void setUseRegionGroups(boolean useRegionGroups) {
this.useRegionGroups = useRegionGroups;
}
public void setUseInOrderDelivery(boolean useInOrderDelivery) {
subnet.setUseInOrderDelivery(useInOrderDelivery);
}
public void setPreset(String presetName) {
Presets.getPreset(presetName).set(this);
this.presetName = presetName;
}
public void setPacketSizing(PacketSizingStrategy packetSizing) {
strategies.packetSizing = packetSizing;
}
public void setTrafficControl(TrafficControlStrategy trafCtrl) {
strategies.trafCtrl = trafCtrl;
}
public void setPLoss(PLossStrategy pLoss) {
strategies.pLoss = pLoss;
}
public void setLatency(LatencyStrategy latency) {
strategies.latency = latency;
}
public void setPositioning(PositioningStrategy positioning) {
strategies.positioning = positioning;
}
public void setFragmenting(FragmentingStrategy frag) {
strategies.frag = frag;
}
public void setJitter(JitterStrategy jit) {
strategies.jit = jit;
}
@Override
public void writeBackToXML(BackWriter bw) {
super.writeBackToXML(bw);
bw.writeSimpleType("useRegionGroups", useRegionGroups);
bw.writeSimpleType("useInOrderDelivery", subnet.getUseInOrderDelivery());
bw.writeSimpleType("preset", presetName);
bw.writeComplexType("Subnet", subnet);
bw.writeComplexType("PacketSizing", strategies.packetSizing);
bw.writeComplexType("Fragmenting", strategies.frag);
bw.writeComplexType("TrafficControl", strategies.trafCtrl);
bw.writeComplexType("PLoss", strategies.pLoss);
bw.writeComplexType("Latency", strategies.latency);
bw.writeComplexType("Jitter", strategies.jit);
bw.writeComplexType("Positioning", strategies.positioning);
}
public AbstractSubnet getSubnet() {
return subnet;
}
}
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network.modular;
import de.tud.kom.p2psim.api.network.NetProtocol;
import de.tud.kom.p2psim.impl.network.AbstractNetMessage;
import de.tudarmstadt.maki.simonstrator.api.Message;
import de.tudarmstadt.maki.simonstrator.api.component.network.NetID;
/**
* Implementation of a NetMessage for the Modular Network layer
*
* @author Leo Nobach
*
*/
public class ModularNetMessage extends AbstractNetMessage {
private long size;
public ModularNetMessage(Message payload, NetID receiver, NetID sender,
IStrategies strategies, NetProtocol netProtocol) {
super(payload, receiver, sender, netProtocol);
this.noOfFragments = strategies.getFragmentingStrategy()
.getNoOfFragments(payload, receiver, sender, netProtocol);
this.size = strategies.getPacketSizingStrategy().getPacketSize(payload,
receiver, sender, netProtocol, noOfFragments);
assert noOfFragments >= 1 : "The number of fragments per message may never be less than 1. ";
}
/**
* Returns the sum of all fragments of this net message.
*/
public long getSize() {
return size;
}
@Override
public String toString() {
return "[ IP " + super.getSender() + " -> " + super.getReceiver()
+ " | size: " + getSize() + " ( " + getSize() + " ) bytes | payload: " + getPayload() + " ]";
}
}
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network.modular;
import java.util.HashMap;
import java.util.Map;
import de.tud.kom.p2psim.impl.network.modular.st.fragmenting.IPv4Fragmenting;
import de.tud.kom.p2psim.impl.network.modular.st.fragmenting.NoFragmenting;
import de.tud.kom.p2psim.impl.network.modular.st.jitter.LognormalJitter;
import de.tud.kom.p2psim.impl.network.modular.st.jitter.NoJitter;
import de.tud.kom.p2psim.impl.network.modular.st.jitter.PingErJitter;
import de.tud.kom.p2psim.impl.network.modular.st.latency.GNPLatency;
import de.tud.kom.p2psim.impl.network.modular.st.latency.GeographicalLatency;
import de.tud.kom.p2psim.impl.network.modular.st.latency.PingErLatency;
import de.tud.kom.p2psim.impl.network.modular.st.latency.StaticLatency;
import de.tud.kom.p2psim.impl.network.modular.st.packetSizing.IPv4Header;
import de.tud.kom.p2psim.impl.network.modular.st.packetSizing.NoHeader;
import de.tud.kom.p2psim.impl.network.modular.st.ploss.NoPacketLoss;
import de.tud.kom.p2psim.impl.network.modular.st.ploss.PingERPacketLoss;
import de.tud.kom.p2psim.impl.network.modular.st.ploss.StaticPacketLoss;
import de.tud.kom.p2psim.impl.network.modular.st.positioning.GNPPositioning;
import de.tud.kom.p2psim.impl.network.modular.st.positioning.GeographicalPositioning;
import de.tud.kom.p2psim.impl.network.modular.st.positioning.TorusPositioning;
import de.tud.kom.p2psim.impl.network.modular.st.trafCtrl.BoundedTrafficQueue;
import de.tud.kom.p2psim.impl.network.modular.st.trafCtrl.NoTrafficControl;
/**
* Different presets that speed up the usage of the Modular Network Layer in the
* XML configuration file. Simply add 'preset="<Preset>"' to the XML element
* of the ModularNetLayerFactory instead of defining every strategy by hand.
* Of course, preset network layer strategies can be overridden by strategies
* explicitly set.
*
* @author Leo Nobach
*
*/
public class Presets {
static Map<String, Preset> presets = new HashMap<String, Preset>();
private static Preset defaultPreset;
public static void addPreset(String name, Preset preset) {
presets.put(name.toLowerCase(), preset);
}
public static Preset getPreset(String name) {
Preset p = presets.get(name.toLowerCase());
if (p == null) throw new IllegalArgumentException("A preset with the name '" + name + "' is not registered.");
return p;
}
public static void setDefaultPreset(Preset p) {
defaultPreset = p;
}
public static Preset getDefaultPreset() {
return defaultPreset;
}
public static abstract class Preset {
public abstract void set(ModularNetLayerFactory f);
}
static {
addPreset("Easy", new Preset() {
@Override
public void set(ModularNetLayerFactory f) {
f.setFragmenting(new NoFragmenting());
f.setJitter(new NoJitter());
f.setLatency(new StaticLatency());
f.setPacketSizing(new NoHeader());
f.setPLoss(new NoPacketLoss());
f.setPositioning(new TorusPositioning());
f.setTrafficControl(new NoTrafficControl());
}
});
Preset fundamental = new Preset() {
@Override
public void set(ModularNetLayerFactory f) {
f.setFragmenting(new IPv4Fragmenting());
f.setJitter(new LognormalJitter());
f.setLatency(new StaticLatency());
f.setPacketSizing(new IPv4Header());
f.setPLoss(new StaticPacketLoss());
f.setPositioning(new TorusPositioning());
f.setTrafficControl(new BoundedTrafficQueue());
}
};
addPreset("Fundamental", fundamental);
setDefaultPreset(fundamental);
addPreset("PingEr", new Preset() {
@Override
public void set(ModularNetLayerFactory f) {
f.setFragmenting(new IPv4Fragmenting());
f.setJitter(new PingErJitter());
f.setLatency(new PingErLatency());
f.setPacketSizing(new IPv4Header());
f.setPLoss(new PingERPacketLoss());
f.setPositioning(new GeographicalPositioning());
f.setTrafficControl(new BoundedTrafficQueue());
}
});
addPreset("Geo", new Preset() {
@Override
public void set(ModularNetLayerFactory f) {
f.setFragmenting(new IPv4Fragmenting());
f.setJitter(new PingErJitter());
f.setLatency(new GeographicalLatency());
f.setPacketSizing(new IPv4Header());
f.setPLoss(new PingERPacketLoss());
f.setPositioning(new GeographicalPositioning());
f.setTrafficControl(new BoundedTrafficQueue());
}
});
addPreset("GNP", new Preset() {
@Override
public void set(ModularNetLayerFactory f) {
f.setFragmenting(new IPv4Fragmenting());
f.setJitter(new PingErJitter());
f.setLatency(new GNPLatency());
f.setPacketSizing(new IPv4Header());
f.setPLoss(new PingERPacketLoss());
f.setPositioning(new GNPPositioning());
f.setTrafficControl(new BoundedTrafficQueue());
}
});
}
}
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network.modular.common;
import java.util.List;
public class GNPToolkit {
public static double getDistance(List<Double> gnpPosA, List<Double> gnpPosB) {
int thisSz = gnpPosA.size();
int otherSz = gnpPosB.size();
if (thisSz != otherSz) throw new AssertionError("GNP Coordinates Dimension mismatch: " + gnpPosA.size() + " and " + gnpPosB.size());
double accDistSq = 0d;
for (int i = 0; i < thisSz; i++) {
double dimDiff = gnpPosA.get(i) - gnpPosB.get(i);
accDistSq += dimDiff * dimDiff;
}
return Math.sqrt(accDistSq);
}
}
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network.modular.common;
import java.awt.geom.Point2D;
import de.tud.kom.p2psim.impl.network.gnp.HaversineHelpers;
public class GeoToolkit {
public static Point2D.Double STANDARD_REF_POINT_GERMANY = new Point2D.Double(
5, 47);
// Source: http://en.wikipedia.org/wiki/Longitude
// lat / Dist per 1 Deg lat / Dist per 1 Deg long
// 0° 110.574 km 111.320 km
// 15° 110.649 km 107.551 km
// 30° 110.852 km 96.486 km
// 45° 111.132 km 78.847 km
// 60° 111.412 km 55.800 km
// 75° 111.618 km 28.902 km
// 90° 111.694 km 0.000 km
static double[] distlat = { 110574, 110649, 110852, 111132, 111412, 111618,
111694 };
static double[] distlong = { 111320, 107551, 96486, 78847, 55800, 28902, 0 };
public static void main(String[] args) {
calcCoordinate(new Point2D.Double(10, 50), 90, 100000);
calcCoordinate(new Point2D.Double(10, 50), 0, 100000);
calcCoordinate(new Point2D.Double(10, 50), -45, 1 * Math.sqrt(2));
calcCoordinate(new Point2D.Double(10.15, 50.45), 135, 1);
System.out.println(GeoToolkit.getDistance(180, 0, 180, 90));
System.out.println(GeoToolkit.getDistance(180, 90, 180, 0));
System.out.println(GeoToolkit.getDistance(13, 18, 54, 72));
System.out.println(GeoToolkit.getDistance(52, 9, 52.5, 9));
System.out.println(GeoToolkit.getDistance(120, 30, 100, 30));
}
public static Point2D.Double calcCoordinate(Point2D.Double point,
double bearing, double distance) {
double dist = distance / 6371000.0;
double brng = Math.toRadians(bearing);
double lat1 = Math.toRadians(point.y);
double lon1 = Math.toRadians(point.x);
double lat2 = Math.asin(Math.sin(lat1) * Math.cos(dist)
+ Math.cos(lat1) * Math.sin(dist) * Math.cos(brng));
double a = Math.atan2(Math.sin(brng) * Math.sin(dist) * Math.cos(lat1),
Math.cos(dist) - Math.sin(lat1) * Math.sin(lat2));
double lon2 = lon1 + a;
lon2 = (lon2 + 3 * Math.PI) % (2 * Math.PI) - Math.PI;
return new Point2D.Double(Math.toDegrees(lon2), Math.toDegrees(lat2));
}
/**
* Returns the distance between two points in meters.
*
* @param latitudeA
* @param longitudeA
* @param latitudeB
* @param longitudeB
* @return the distance between two points in meters.
*/
public static double getDistance(double latitudeA, double longitudeA,
double latitudeB, double longitudeB) {
double lat1 = Math.toRadians(latitudeA);
double lat2 = Math.toRadians(latitudeB);
double dlat = lat2 - lat1;
double long1 = Math.toRadians(longitudeA);
double long2 = Math.toRadians(longitudeB);
double dlong = long1 - long2;
double a = Math.pow((Math.sin(dlat / 2)), 2) + Math.cos(lat1)
* Math.cos(lat2) * Math.pow((Math.sin(dlong / 2)), 2);
// angle in radians formed by start point, earth's center, & end point
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
// radius of earth at midpoint of route
double r = HaversineHelpers.globeRadiusOfCurvature((lat1 + lat2) / 2);
return r * c;
}
/**
* Transforms a given longitude latitude coordinate to a point in the
* Cartesian space
*
* @param referencePoint
* the reference point in longitude latitude coordinates
* @param longLat
* the point to be transformed in longitude latitude coordinates
* @return the XY coordinates in meters form the reference point
*/
public static Point2D.Double transformToXY(Point2D referencePoint,
Point2D longLat) {
return new Point2D.Double((longLat.getX() - referencePoint.getX())
* distlong[(int) referencePoint.getX() / 15],
(longLat.getY() - referencePoint.getY())
* distlat[(int) referencePoint.getY() / 15]);
}
/**
* Transforms a given X/Y coordinate in meters into a long latitude
* coordinate in degrees based on a given reference point given in long lat
*
* @param referencePoint
* the reference point as longitude latitude coordinates
* @param XY
* the point to be transformed in meters
* @return the longitude / latitude
*/
public static Point2D.Double transformToLongLat(Point2D referencePoint,
Point2D XY) {
return new Point2D.Double(
XY.getX() / distlong[(int) referencePoint.getX() / 15]
+ referencePoint.getX(),
(XY.getY() / distlat[(int) referencePoint.getY() / 15] + referencePoint
.getY()));
}
}
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network.modular.common;
import java.util.ArrayList;
import java.util.Collections;
import umontreal.iro.lecuyer.probdist.LognormalDist;
/**
*
* Taken from Gerald Klunker's PingErLookup
*
* @author Gerald Klunker, Leo Nobach
*
*/
public class PingErToolkit {
public static JitterParameter getJitterParameterFrom(double avgRtt, double minRtt, double dVar) {
return getJitterParameterDownhillSimplex(avgRtt - minRtt, dVar);
}
public static LognormalDist getNewLnDistFrom(double avgRtt, double minRtt,
double dVar) {
JitterParameter params = getJitterParameterFrom(avgRtt, minRtt, dVar);
return new LognormalDist(params.m, params.s);
}
/**
* Implemenation of a downhill simplex algortihm that finds the
* log-normal parameters mu and sigma that minimized the error between
* measured expectation and iqr and the resulting expectation and iqr.
*
* @param expectation
* value
* @param iqr
* variation
* @return JitterParameter object with the log-normal parameter mu and
* sigma
*/
public static JitterParameter getJitterParameterDownhillSimplex(
double expectation, double iqr) {
ArrayList<JitterParameter> solutions = new ArrayList<JitterParameter>();
solutions.add(new JitterParameter(0.1, 0.1, expectation, iqr));
solutions.add(new JitterParameter(0.1, 5.0, expectation, iqr));
solutions.add(new JitterParameter(5.0, 0.1, expectation, iqr));
Collections.sort(solutions);
// 100 interations are enough for good results
for (int c = 0; c < 100; c++) {
JitterParameter newSolution = getNewParameter1(solutions,
expectation, iqr);
if (newSolution != null
&& newSolution.getError() < solutions.get(0).getError()) {
JitterParameter newSolution2 = getNewParameter2(solutions,
expectation, iqr);
if (newSolution2 != null
&& newSolution2.getError() < newSolution.getError()) {
solutions.remove(2);
solutions.add(newSolution2);
} else {
solutions.remove(2);
solutions.add(newSolution);
}
} else if (newSolution != null
&& newSolution.getError() < solutions.get(2).getError()) {
solutions.remove(2);
solutions.add(newSolution);
} else {
solutions.get(1).m = solutions.get(1).m + 0.5
* (solutions.get(0).m - solutions.get(1).m);
solutions.get(2).m = solutions.get(2).m + 0.5
* (solutions.get(0).m - solutions.get(2).m);
solutions.get(1).s = solutions.get(1).s + 0.5
* (solutions.get(0).s - solutions.get(1).s);
solutions.get(2).s = solutions.get(2).s + 0.5
* (solutions.get(0).s - solutions.get(2).s);
}
Collections.sort(solutions);
}
return solutions.get(0);
}
/**
* Container the log-normal distribution parameters. Used in the
* Downhill Simplex method.
*
*/
public static class JitterParameter implements Comparable<JitterParameter> {
double m;
double s;
double ew;
double iqr;
public JitterParameter(double m, double s, double ew, double iqr) {
this.m = m;
this.s = s;
this.ew = ew;
this.iqr = iqr;
}
/**
* error will be minimized within the downhill simplx algorithm
*
* @return error (variation between measured expectation and iqr and
* the resulting log-normal expectation and iqr.
*/
public double getError() {
LognormalDist jitterDistribution = new LognormalDist(m, s);
double error1 = Math.pow((iqr - (jitterDistribution
.inverseF(0.75) - jitterDistribution.inverseF(0.25)))
/ iqr, 2);
double error2 = Math.pow((ew - Math.exp(m
+ (Math.pow(s, 2) / 2.0)))
/ ew, 2);
return error1 + error2;
}
public int compareTo(JitterParameter p) {
double error1 = this.getError();
double error2 = p.getError();
if (error1 < error2)
return -1;
else if (error1 > error2)
return 1;
else
return 0;
}
/**
*
* @return expectation value of the log-normal distribution
*/
public double getAverageJitter() {
return Math.exp(m + (Math.pow(s, 2) / 2.0));
}
/**
*
* @return iqr of the log-normal distribution
*/
public double getIQR() {
LognormalDist jitterDistribution = new LognormalDist(m, s);
return jitterDistribution.inverseF(0.75)
- jitterDistribution.inverseF(0.25);
}
@Override
public String toString() {
LognormalDist jitterDistribution = new LognormalDist(m, s);
double iqr1 = jitterDistribution.inverseF(0.75)
- jitterDistribution.inverseF(0.25);
double ew1 = Math.exp(m + (Math.pow(s, 2) / 2.0));
return "m: " + m + " s: " + s + " Error: " + getError()
+ " iqr: " + iqr1 + " ew: " + ew1;
}
}
/**
* movement of factor 2 to center of solutions
*
* @param solutions
* @param expectation
* @param iqr
* @return moved solution
*/
private static JitterParameter getNewParameter1(
ArrayList<JitterParameter> solutions, double expectation,
double iqr) {
double middleM = (solutions.get(0).m + solutions.get(1).m + solutions
.get(2).m) / 3.0;
double middleS = (solutions.get(0).s + solutions.get(1).s + solutions
.get(2).s) / 3.0;
double newM = middleM + (solutions.get(0).m - solutions.get(2).m);
double newS = middleS + (solutions.get(0).s - solutions.get(2).s);
if (newS > 0)
return new JitterParameter(newM, newS, expectation, iqr);
else
return null;
}
/**
* movement of factor 3 to center of solutions
*
* @param solutions
* @param expectation
* @param iqr
* @return moved solution
*/
private static JitterParameter getNewParameter2(
ArrayList<JitterParameter> solutions, double expectation,
double iqr) {
double middleM = (solutions.get(0).m + solutions.get(1).m + solutions
.get(2).m) / 3.0;
double middleS = (solutions.get(0).s + solutions.get(1).s + solutions
.get(2).s) / 3.0;
double newM = middleM + 2
* (solutions.get(0).m - solutions.get(2).m);
double newS = middleS + 2
* (solutions.get(0).s - solutions.get(2).s);
if (newS > 0)
return new JitterParameter(newM, newS, expectation, iqr);
else
return null;
}
}
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network.modular.db;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.log4j.Logger;
import org.xml.sax.SAXException;
import umontreal.iro.lecuyer.probdist.LognormalDist;
import de.tud.kom.p2psim.impl.network.IPv4NetID;
import de.tud.kom.p2psim.impl.network.modular.common.PingErToolkit;
import de.tud.kom.p2psim.impl.util.BackToXMLWritable;
import de.tud.kom.p2psim.impl.util.SymmetricRelation;
import de.tud.kom.p2psim.impl.util.Tuple;
import de.tud.kom.p2psim.impl.util.db.relational.DBInstantiationException;
import de.tud.kom.p2psim.impl.util.db.relational.RelationalDB;
import de.tud.kom.p2psim.impl.util.logging.SimLogger;
/**
* Database format for measurements of network characteristics for the Modular Network Layer.
* @author Leo Nobach
*
*/
public class NetMeasurementDB extends RelationalDB implements BackToXMLWritable {
static Logger log = SimLogger.getLogger(NetMeasurementDB.class);
boolean loadedFromFile = false;
public boolean wasLoadedFromFile() {
return loadedFromFile;
}
public class Continent extends StringAddressableDBIDObject {
public Continent(String name) {
super(name);
}
public Continent(IDBObjInstantiator inst) throws DBInstantiationException {
super(inst);
}
public String toString() {
return this.getName();
}
}
/**
* A geographical region of hosts, defined by PingEr
*
*/
public class PingErRegion extends StringAddressableDBIDObject {
public PingErRegion(String name) {
super(name);
}
public PingErRegion(IDBObjInstantiator inst) throws DBInstantiationException {
super(inst);
}
public String toString() {
return this.getName();
}
}
public class Country extends StringAddressableDBIDObject {
public Continent getContinent() {
return continent;
}
public void setContinent(Continent continent) {
this.continent = continent;
}
private Continent continent;
private PingErRegion pingErRegion;
private String cc;
public PingErRegion getPingErRegion() {
return pingErRegion;
}
public void setPingErRegion(PingErRegion pingErRegion) {
this.pingErRegion = pingErRegion;
}
public Country(String name, Continent continent, PingErRegion pingErRegion, String countryCode) {
super(name);
this.continent = continent;
this.pingErRegion = pingErRegion;
this.cc = countryCode;
}
public Country(IDBObjInstantiator inst) throws DBInstantiationException {
super(inst);
this.continent = inst.getDBObj("continent", Continent.class);
this.pingErRegion = inst.getDBObj("pingerregion", PingErRegion.class);
this.cc = inst.getString("cc");
}
public String getCC() {
return cc;
}
public String toString() {
return this.getName();
}
}
public class Region extends StringAddressableDBIDObject {
public Country getCountry() {
return country;
}
public void setCountry(Country country) {
this.country = country;
}
private Country country;
public Region(String name, Country country) {
super(name);
this.country = country;
}
public Region(IDBObjInstantiator inst) throws DBInstantiationException {
super(inst);
this.country = inst.getDBObj("country", Country.class);
}
public String toString() {
return this.getName();
}
}
public class City extends StringAddressableDBIDObject {
public Region getRegion() {
return region;
}
public void setRegion(Region region) {
this.region = region;
}
private Region region;
public City(String name, Region region) {
super(name);
this.region = region;
}
public City(IDBObjInstantiator inst) throws DBInstantiationException {
super(inst);
this.region = inst.getDBObj("region", Region.class);
}
public String toString() {
return this.getName();
}
}
/**
* Measurement information for a host
*
*/
public class Host extends DBObject {
City city;
double longitude;
double latitude;
List<Double> coordinates;
public Host(int ip, City city, double longitude, double latitude, List<Double> coordinates) {
super(ip);
this.city = city;
this.longitude = longitude;
this.latitude = latitude;
this.coordinates = coordinates;
}
public Host(IDBObjInstantiator inst) throws DBInstantiationException {
super(inst);
this.city = inst.getDBObj("city", City.class);
this.longitude = inst.getDouble("longitude");
this.latitude = inst.getDouble("latitude");
this.coordinates = inst.getList("coordinates", Double.class);
}
public City getCity() {
return city;
}
public double getLongitude() {
return longitude;
}
public double getLatitude() {
return latitude;
}
public List<Double> getCoordinates() { //TODO: Refactoring in getGNPCoordinates
return coordinates;
}
public String toString() {
return "Host(" + IPv4NetID.intToIP(this.getId()) + ")";
}
}
/**
* A group of hosts.
*
*/
public class Group extends StringAddressableDBIDObject {
private List<Host> members;
private transient int nextMember = 0;
public Group(IDBObjInstantiator inst) throws DBInstantiationException {
super(inst);
members = inst.getList("members", Host.class);
}
public Group(String name, List<Host> members) {
super(name);
this.members = members;
}
public List<Host> getMembers() {
return members;
}
public String toString() {
return this.getName();
}
public Host tGetNextMember() {
if (members.size() == 0) throw new IllegalStateException("The group named " + this.getName() + " exists, but is empty. Please change the group name or refresh data, or set 'useRegionGroups=\"false\" in the ModularNetLayerFactory'");
if (nextMember >= members.size()) throw new IllegalStateException("You can not create another host. Already created " + members.size() + " hosts in group " + this.getName());
Host result = members.get(nextMember);
nextMember++;
return result;
}
}
Map<Tuple<Object, Object>, SummaryRelation> relations = new HashMap<Tuple<Object, Object>, SummaryRelation>();
private String filename;
public GlobalSummaryRelation globRel = null;
public SummaryRelation getSummaryRelFrom(Object from, Object to) {
return relations.get(new SymmetricRelation<Object, Object>(from, to));
}
/**
* A relation from a set of hosts to another set of hosts. Summary relations are symmetric.
* Contains measurement data applicable for this relation of hosts
*
*/
public abstract class SummaryRelation extends DBObject {
public double getMinRtt() {
return minRtt;
}
public double getAvgRtt() {
return avgRtt;
}
public double getdVar() {
return dVar;
}
/**
* Returns the packet loss in PERCENT!
* @return
*/
public double getpLoss() {
return pLoss;
}
public LognormalDist tGetJitterLnDist() {
if (jitterLnDist == null) {
jitterLnDist = PingErToolkit.getNewLnDistFrom(avgRtt, minRtt, dVar);
log.debug("Calculated requested log-normal jitter distribution for summary relation " + this);
}
return jitterLnDist;
}
double minRtt;
double avgRtt;
double dVar;
double pLoss;
transient LognormalDist jitterLnDist = null;
public SummaryRelation(IDBObjInstantiator inst) throws DBInstantiationException {
super();
this.minRtt = inst.getDouble("minrtt");
this.avgRtt = inst.getDouble("avgrtt");
this.dVar = inst.getDouble("dvar");
this.pLoss = inst.getDouble("ploss");
}
public SummaryRelation(double minRtt, double avgRtt, double dVar,
double pLoss) {
super();
this.minRtt = minRtt;
this.avgRtt = avgRtt;
this.dVar = dVar;
this.pLoss = pLoss;
}
}
/**
* A relation from all hosts in a country to all hosts in another country
*/
public class CountryCountrySummaryRelation extends SummaryRelation {
private Country cntrA;
private Country cntrB;
public CountryCountrySummaryRelation(IDBObjInstantiator inst)
throws DBInstantiationException {
super(inst);
this.cntrA = inst.getDBObj("cntra", Country.class);
this.cntrB = inst.getDBObj("cntrb", Country.class);
put();
}
public CountryCountrySummaryRelation(Country cntrA, Country cntrB, double minRtt, double avgRtt,
double dVar, double pLoss) {
super(minRtt, avgRtt, dVar, pLoss);
this.cntrA = cntrA;
this.cntrB = cntrB;
put();
}
private void put() {
relations.put(new Tuple<Object, Object>(cntrA, cntrB), this);
}
public Country getCntrA() {
return cntrA;
}
public Country getCntrB() {
return cntrB;
}
public String toString() {
return "CC:" + cntrA.getName() + " <=> " + cntrB.getName();
}
}
/**
* A relation from all hosts in a country to all hosts in a region
*/
public class CountryRegionSummaryRelation extends SummaryRelation {
private Country cntrA;
private PingErRegion regB;
public CountryRegionSummaryRelation(IDBObjInstantiator inst)
throws DBInstantiationException {
super(inst);
this.cntrA = inst.getDBObj("cntra", Country.class);
this.regB = inst.getDBObj("regb", PingErRegion.class);
put();
}
public CountryRegionSummaryRelation(Country cntrA, PingErRegion regB, double minRtt, double avgRtt,
double dVar, double pLoss) {
super(minRtt, avgRtt, dVar, pLoss);
this.cntrA = cntrA;
this.regB = regB;
put();
}
private void put() {
relations.put(new Tuple<Object, Object>(cntrA, regB), this);
}
public Country getCntrA() {
return cntrA;
}
public PingErRegion getRegB() {
return regB;
}
public String toString() {
return "CR:" + cntrA.getName() + " <=> " + regB.getName();
}
}
/**
* A relation from all hosts in a region to all hosts in a country
*/
public class RegionCountrySummaryRelation extends SummaryRelation {
private PingErRegion regA;
private Country cntrB;
public RegionCountrySummaryRelation(IDBObjInstantiator inst)
throws DBInstantiationException {
super(inst);
this.regA = inst.getDBObj("rega", PingErRegion.class);
this.cntrB = inst.getDBObj("cntrb", Country.class);
put();
}
public RegionCountrySummaryRelation(PingErRegion regA, Country cntrB, double minRtt, double avgRtt,
double dVar, double pLoss) {
super(minRtt, avgRtt, dVar, pLoss);
this.regA = regA;
this.cntrB = cntrB;
put();
}
private void put() {
relations.put(new Tuple<Object, Object>(regA, cntrB), this);
}
public PingErRegion getRegA() {
return regA;
}
public Country getCntrB() {
return cntrB;
}
public String toString() {
return "RC:" + regA.getName() + " <=> " + cntrB.getName();
}
}
/**
* A relation from all hosts in a region to all hosts in another region
*/
public class RegionRegionSummaryRelation extends SummaryRelation {
private PingErRegion regA;
private PingErRegion regB;
public RegionRegionSummaryRelation(IDBObjInstantiator inst)
throws DBInstantiationException {
super(inst);
this.regA = inst.getDBObj("rega", PingErRegion.class);
this.regB = inst.getDBObj("regb", PingErRegion.class);
put();
}
public RegionRegionSummaryRelation(PingErRegion regA, PingErRegion regB, double minRtt, double avgRtt,
double dVar, double pLoss) {
super(minRtt, avgRtt, dVar, pLoss);
this.regA = regA;
this.regB = regB;
put();
}
private void put() {
relations.put(new Tuple<Object, Object>(regA, regB), this);
}
public PingErRegion getRegA() {
return regA;
}
public PingErRegion getRegB() {
return regB;
}
public String toString() {
return "RR:" + regA.getName() + " <=> " + regB.getName();
}
}
/**
* To use if no summary relation could be found for the host.
* @author
*
*/
public class GlobalSummaryRelation extends SummaryRelation {
public GlobalSummaryRelation(double minRtt, double avgRtt, double dVar,
double pLoss) {
super(minRtt, avgRtt, dVar, pLoss);
NetMeasurementDB.this.globRel = this;
}
public GlobalSummaryRelation(IDBObjInstantiator inst)
throws DBInstantiationException {
super(inst);
NetMeasurementDB.this.globRel = this;
}
}
@Override
public List<Class<? extends DBObject>> getDependencySortedSerializationOrder() {
List<Class<? extends DBObject>> result = new ArrayList<Class<? extends DBObject>>(4);
result.add(Continent.class);
result.add(PingErRegion.class);
result.add(Country.class);
result.add(Region.class);
result.add(City.class);
result.add(Host.class);
result.add(Group.class);
result.add(CountryCountrySummaryRelation.class);
result.add(CountryRegionSummaryRelation.class);
result.add(RegionCountrySummaryRelation.class);
result.add(RegionRegionSummaryRelation.class);
result.add(GlobalSummaryRelation.class);
return result;
}
/**
* To be called by the PeerfactSim.KOM configurator when giving the File parameter.
* @param filename
* @throws ParserConfigurationException
* @throws IOException
* @throws SAXException
*/
public void setFile(String filename) throws SAXException, IOException, ParserConfigurationException {
loadedFromFile = true;
InputStream input = null;
if (!new File(filename).exists()) {
if (new File(filename + ".zip").exists()) {
input = new BufferedInputStream(new ZipInputStream(new FileInputStream(filename + ".zip")));
}
} else {
input = new BufferedInputStream(new FileInputStream(filename));
}
log.info("Loading measurement database from " + filename + "...");
this.readFromXMLFile(input);
this.filename = filename;
}
public SummaryRelation getMostAccurateSummaryRelation(Host from,
Host to) {
Country host1Country = from.getCity().getRegion().getCountry();
Country host2Country = to.getCity().getRegion().getCountry();
SummaryRelation sumRel = getSummaryRelFrom(host1Country, host2Country);
if (sumRel == null) sumRel = getSummaryRelFrom(host1Country.getPingErRegion(), host2Country);
if (sumRel == null) sumRel = getSummaryRelFrom(host1Country, host2Country.getPingErRegion());
if (sumRel == null) sumRel = getSummaryRelFrom(host1Country.getPingErRegion(), host2Country);
if (sumRel == null) sumRel = getSummaryRelFrom(host1Country.getPingErRegion(), host2Country.getPingErRegion());
if (sumRel == null) return globRel;
return sumRel;
}
@Override
public void writeBackToXML(BackWriter bw) {
bw.writeSimpleType("file", filename);
}
}
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network.modular.livemon;
import de.tud.kom.p2psim.impl.util.LiveMonitoring.ProgressValue;
import de.tud.kom.p2psim.impl.util.toolkits.NumberFormatToolkit;
public class MsgDrop implements ProgressValue {
long dropped = 0;
long total = 0;
private String ownerName;
Object lock = new Object();
public MsgDrop(String ownerName) {
this.ownerName = ownerName;
}
public void droppedMessage() {
synchronized(lock) {
dropped ++;
total ++;
}
}
public void noDropMessage() {
synchronized(lock) {
total ++;
}
}
@Override
public String getName() {
return "Net: " + ownerName + " Msg Drop";
}
@Override
public String getValue() {
synchronized(lock) {
if (total == 0) return "Unknown";
return dropped + ", quota: " + NumberFormatToolkit.formatPercentage(dropped/(double)total, 3);
}
}
}
\ No newline at end of file
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network.modular.livemon;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.Map;
import java.util.Map.Entry;
import de.tud.kom.p2psim.api.network.NetMessage;
import de.tud.kom.p2psim.impl.util.LiveMonitoring;
import de.tud.kom.p2psim.impl.util.MultiSet;
import de.tud.kom.p2psim.impl.util.Tuple;
import de.tud.kom.p2psim.impl.util.toolkits.StringToolkit;
import de.tud.kom.p2psim.impl.util.toolkits.TimeToolkit;
import de.tudarmstadt.maki.simonstrator.api.Message;
import de.tudarmstadt.maki.simonstrator.api.Time;
import de.tudarmstadt.maki.simonstrator.api.component.network.NetID;
public class NetLayerLiveMonitoring {
static final boolean DBG_TRAF_CTRL_DROP = false;
static MsgDrop trafCtrlMsgDrop = new MsgDrop("Traffic Ctrl");
static MsgDrop subnetMsgDrop = new MsgDrop("Subnet");
static MsgDrop offlineMsgDrop = new MsgDrop("Offline");
static MsgDrop routingMsgDrop = new MsgDrop("Routing");
private static Writer bufWr;
public static void register() {
LiveMonitoring.addProgressValue(trafCtrlMsgDrop);
LiveMonitoring.addProgressValue(subnetMsgDrop);
LiveMonitoring.addProgressValue(offlineMsgDrop);
LiveMonitoring.addProgressValue(routingMsgDrop);
if (DBG_TRAF_CTRL_DROP) {
try {
bufWr = new BufferedWriter(new FileWriter(new File("outputs/trafCtrlPacketLossDump")));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
public static MsgDrop getTrafCtrlMsgDrop() {
return trafCtrlMsgDrop;
}
public static MsgDrop getSubnetMsgDrop() {
return subnetMsgDrop;
}
public static MsgDrop getOfflineMsgDrop() {
return offlineMsgDrop;
}
public static MsgDrop getRoutingMsgDrop() {
return routingMsgDrop;
}
public static void droppedMessageTrafCtrl(NetMessage netMsg) {
if (DBG_TRAF_CTRL_DROP) {
try {
Message msg = netMsg.getPayload().getPayload();
//bufWr.write("Dropped " + msg.getClass().getSimpleName() + ", s=" + netMsg.getSender() + ", r=" + netMsg.getReceiver() + ", msg='" + msg + "'\n");
Tuple<Class<? extends Message>, Tuple<NetID, NetID>> msgTpl = new Tuple<Class<? extends Message>, Tuple<NetID,NetID>>(msg.getClass(), new Tuple<NetID, NetID>(netMsg.getSender(), netMsg.getReceiver()));
msgAccu.addOccurrence(msgTpl);
msgs++;
if (msgs >= 10000) {
dumpMsgs();
msgAccu.clear();
msgs = 0;
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
getTrafCtrlMsgDrop().droppedMessage();
}
private static void dumpMsgs() throws IOException {
Map<Tuple<Class<? extends Message>, Tuple<NetID, NetID>>, Integer> msgList = msgAccu.getUnmodifiableMap();
bufWr.write("=================== Msgs dropped until " + TimeToolkit.getPFSDefaultTimeToolkit().timeStringFromLong(Time.getCurrentTime()) + "============\n");
for (Entry<Tuple<Class<? extends Message>, Tuple<NetID, NetID>>, Integer> tpl : msgList.entrySet()) {
bufWr.write(StringToolkit.padFixed(tpl.getKey().getA().getSimpleName() + ", s=" + tpl.getKey().getB().getA() + ", r=" + tpl.getKey().getB().getB() + ": ", 100) + tpl.getValue() + "\n");
}
}
static MultiSet<Tuple<Class<? extends Message>, Tuple<NetID, NetID>>> msgAccu = new MultiSet<Tuple<Class<? extends Message>,Tuple<NetID,NetID>>>();
static long msgs = 0;
}
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network.modular.st;
import de.tud.kom.p2psim.api.network.NetProtocol;
import de.tudarmstadt.maki.simonstrator.api.Message;
import de.tudarmstadt.maki.simonstrator.api.component.network.NetID;
/**
* A network layer usually splits up the SDU into multiple fragments, if it is too big.
* This strategy determines how many fragments are needed to service the given payload.
*
* @author Leo Nobach
*
*/
public interface FragmentingStrategy extends ModNetLayerStrategy {
/**
* Returns the number of fragments for the given payload in order to construct a NetMessage.
* @param payload , the payload passed by the transport layer
* @param receiver , the receiver address of the future net message
* @param sender , the sender address of the future net message
* @param netProtocol , the network protocol used of the future net message.
* @return
*/
public int getNoOfFragments(Message payload, NetID receiver, NetID sender, NetProtocol netProtocol);
}
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