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
package de.tud.kom.p2psim.impl.network.fairshare;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import de.tud.kom.p2psim.api.common.SimHost;
import de.tud.kom.p2psim.impl.network.IPv4NetID;
import de.tud.kom.p2psim.impl.network.fairshare.position.FairshareGnpPosition;
import de.tud.kom.p2psim.impl.network.fairshare.position.GeoLocation;
import de.tud.kom.p2psim.impl.util.logging.SimLogger;
import de.tudarmstadt.maki.simonstrator.api.Host;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.component.HostComponentFactory;
public class OptimizedNetLayerFactory implements HostComponentFactory {
private static Logger log = SimLogger
.getLogger(OptimizedNetLayerFactory.class);
private final OptimizedSubnet subnet;
private double downBandwidth;
private double upBandwidth;
private HashMap<IPv4NetID, GnpHostInfo> hostPool;
private HashMap<String, ArrayList<IPv4NetID>> namedGroups;
public OptimizedNetLayerFactory() {
subnet = new OptimizedSubnet();
}
@Override
public Node createComponent(Host phost) {
SimHost host = (SimHost) phost;
Node netLayer = newNetLayer(host, host.getProperties().getGroupID());
return netLayer;
}
/**
* random node form group
*
* @param id
* @return
*/
public Node newNetLayer(SimHost host, String id) {
if (this.namedGroups.containsKey(id)
&& !this.namedGroups.get(id).isEmpty()) {
int size = namedGroups.get(id).size();
IPv4NetID netId = namedGroups.get(id).get(
Randoms.getRandom(OptimizedNetLayerFactory.class).nextInt(
size));
namedGroups.get(id).remove(netId);
return newNetLayer(host, netId);
} else {
throw new IllegalStateException(
"No (more) Hosts are assigned to \"" + id + "\"");
}
}
private Node newNetLayer(SimHost host, IPv4NetID netID) {
FairshareGnpPosition gnpPos = this.hostPool.get(netID).gnpPosition;
GeoLocation geoLoc = this.hostPool.get(netID).geoLoc;
Node nw = new Node(host, downBandwidth, upBandwidth, netID, gnpPos,
geoLoc,
subnet);
hostPool.remove(netID);
return nw;
}
public void setGnpFile(String gnpFileName) {
File gnpFile = new File(gnpFileName);
hostPool = new HashMap<IPv4NetID, GnpHostInfo>();
namedGroups = new HashMap<String, ArrayList<IPv4NetID>>();
log.info("Read hosts from file " + gnpFile);
SAXReader reader = new SAXReader(false);
Document configuration = null;
try {
configuration = reader.read(gnpFile);
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Element root = configuration.getRootElement();
assert root.getName().equals("gnp");
for (Object obj : root.elements()) {
Element elem = (Element) obj;
if (elem.getName().equals("GroupLookup")) {
for (Iterator iter = elem.elementIterator("Group"); iter
.hasNext();) {
Element variable = (Element) iter.next();
String id = variable.attributeValue("id");
ArrayList<IPv4NetID> group = new ArrayList<IPv4NetID>();
for (Iterator ipIter = variable.elementIterator("IPs"); ipIter
.hasNext();) {
Element ipElement = (Element) ipIter.next();
String[] ips = ipElement.attributeValue("value").split(
",");
for (int c = 0; c < ips.length; c++)
group.add(new IPv4NetID(Long.parseLong(ips[c])));
}
if (namedGroups.containsKey(id)) {
throw new IllegalStateException(
"Multiple Group Definition in " + gnpFileName
+ " ( Group: " + id + " )");
} else {
namedGroups.put(id, group);
}
}
} else if (elem.getName().equals("Hosts")) {
for (Iterator iter = elem.elementIterator("Host"); iter
.hasNext();) {
Element variable = (Element) iter.next();
// IP-Address
IPv4NetID hostID = new IPv4NetID(Long.parseLong(variable
.attributeValue("ip")));
// GNP-Coordinates
String[] coordinatesS = variable.attributeValue(
"coordinates").split(",");
double[] coordinatesD = new double[coordinatesS.length];
for (int c = 0; c < coordinatesD.length; c++)
coordinatesD[c] = Double.parseDouble(coordinatesS[c]);
FairshareGnpPosition gnpPos = new FairshareGnpPosition(coordinatesD);
// GeoLocation
String continentalArea = variable
.attributeValue("continentalArea");
String countryCode = variable.attributeValue("countryCode");
String region = variable.attributeValue("region");
String city = variable.attributeValue("city");
String isp = variable.attributeValue("isp");
double longitude = Double.parseDouble(variable
.attributeValue("longitude"));
double latitude = Double.parseDouble(variable
.attributeValue("latitude"));
GeoLocation geoLoc = new GeoLocation(continentalArea,
countryCode, region, city, isp, latitude, longitude);
GnpHostInfo hostInfo = new GnpHostInfo(geoLoc, gnpPos);
hostPool.put(hostID, hostInfo);
}
}
}
}
public void setDownBandwidth(double downBandwidth) {
this.downBandwidth = downBandwidth / 8.0;
}
public void setUpBandwidth(double upBandwidth) {
this.upBandwidth = upBandwidth / 8.0;
}
private class GnpHostInfo {
private final FairshareGnpPosition gnpPosition;
private final GeoLocation geoLoc;
public GnpHostInfo(GeoLocation geoLoc, FairshareGnpPosition gnpPos) {
this.gnpPosition = gnpPos;
this.geoLoc = geoLoc;
}
}
}
package de.tud.kom.p2psim.impl.network.fairshare;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
import de.tud.kom.p2psim.api.network.NetLatencyModel;
import de.tud.kom.p2psim.api.network.NetLayer;
import de.tud.kom.p2psim.api.network.NetMessage;
import de.tud.kom.p2psim.impl.network.AbstractSubnet;
import de.tud.kom.p2psim.impl.network.IPv4Message;
import de.tud.kom.p2psim.impl.network.IPv4NetID;
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.Time;
import de.tudarmstadt.maki.simonstrator.api.component.network.NetID;
/**
*
* @author Gerald Klunker
* @version 0.1, 17.01.2008
*
*/
public class OptimizedSubnet extends AbstractSubnet implements EventHandler {
private static Logger log = SimLogger.getLogger(OptimizedSubnet.class);
private final NetLatencyModel netLatencyModel;
private final Map<IPv4NetID, Node> nodes;
private final FairShareAlgorithm fairShare;
private final List<Link> links;
private long nextMsgArrival;
private final static int EVENT_RECEIVE = 1;
private final static int EVENT_STATUS = 2;
public OptimizedSubnet() {
nodes = new HashMap<IPv4NetID, Node>();
fairShare = new FairShareAlgorithm();
links = new LinkedList<Link>();
netLatencyModel = new OptimizedLatencyModel();
}
public OptimizedSubnet(NetLatencyModel model) {
nodes = new HashMap<IPv4NetID, Node>();
fairShare = new FairShareAlgorithm();
links = new LinkedList<Link>();
netLatencyModel = model;
}
Node getNetLayer(NetID netId) {
return nodes.get(netId);
}
public NetLatencyModel getLatencyModel() {
return netLatencyModel;
}
/**
* Registers a NetWrapper in the SubNet.
*
* @param wrapper
* The NetWrapper.
*/
@Override
public void registerNetLayer(NetLayer netLayer) {
nodes.put((IPv4NetID) netLayer.getNetID(), (Node) netLayer);
}
@Override
public void eventOccurred(Object content, int type) {
if (type == EVENT_RECEIVE) {
IPv4Message msg = (IPv4Message) content;
Node receiver = nodes.get(msg.getReceiver());
receiver.receive(msg);
} else if (type == EVENT_STATUS) {
if (Time.getCurrentTime() == nextMsgArrival) {
log.debug("New Message arrival at -----------------------------------------------------> "
+ Time.getCurrentTime());
log.debug("Number of Links: " + links.size());
List<Link> obsoleteLinks = new LinkedList<Link>();
boolean error = true;
// Sort Link list by means of earliest transmission end time
Collections.sort(links, new TransferEndTimeComp());
// Dispatch messages and filter obsolete Links
for (Link link : links) {
if (link.getTransferEndTime() > nextMsgArrival) {
assert (!error);
break;
} else {
error = false;
assert (link.getTransferEndTime() == nextMsgArrival);
Node sender = link.getNode(false);
Node receiver = link.getNode(true);
assert (sender.isMessageQueueEmpty(receiver) == false);
NetMessage message = sender
.removeMessageFromQueue(receiver);
Event.scheduleWithDelay(link.getPropagationDelay(),
this, message, EVENT_RECEIVE);
assert (Time.getCurrentTime() - link.getCreationTime() > 0);
log.info(Time.getCurrentTime()
+ ">TCP Message arrived ("
+ message.getSender()
+ " -> "
+ message.getReceiver()
+ ") | "
+ message.getPayload()
+ ") | "
+ message.getPayload().getPayload()
+ " | Transmission time: "
+ ((Time.getCurrentTime() - link
.getCreationTime()) / (double) Time.MILLISECOND)
+ " ms"
+ "; Scheduling for "
+ (Time.getCurrentTime() + link
.getPropagationDelay()) + ".");
link.resetBurst();
boolean anotherMessageInQueue = !sender
.isMessageQueueEmpty(receiver);
if (anotherMessageInQueue) {
link.addBurstMessage(sender
.peekMessageQueue(receiver));
} else {
obsoleteLinks.add(link);
}
}
}
for (Link link : obsoleteLinks) {
if (!link.isBurst()) {
Node sender = link.getNode(false);
Node receiver = link.getNode(true);
links.remove(link);
sender.removeConnection(link, false);
receiver.removeConnection(link, true);
/*
* NOTE: CHANGED by Peter Heise:
*
* Did not recalculate all links on remove. Now has to
* called like.
*/
LinkedHashSet<Connection> links = new LinkedHashSet<Connection>();
receiver.traverseConnections(links, true);
sender.traverseConnections(links, false);
fairShare.run(links);
}
}
scheduleNextMessageArrival();
}
}
}
private void scheduleNextMessageArrival() {
nextMsgArrival = Long.MAX_VALUE;
for (Link l : links) {
if (l.hasStatusChanged())
l.calculateNewTransferEndTime();
if (l.getTransferEndTime() < nextMsgArrival)
nextMsgArrival = l.getTransferEndTime();
}
assert (nextMsgArrival >= Time.getCurrentTime()) : "nextMsgArrival is "
+ nextMsgArrival
+ "; current time is "
+ Time.getCurrentTime();
Event.scheduleWithDelay(nextMsgArrival - Time.getCurrentTime(), this,
null, EVENT_STATUS);
}
@Override
public void send(NetMessage msg) {
// TODO Auto-generated method stub
}
public void sendUDP(NetMessage netMsg) {
Node sender = nodes.get(netMsg.getSender());
Node receiver = nodes.get(netMsg.getReceiver());
long end2endDelay = netLatencyModel.getLatency(sender, receiver);
Event.scheduleWithDelay(end2endDelay, this, netMsg, EVENT_RECEIVE);
}
private void printFairShareGraph(String header) {
System.out.println(header);
for (Link link : links) {
System.out.println("Link: " + link.getNode(false).getNetID()
+ " --> " + link.getNode(true).getNetID() + " ("
+ link.getBandwidth() + ")");
}
}
// public boolean isLinkAlreadyEstablished(Node sender, Node receiver) {
// for (Link link : links) {
// if (link.getNode(false).equals(sender) &&
// link.getNode(true).equals(receiver))
// return true;
// }
// return false;
// }
public void sendTCPMessage(Node sender, Node receiver, double messageSize) {
Link link = new Link(sender, receiver, messageSize,
netLatencyModel.getLatency(sender, receiver));
// assert (!isLinkAlreadyEstablished(sender, receiver));
assert (!links.contains(link));
links.add(link);
LinkedHashSet<Connection> links = new LinkedHashSet<Connection>();
sender.traverseConnections(links, false);
fairShare.run(links);
log.debug("Sending TCP Message to " + receiver.getNetID()
+ " with latency of "
+ netLatencyModel.getLatency(sender, receiver)
/ Time.MILLISECOND + "ms at " + Time.getCurrentTime()
/ Time.MILLISECOND + "ms, size=" + messageSize + ", rate = "
+ link.getBandwidth());
scheduleNextMessageArrival();
}
public void isOffline(Node offlineNode,
Set<Connection> outgoingConnections,
Set<Connection> incomingConnections) {
// int a = 1;
for (Connection link : outgoingConnections) {
Node otherSide = link.getNode(true);
links.remove(link);
offlineNode.removeConnection(link, false);
otherSide.removeConnection(link, true);
LinkedHashSet<Connection> links = new LinkedHashSet<Connection>();
otherSide.traverseConnections(links, true);
fairShare.run(links);
}
for (Connection link : incomingConnections) {
Node otherSide = link.getNode(false);
links.remove(link);
offlineNode.removeConnection(link, true);
LinkedHashSet<Connection> links = new LinkedHashSet<Connection>();
otherSide.traverseConnections(links, false);
fairShare.run(links);
}
scheduleNextMessageArrival();
}
public void cancelTransmission(Node sender, Node receiver) {
Link toCancel = null;
for (Link link : links) {
Node src = link.getNode(false);
Node dst = link.getNode(true);
if (src.equals(sender) && dst.equals(receiver)) {
toCancel = link;
break;
}
}
assert (toCancel != null);
NetMessage message = sender.removeMessageFromQueue(receiver);
toCancel.resetBurst();
boolean anotherMessageInQueue = !sender.isMessageQueueEmpty(receiver);
if (anotherMessageInQueue) {
toCancel.addBurstMessage(sender.peekMessageQueue(receiver));
} else {
links.remove(toCancel);
sender.removeConnection(toCancel, false);
receiver.removeConnection(toCancel, true);
LinkedHashSet<Connection> links = new LinkedHashSet<Connection>();
sender.traverseConnections(links, false);
fairShare.run(links);
}
scheduleNextMessageArrival();
}
class TransferEndTimeComp implements Comparator<Link> {
@Override
public int compare(Link o1, Link o2) {
if (o1.getTransferEndTime() < o2.getTransferEndTime()) {
return -1;
} else if (o1.getTransferEndTime() > o2.getTransferEndTime()) {
return +1;
} else {
return 0;
}
}
}
}
\ No newline at end of file
package de.tud.kom.p2psim.impl.network.fairshare.position;
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 FairshareGnpPosition implements Position {
private static final long serialVersionUID = -1103996725403557900L;
private final double[] gnpCoordinates;
private double error = -1.0;
/**
*
* @param gnpCoordinates
* coordinate array for new position
*/
public FairshareGnpPosition(double[] gnpCoordinates) {
super();
this.gnpCoordinates = gnpCoordinates;
}
/**
*
* @param dimension
* @param maxDiversity
*/
public void diversify(double[][] dimension, double maxDiversity) {
for (int c = 0; c < this.gnpCoordinates.length; c++) {
double rand = (2 * maxDiversity * Randoms.getRandom(
FairshareGnpPosition.class)
.nextDouble()) - 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 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];
}
/**
*
* @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[1];
return result;
}
}
@Override
public double getDistance(Position netPosition) {
FairshareGnpPosition coord = (FairshareGnpPosition) netPosition;
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 int getTransmissionSize() {
// 2 * size(double)
return 2 * 8;
}
@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");
}
public double[] getCoords() {
return gnpCoordinates;
}
@Override
public FairshareGnpPosition clone() {
return new FairshareGnpPosition(gnpCoordinates);
}
}
package de.tud.kom.p2psim.impl.network.fairshare.position;
public class GeoLocation {
private final String countryCode;
private final String region;
private final String city;
private final String isp;
private final String continentalArea;
private final double latitude;
private final double longitude;
public GeoLocation(String conArea, String countryCode, String region,
String city, String isp, double latitude, double longitude) {
super();
this.continentalArea = conArea;
this.countryCode = countryCode;
this.region = region;
this.city = city;
this.isp = isp;
this.latitude = latitude;
this.longitude = longitude;
}
public String getContinentalArea() {
return continentalArea;
}
public String getCountryCode() {
return countryCode;
}
public String getRegion() {
return region;
}
public String getCity() {
return city;
}
public String getIsp() {
return isp;
}
public double getLatitude() {
return latitude;
}
public double getLongitude() {
return longitude;
}
}
/*
* 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.fairshare.position;
import de.tud.kom.p2psim.api.common.Position;
/**
* Implementation of NetPosition for Position and distance measurnment on the
* earth.
*
* @author Gerald Klunker
* @version 0.1, 05.02.2008
*
*/
public class GeographicPosition implements Position {
private final double latitude;
private final double longitude;
/**
*
* @param longitude
* @param latitude
*/
public GeographicPosition(double longitude, double latitude) {
this.longitude = longitude;
this.latitude = latitude;
}
/**
* @return geographical distance in km
*/
@Override
public double getDistance(Position point) {
double pi = 3.14159265;
double radConverter = pi / 180;
double lat1 = latitude * radConverter;
double lat2 = ((GeographicPosition) point).getLatitude() * radConverter;
double delta_lat = lat2 - lat1;
double delta_lon = (((GeographicPosition) point).getLongitude() - longitude)
* radConverter;
double temp = Math.pow(Math.sin(delta_lat / 2), 2) + Math.cos(lat1)
* Math.cos(lat2) * Math.pow(Math.sin(delta_lon / 2), 2);
return 2 * 6378.2 * Math.atan2(Math.sqrt(temp), Math.sqrt(1 - temp));
}
/**
*
* @return latitude of position
*/
public double getLatitude() {
return latitude;
}
/**
*
* @return longitude of position
*/
public double getLongitude() {
return longitude;
}
@Override
public int getTransmissionSize() {
// 2 * size(double)
return 2 * 8;
}
@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");
}
public GeographicPosition clone() {
return new GeographicPosition(longitude, latitude);
}
}
package de.tud.kom.p2psim.impl.network.fairshareng;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.apache.log4j.Logger;
import de.tud.kom.p2psim.impl.util.logging.SimLogger;
/**
* The Class DirectedGraph.
*
* This algorithm is based on the Paper
* Accurate and Efficient Simulation of Bandwidth Dynamics for Peer-To-Peer Overlay Networks
* by Alexandros Gkogkas et al.
*
*/
public class DirectedGraph {
/** The logger. */
private static Logger log = SimLogger.getLogger(DirectedGraph.class);
/** The flowList: contains all flows in graph. */
private final Collection<FairshareFlow> flowList;
/** The node map: contains all nodes in graph and respective flows of those. */
private final HashMap<FairshareNode, HashSet<FairshareFlow>[]> nodeMap;
/** Constants. */
private final static int UPLOADING_FLOWS = 0;
private final static int DOWNLOADING_FLOWS = 1;
/** Constants. */
private final static int AFFECTED_BY_UPLOAD_DECREASE = 0;
private final static int AFFECTED_BY_UPLOAD_INCREASE = 1;
private final static int AFFECTED_BY_DNLOAD_DECREASE = 2;
private final static int AFFECTED_BY_DNLOAD_INCREASE = 3;
/** Constants. */
public final static boolean EVENT_STREAM_NEW = true;
public final static boolean EVENT_STREAM_ENDED = false;
/** Constants. */
public final static boolean UPLOADING_FLOW = true;
public final static boolean DOWNLOADING_FLOW = false;
/** Constants. */
public final static boolean USED_FOR_SCHEDULING = true;
public final static boolean NOT_USED_FOR_SCHEDULING = false;
/** Depending on usage, use different data structures: Set in constructor */
private final boolean useForScheduling;
/**
* Instantiates a new empty directed graph.
*
* @param useForScheduling use graph for scheduling
*/
public DirectedGraph(boolean useForScheduling) {
this.nodeMap = new LinkedHashMap<FairshareNode, HashSet<FairshareFlow>[]>();
this.useForScheduling = useForScheduling;
if( useForScheduling ) {
this.flowList = new LinkedList<FairshareFlow>();
} else {
this.flowList = new LinkedHashSet<FairshareFlow>();
}
}
/**
* Instantiates a new directed graph containing given graph.
*
* @param graphToClone the full graph
*/
public DirectedGraph(DirectedGraph graphToClone) {
this(DirectedGraph.NOT_USED_FOR_SCHEDULING);
this.addAllNodes(graphToClone.getAllNodes());
this.addAllFlows(graphToClone.getAllFlows());
}
/**
* Adds a node to the graph.
*
* @param node
* the node
*/
@SuppressWarnings("unchecked")
public void addNode(FairshareNode node) {
if (node == null) {
return;
}
if (!this.nodeMap.containsKey(node)) {
this.nodeMap.put(node, new LinkedHashSet[] { new LinkedHashSet<FairshareFlow>(30), new LinkedHashSet<FairshareFlow>(30) });
}
}
/**
* Adds all nodes to the graph.
*
* @param nodes the nodes
*/
public void addAllNodes(Set<? extends FairshareNode> nodes) {
for (final FairshareNode node : nodes) {
this.addNode(node);
}
}
/**
* Adds a the flow to the graph. Nodes have to be existent or
* exception will be thrown.
*
* @param flow
* the flow
* @return true, if successful
*
* @throws Exception
* the exception
*/
public boolean addFlow(FairshareFlow flow) {
/*
* Save in nodeMap to enable fast lookup as well as in flowSet for fast
* iteration.
*/
this.nodeMap.get(flow.getSrc())[UPLOADING_FLOWS].add(flow);
this.nodeMap.get(flow.getDst())[DOWNLOADING_FLOWS].add(flow);
if( !this.useForScheduling ) {
return this.flowList.add(flow);
}
// Ok: We've got a list. Check for duplicates.
if( this.flowList.contains(flow) ) {
return false;
}
return this.flowList.add(flow);
}
/**
* Adds a the flow to the graph. Nodes _do not_ have to be existent before calling.
* In case nodes are not existent, nodes will be added to graph.
*
* @param flow
* the flow
* @return true, if successful
*/
public boolean addFlowWithNodes(FairshareFlow flow) {
this.addNode(flow.getSrc());
this.addNode(flow.getDst());
boolean result = false;
try {
result = this.addFlow(flow);
} catch (final Exception e) {
// None.
}
return result;
}
/**
* Adds the all flows to the graph.
*
* @param flows the flows
* @throws Exception the exception
*/
public void addAllFlows(Collection<FairshareFlow> flows) {
for (final FairshareFlow flow : flows) {
this.addFlow(flow);
}
}
/**
* Gets all flows.
*
* @return the all flows
*/
public Collection<FairshareFlow> getAllFlows() {
return this.flowList;
}
/**
* Gets all nodes.
*
* @return the all nodes
*/
public Set<FairshareNode> getAllNodes() {
return this.nodeMap.keySet();
}
/**
* Gets all uploading flows from Node
*
* @param node
* the node
* @return the uploading flows from node
*/
public Set<FairshareFlow> getUploadingFlowsFrom(FairshareNode node) {
return node == null ? null : this.nodeMap.get(node)[UPLOADING_FLOWS];
}
/**
* Gets the uploading flows from given node in ascending order.
*
* @param node the node
* @return the uploading flows from given node in asc order
*/
private List<FairshareFlow> getUploadingFlowsFromInAscOrder(FairshareNode node) {
final LinkedList<FairshareFlow> flows = new LinkedList<FairshareFlow>(this.getUploadingFlowsFrom(node));
Collections.sort(flows);
return flows;
}
/**
* Gets all downloading flows from Node
*
* @param node
* the node
* @return the downloading flows from
*/
public Set<FairshareFlow> getDownloadingFlowsTo(FairshareNode node) {
return node == null ? null : this.nodeMap.get(node)[DOWNLOADING_FLOWS];
}
/**
* Gets the downloading flows in asc order.
*
* @param node the node
* @return the downloading flows in asc order
*/
private List<FairshareFlow> getDownloadingFlowsInAscOrder(FairshareNode node) {
final LinkedList<FairshareFlow> flows = new LinkedList<FairshareFlow>(this.getDownloadingFlowsTo(node));
Collections.sort(flows);
return flows;
}
/**
* Tries to remove flow from graph. If flow does not exist in graph, no
* exception is raised.
*
* @param flow the flow
*/
public void tryRemoveFlow(FairshareFlow flow) {
if( this.flowList.contains(flow) ) {
this.removeFlow(flow);
}
}
/**
* Removes flow from the graph.
*
* @param flow the flow
*/
public void removeFlow(FairshareFlow flow) {
this.flowList.remove(flow);
this.nodeMap.get(flow.getSrc())[UPLOADING_FLOWS].remove(flow);
this.nodeMap.get(flow.getDst())[DOWNLOADING_FLOWS].remove(flow);
}
/**
* Removes node from the graph
*
* @param node the node
*
* @throws Exception Throws exception if node has active flows.
*/
public void removeNode(FairshareNode node) throws Exception {
if( (this.nodeMap.get(node)[UPLOADING_FLOWS].size() + this.nodeMap.get(node)[DOWNLOADING_FLOWS].size()) > 0 ) {
throw new Exception(node + " still has active links. Need to be removed first.");
}
this.nodeMap.remove(node);
}
/**
* Allocate bandwidth on full graph, min-max implementation based on Gkogkas et. al.
*
* Warning: method deletes flows from graph. If you need original graph,
* invoke clone();
*
* @throws Exception
* the exception
*/
public void allocateBandwidthOnFullGraph_Alg01() throws Exception {
final List<FairshareNode> satUp = new LinkedList<FairshareNode>();
final List<FairshareNode> satDown = new LinkedList<FairshareNode>();
// Reset all flows in subgraph.
for (final FairshareFlow flow : this.getAllFlows()) {
flow.setRate(0);
}
while (!this.getAllFlows().isEmpty()) {
/* Line 4 + 5. */
double fairshare_rate_upload = Double.MAX_VALUE;
double fairshare_rate_download = Double.MAX_VALUE;
for (final FairshareNode node : this.getAllNodes()) {
/* Calculate UPLOADING c_i / |F_i| */
final double c_i_up = node.getCurrentBandwidth().getUpBW();
if (c_i_up > 0) {
final int outgoing_links = this.getUploadingFlowsFrom(node).size();
final double current_fairshare_rate = (outgoing_links > 0) ? c_i_up / outgoing_links : Double.MAX_VALUE;
/* Add to minimal set. */
if (current_fairshare_rate <= fairshare_rate_upload) {
if (current_fairshare_rate < fairshare_rate_upload) {
satUp.clear();
fairshare_rate_upload = current_fairshare_rate;
}
satUp.add(node);
}
}
/* Calculate DOWNLOADING c_i / |F_i| */
final double c_i_down = node.getCurrentBandwidth().getDownBW();
if (c_i_down > 0) {
final int outgoing_links = this.getDownloadingFlowsTo(node).size();
final double current_fairshare_rate = (outgoing_links > 0) ? c_i_down / outgoing_links : Double.MAX_VALUE;
/* Add to minimal set. */
if (current_fairshare_rate <= fairshare_rate_download) {
if (current_fairshare_rate < fairshare_rate_download) {
satDown.clear();
fairshare_rate_download = current_fairshare_rate;
}
satDown.add(node);
}
}
}
/* Line 6 - 10. */
final double fairshare_rate = fairshare_rate_upload > fairshare_rate_download ? fairshare_rate_download : fairshare_rate_upload;
if (fairshare_rate_upload > fairshare_rate_download) {
satUp.clear();
} else if (fairshare_rate_upload < fairshare_rate_download) {
satDown.clear();
}
//log.debug(".. Calculating Fairshare Rate r*=" + fairshare_rate + "@" + satUp + satDown);
/*
* Part 1 of algorithm done.
*/
if (!satUp.isEmpty()) {
for (final FairshareNode node : satUp) {
for (final FairshareFlow flow : new LinkedList<FairshareFlow>(this.getUploadingFlowsFrom(node))) {
flow.setRate(fairshare_rate);
this.removeFlow(flow);
//log.debug("\t... Applying (satUp) to " + flow);
}
}
}
if (!satDown.isEmpty()) {
for (final FairshareNode node : satDown) {
for (final FairshareFlow flow : new LinkedList<FairshareFlow>(this.getDownloadingFlowsTo(node))) {
flow.setRate(fairshare_rate);
this.removeFlow(flow);
//log.debug("\t... Applying (satDown) to " + flow);
}
}
}
/*
* Part 2 of algorithm done.
*/
}
}
/**
* Discover affected subgraph according to
* "Accurate and Efficient Simulation of Bandwidth Dynamics for Peer-To-Peer Overlay Networks"
* by Alexandros Gkogkas.
*
* @param triggeringFlow the triggering flow
* @param newFlow flow is new (created) or old (gets deleted)
*
* @return the affected directed graph
*
* @throws Exception the exception
*/
@SuppressWarnings("unchecked")
public DirectedGraph discoverAffectedSubgraph_Alg02(FairshareFlow triggeringFlow, boolean newFlow) throws Exception {
int hop = 0;
final DirectedGraph affectedSubGraph = new DirectedGraph(false);
final HashSet<FairshareNode>[] affectedNodesByDiscovery = new LinkedHashSet[] { new LinkedHashSet<FairshareNode>(), new LinkedHashSet<FairshareNode>(), new LinkedHashSet<FairshareNode>(), new LinkedHashSet<FairshareNode>() };
/* New flow? Add. */
if (newFlow) {
affectedSubGraph.addFlowWithNodes(triggeringFlow);
}
Set<FairshareNode> sourceAffectedNodes_SAU = new LinkedHashSet<FairshareNode>();
sourceAffectedNodes_SAU.add(triggeringFlow.getSrc());
Set<FairshareNode> destinationAffectedNodes_DAU = new LinkedHashSet<FairshareNode>();
destinationAffectedNodes_DAU.add(triggeringFlow.getDst());
/* Line 6. */
while ( !(destinationAffectedNodes_DAU.isEmpty() && sourceAffectedNodes_SAU.isEmpty()) && ! sourceAffectedNodes_SAU.equals(destinationAffectedNodes_DAU) ) {
//log.debug("\n\nCalculating iteration/hop = " + (hop) + "/" + (((hop % 2) == 0) ? "even" : "odd"));
final Set<FairshareNode> tmp_sourceAffectedNodes_SAU_DASH = new LinkedHashSet<FairshareNode>();
final Set<FairshareNode> tmp_destinationAffectedNodes_DAU_DASH = new LinkedHashSet<FairshareNode>();
//log.debug(".. SAU = " + sourceAffectedNodes_SAU);
//log.debug(".. DAU = " + destinationAffectedNodes_DAU);
for (final FairshareNode node : sourceAffectedNodes_SAU) {
if ((((hop % 2) != 0) && newFlow)) { /* ODD, UP, NEW */
tmp_sourceAffectedNodes_SAU_DASH.addAll(downDecrease(affectedSubGraph, affectedNodesByDiscovery, node));
} else if ((((hop % 2) == 0) && newFlow)) { /* EVEN, UP, NEW */
tmp_sourceAffectedNodes_SAU_DASH.addAll(upIncrease(affectedSubGraph, affectedNodesByDiscovery, node));
} else if ((((hop % 2) != 0) && !newFlow)) { /* ODD, UP, FINISH */
tmp_sourceAffectedNodes_SAU_DASH.addAll(downIncrease(affectedSubGraph, affectedNodesByDiscovery, node));
} else if ((((hop % 2) == 0) && !newFlow)) { /* EVEN, UP, FINISH */
tmp_sourceAffectedNodes_SAU_DASH.addAll(upDecrease(affectedSubGraph, affectedNodesByDiscovery, node));
}
}
for (final FairshareNode node : destinationAffectedNodes_DAU) {
if ((((hop % 2) != 0) && newFlow)) { /* ODD, DOWN, NEW */
tmp_destinationAffectedNodes_DAU_DASH.addAll(upDecrease(affectedSubGraph, affectedNodesByDiscovery, node));
} else if ((((hop % 2) == 0) && newFlow)) { /* EVEN, DOWN, NEW */
tmp_destinationAffectedNodes_DAU_DASH.addAll(downIncrease(affectedSubGraph, affectedNodesByDiscovery, node));
} else if ((((hop % 2) != 0) && !newFlow)) { /* ODD, DOWN, FINISH */
tmp_destinationAffectedNodes_DAU_DASH.addAll(upIncrease(affectedSubGraph, affectedNodesByDiscovery, node));
} else if ((((hop % 2) == 0) && !newFlow)) { /* EVEN, DOWN, FINISH */
tmp_destinationAffectedNodes_DAU_DASH.addAll(downDecrease(affectedSubGraph, affectedNodesByDiscovery, node));
}
}
/* Line 19. */
sourceAffectedNodes_SAU = tmp_sourceAffectedNodes_SAU_DASH;
destinationAffectedNodes_DAU = tmp_destinationAffectedNodes_DAU_DASH;
//log.debug("SAU' = " + tmp_sourceAffectedNodes_SAU_DASH);
//log.debug("DAU' = " + tmp_destinationAffectedNodes_DAU_DASH);
/* Line 20. */
hop++;
}
return affectedSubGraph;
}
/**
* "Upload decrease": all affected upload decrease hosts. According to
* "Accurate and Efficient Simulation of Bandwidth Dynamics for Peer-To-Peer Overlay Networks"
* by Alexandros Gkogkas.
*
* @param affectedGraph the affected graph
* @param affectedNodesByDiscovery the affected nodes by discovery
* @param node the node
* @return the list
* @throws Exception the exception
*/
private List<FairshareNode> upDecrease(DirectedGraph affectedGraph, HashSet<FairshareNode>[] affectedNodesByDiscovery, FairshareNode node) throws Exception {
//log.debug(".. upDecrease on " + node);
affectedNodesByDiscovery[AFFECTED_BY_UPLOAD_DECREASE].add(node);
final List<FairshareNode> result = new LinkedList<FairshareNode>();
/* Line 2. */
for (final FairshareFlow flow : this.getUploadingFlowsFrom(node)) {
if (flow.isLocallyBottlenecked(node)) {
//log.debug(".... adding " + flow + " to AF");
if (affectedGraph.addFlowWithNodes(flow)) {
if (!affectedNodesByDiscovery[AFFECTED_BY_DNLOAD_INCREASE].contains(flow.getDst())) {
result.add(flow.getDst());
}
}
}
}
//log.debug(".... result = " + result);
return result;
}
/**
* "Upload increase": all affected upload increase hosts. According to
* "Accurate and Efficient Simulation of Bandwidth Dynamics for Peer-To-Peer Overlay Networks"
* by Alexandros Gkogkas.
*
* @param affectedGraph the affected graph
* @param affectedNodesByDiscovery the affected nodes by discovery
* @param node the node
* @return the list
* @throws Exception the exception
*/
private List<FairshareNode> upIncrease(DirectedGraph affectedGraph, HashSet<FairshareNode>[] affectedNodesByDiscovery, FairshareNode node) throws Exception {
//log.debug(".. upIncrease on " + node);
affectedNodesByDiscovery[AFFECTED_BY_UPLOAD_INCREASE].add(node);
final List<FairshareNode> result = new LinkedList<FairshareNode>();
/* Line 2. */
for (final FairshareFlow flow : this.getUploadingFlowsFrom(node)) {
if (flow.isLocallyBottlenecked(node)
|| (flow.isRemotelyBottlenecked(node) && (remotelyBottleneckedTurnIntoLocallyBottlenecked(node, flow, UPLOADING_FLOW) == false))) {
//log.debug(".... adding " + flow + " to AF");
if (affectedGraph.addFlowWithNodes(flow)) {
if (!affectedNodesByDiscovery[AFFECTED_BY_DNLOAD_DECREASE].contains(flow.getDst())) {
result.add(flow.getDst());
}
}
}
}
//log.debug(".... result = " + result);
return result;
}
/**
* "Down decrease": all affected download decrease hosts. According to
* "Accurate and Efficient Simulation of Bandwidth Dynamics for Peer-To-Peer Overlay Networks"
* by Alexandros Gkogkas.
*
* @param affectedGraph the affected graph
* @param affectedNodesByDiscovery the affected nodes by discovery
* @param node the node
* @return the list
* @throws Exception the exception
*/
private List<FairshareNode> downDecrease(DirectedGraph affectedGraph, HashSet<FairshareNode>[] affectedNodesByDiscovery, FairshareNode node) throws Exception {
//log.debug(".. downDecrease on " + node);
affectedNodesByDiscovery[AFFECTED_BY_DNLOAD_DECREASE].add(node);
final List<FairshareNode> result = new LinkedList<FairshareNode>();
/* Line 2. */
for (final FairshareFlow flow : this.getDownloadingFlowsTo(node)) {
if (flow.isLocallyBottlenecked(node)) {
//log.debug(".... adding " + flow + " to AF");
if (affectedGraph.addFlowWithNodes(flow)) {
if (!affectedNodesByDiscovery[AFFECTED_BY_UPLOAD_INCREASE].contains(flow.getSrc())) {
result.add(flow.getSrc());
}
}
}
}
//log.debug(".... result = " + result);
return result;
}
/**
* "Down increase": all affected download increase hosts. According to
* "Accurate and Efficient Simulation of Bandwidth Dynamics for Peer-To-Peer Overlay Networks"
* by Alexandros Gkogkas.
*
* @param affectedGraph the affected graph
* @param affectedNodesByDiscovery the affected nodes by discovery
* @param node the node
* @return the list
* @throws Exception the exception
*/
private List<FairshareNode> downIncrease(DirectedGraph affectedGraph, HashSet<FairshareNode>[] affectedNodesByDiscovery, FairshareNode node) throws Exception {
//log.debug(".. downIncrease on " + node);
affectedNodesByDiscovery[AFFECTED_BY_DNLOAD_INCREASE].add(node);
final List<FairshareNode> result = new LinkedList<FairshareNode>();
/* Line 2. */
for (final FairshareFlow flow : this.getDownloadingFlowsTo(node)) {
if (flow.isLocallyBottlenecked(node)
|| (flow.isRemotelyBottlenecked(node) && (remotelyBottleneckedTurnIntoLocallyBottlenecked(node, flow, DOWNLOADING_FLOW) == false))) {
//log.debug(".... adding " + flow + " to AF");
if (affectedGraph.addFlowWithNodes(flow)) {
if (!affectedNodesByDiscovery[AFFECTED_BY_UPLOAD_DECREASE].contains(flow.getSrc())) {
result.add(flow.getSrc());
}
}
}
}
//log.debug(".... result = " + result);
return result;
}
/**
* Return true if given node remotely bottlenecked node turns into locally bottlenecked on BW increase.
*
* According to
* "Accurate and Efficient Simulation of Bandwidth Dynamics for Peer-To-Peer Overlay Networks"
* by Alexandros Gkogkas.
*
* @param node the node
* @param flow the flow
* @return true, if successful
* @throws Exception the exception
*/
private boolean remotelyBottleneckedTurnIntoLocallyBottlenecked(FairshareNode node, FairshareFlow flow, boolean uploading) throws Exception {
final int ARRAY_INDEX_OFFSET = -1;
//log.debug(".... remotelyBottleneckedTurnIntoLocallyBottlenecked on " + node + "/" + flow);
/* Get remotely bottlenecked flows in ascending bandwidth order. */
final LinkedList<FairshareFlow> remotelyBottleNeckedFlows = new LinkedList<FairshareFlow>();
final List<FairshareFlow> flowList = (uploading) ? this.getUploadingFlowsFromInAscOrder(node) : this.getDownloadingFlowsInAscOrder(node);
for (final FairshareFlow curFlow : flowList) {
if (curFlow.isRemotelyBottlenecked(node)) {
remotelyBottleNeckedFlows.add(curFlow);
}
}
final int flowCount = flowList.size();
final double capacity_max = (uploading) ? node.getMaxBandwidth().getUpBW() : node.getMaxBandwidth().getDownBW();
double delta_C= 0;
for (int i = 1; i <= remotelyBottleNeckedFlows.size(); i++) {
if( i == 2 ) {
// Calculate C_1 --> i - 1
delta_C += ( (capacity_max / (flowCount + 1 )) - remotelyBottleNeckedFlows.get(1 + ARRAY_INDEX_OFFSET).getRate()) / flowCount;
} else if( i > 2 ) {
// Calculate C_2+ --> i - 1
double nominator = (capacity_max / ( flowCount + 1 )) + delta_C;
for (int j = 0; j < (i - 2); j++) {
nominator -= remotelyBottleNeckedFlows.get((i - 1) + ARRAY_INDEX_OFFSET).getRate();
}
final double denominator = ( (flowCount - i) + 1 );
delta_C += nominator / denominator;
}
final double r_i_calculated = (capacity_max / (flowCount + 1)) + delta_C;
boolean r_i_affected = false;
if (!(remotelyBottleNeckedFlows.get(i + ARRAY_INDEX_OFFSET).getRate() < r_i_calculated)) {
//log.debug("...... found affected flow: " + remotelyBottleNeckedFlows.get(i + ARRAY_INDEX_OFFSET));
r_i_affected = true;
}
//log.debug("........ i=" + i + " r_i=" + remotelyBottleNeckedFlows.get(i + ARRAY_INDEX_OFFSET).getRate() + " < " + r_i_calculated
// + " " + remotelyBottleNeckedFlows.get(i + ARRAY_INDEX_OFFSET));
if (remotelyBottleNeckedFlows.get(i + ARRAY_INDEX_OFFSET).getRate() >= flow.getRate()) {
//log.debug("........ AFFECTED=" + r_i_affected);
return r_i_affected ? false : true;
}
}
/* No flow affected. */
//log.debug("...... not affected/returning true!");
return true;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#clone()
*/
@Override
protected DirectedGraph clone() throws CloneNotSupportedException {
final DirectedGraph newGraph = new DirectedGraph(false);
newGraph.addAllNodes(this.getAllNodes());
try {
newGraph.addAllFlows(this.getAllFlows());
} catch (final Exception e) {
// No action.
}
return newGraph;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
final StringBuilder string = new StringBuilder();
for (final FairshareNode node : this.getAllNodes()) {
string.append(node.toString() + "\n");
for (final FairshareFlow flow : this.getUploadingFlowsFrom(node)) {
string.append(".. " + flow.toString() + "\n");
}
}
string.append("\n");
return string.toString();
}
/**
* Reset all flows in the graph.
*/
public void resetGraph() {
for (final FairshareFlow flow : this.getAllFlows()) {
flow.reset();
}
for (final FairshareNode node : this.getAllNodes()) {
node.reset();
}
}
/**
* Adds a subgraph to this graph.
*
* @param affectedGraph the affected graph
* @return true, if successful
*/
public boolean addGraph(DirectedGraph affectedGraph) {
this.addAllNodes(affectedGraph.getAllNodes());
try {
this.addAllFlows(affectedGraph.getAllFlows());
} catch (final Exception e) {
return false;
}
return true;
}
}
package de.tud.kom.p2psim.impl.network.fairshareng;
import org.apache.log4j.Logger;
import de.tud.kom.p2psim.impl.util.logging.SimLogger;
import de.tudarmstadt.maki.simonstrator.api.Time;
/**
* The Class Flow.
*/
public class FairshareFlow implements Comparable<FairshareFlow> {
private static Logger log = SimLogger.getLogger(FairshareFlow.class);
/** The dst. */
private final FairshareNode src, dst;
/** The hash code. */
private final int hashCode;
/** The propagation delay. */
private final long propagationDelay;
/** The current rate. */
private double currentRate;
/** Time when transfer is expected to end. */
private long transferEndTime;
/** Time when flow was first created (or burst was called). */
private long creationTime;
/** Remaining bytes. */
private double remainingBytes;
/** The last time, old current time. Needed to calculate remaining bytes. */
private long lastTime;
/** The old bandwidth. */
private double oldBandwidth;
/** The subnet. */
private final FairshareSubnet subnet;
/**
* Instantiates a new flow.
* @param fairshareSubnet
*
* @param src
* the src node
* @param dst
* the dst node
* @param messageSize
* size of message
* @param propagationDelay
* propagation delay of message
*/
public FairshareFlow(FairshareSubnet subnet, FairshareNode src, FairshareNode dst, double messageSize, long propagationDelay) {
this.subnet = subnet;
this.src = src;
this.dst = dst;
this.remainingBytes = messageSize;
this.propagationDelay = propagationDelay;
this.creationTime = Time.getCurrentTime();
this.lastTime = this.creationTime;
this.currentRate = 0;
this.oldBandwidth = 0;
/**
* FIXME [JR]: Using the following calculation, two distinct flows between the same nodes have the same hash code... !?
* Shouldn't parallel transfers between the same nodes be possible?
*/
final int hc = 17;
final int hashMultiplier = 59;
this.hashCode = (((hc * hashMultiplier) + this.src.hashCode()) * hc) + this.dst.hashCode();
}
/**
* Gets the dst of the flow.
*
* @return the dst
*/
public FairshareNode getDst() {
return this.dst;
}
/**
* Gets the src of the flow.
*
* @return the src
*/
public FairshareNode getSrc() {
return this.src;
}
/**
* Gets the current rate.
*
* @return the rate
*/
public double getRate() {
return this.currentRate;
}
/**
* Gets the propagation delay.
*
* @return the propagation delay
*/
public long getPropagationDelay() {
return this.propagationDelay;
}
/**
* Gets the transfer end time.
*
* @return the transfer end time
*/
public long getTransferEndTime() {
return this.transferEndTime;
}
/**
* Gets the creation time.
*
* @return the creation time
*/
public long getCreationTime() {
return this.creationTime;
}
/**
* Adds a new message to the flow.
*
* @param msgSize the msg size
*/
public void addBurstMessage(double msgSize) {
this.creationTime = Time.getCurrentTime();
this.lastTime = this.creationTime;
this.remainingBytes = msgSize;
assert (this.remainingBytes > 0);
/* Delete flow from scheduler as transferEndTime will change and we need to reinsert. */
this.subnet.removeEventFromSchedule(this);
this.calculateNewTransferEndTime();
/* Reinsert, according to new transferEndTime. */
this.subnet.addEventToSchedule(this);
}
/**
* Sets the flow's rate. Flow will automatically query Nodes for free
* bandwidth and reserve it.
*
* Usually called two times. Once: Set rate to zero, then again for real rate.
*
* @param newRate
* the new rate
* @throws Exception
* thrown if not enough bandwidth could be reserved
*/
public long setRate(double newRate) throws Exception {
assert( newRate >= 0 );
if( newRate != this.currentRate ) {
this.getSrc().addCurrentUpRate(newRate - this.currentRate);
this.getDst().addCurrentDownRate(newRate - this.currentRate);
this.oldBandwidth = this.currentRate;
this.currentRate = newRate;
// if( newRate > 0 ) {
// log.debug("Setting rate to " + newRate + "bytes/sec for " + this);
// }
if( newRate == 0 ) {
/* Rate is zero, so message will never be fully received. */
this.subnet.removeEventFromSchedule(this);
}
this.calculateNewTransferEndTime();
if( newRate > 0 ) {
/* Reschedule Flow. */
this.subnet.addEventToSchedule(this);
}
}
return this.transferEndTime;
}
/**
* Resets the Flow: Sets current rate to zero.
*/
public void reset() {
try {
this.setRate(0);
} catch (final Exception e) {
//None.
}
}
/**
* Checks if a node is locally bottlenecked.
*
* @param inRespectToNode
* the node in respect to
* @return true, if is locally bottlenecked
*
* @throws Exception
* thrown if neither src or dst match one end of the flow
*/
public boolean isLocallyBottlenecked(FairshareNode inRespectToNode) throws Exception {
if ((inRespectToNode != this.src) && (inRespectToNode != this.dst)) {
throw new Exception(inRespectToNode + " is neither src or dst.");
}
if (inRespectToNode == this.src) {
return (this.src.getCurrentBandwidth().getUpBW() == 0);
} else if (inRespectToNode == this.dst) {
return (this.dst.getCurrentBandwidth().getDownBW() == 0);
}
return false;
}
/**
* Checks if a node is remotely bottlenecked.
*
* @param inRespectToNode
* the node in respect to
* @return true, if is remotely bottlenecked
*
* @throws Exception
* thrown if neither src or dst match one end of the flow
*/
public boolean isRemotelyBottlenecked(FairshareNode inRespectToNode) throws Exception {
if ((inRespectToNode != this.src) && (inRespectToNode != this.dst)) {
throw new Exception(inRespectToNode + " is neither src or dst.");
}
if (inRespectToNode == this.dst) {
return (this.src.getCurrentBandwidth().getUpBW() == 0);
} else if (inRespectToNode == this.src) {
return (this.dst.getCurrentBandwidth().getDownBW() == 0);
}
return false;
}
private void calculateNewTransferEndTime() {
final long currentTime = Time.getCurrentTime();
final long lastTransferInterval = currentTime - this.lastTime;
this.lastTime = currentTime;
assert (lastTransferInterval >= 0);
final double byteBurst = (lastTransferInterval / (double) Time.SECOND)
* this.oldBandwidth;
this.remainingBytes -= byteBurst;
double time;
if( this.getRate() == 0 ) {
time = Double.POSITIVE_INFINITY;
} else {
time = this.remainingBytes / this.getRate();
}
this.transferEndTime = Math.round(time * Time.SECOND) + currentTime;
if (this.transferEndTime < currentTime) {
this.transferEndTime = currentTime;
}
assert (this.creationTime <= this.transferEndTime);
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (obj instanceof FairshareFlow) {
final FairshareFlow flow = (FairshareFlow) obj;
/**
* FIXME [JR]: Just to be sure: can't there be two distinct parallel flows between the same nodes?!
* With the following comparison they would be the same... make sure that is right!
* Maybe consider calculating a unique hash code (see comment above) and using this to compare them!
*/
return flow.getSrc().equals(this.getSrc()) && flow.getDst().equals(this.getDst());
}
return super.equals(obj);
}
/*
* (non-Javadoc)
*
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
@Override
public int compareTo(FairshareFlow flow) {
return ((Double)this.getRate()).compareTo(flow.getRate());
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
try {
return "Flow[ " + this.getSrc() + " -> " + this.getDst() + " Arr: " + this.transferEndTime + "]";
} catch (final Exception e) {
//None.
}
return null;
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
/* Precomputed so save time. */
return this.hashCode;
}
}
\ No newline at end of file
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* PeerfactSim.KOM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network.fairshareng;
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.IPv4NetID;
import de.tud.kom.p2psim.impl.network.fairshareng.livemon.FairshareLiveMonitoring;
import de.tud.kom.p2psim.impl.network.modular.DBHostListManager;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB;
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.PositioningStrategy;
import de.tud.kom.p2psim.impl.network.modular.st.positioning.GNPPositioning;
import de.tud.kom.p2psim.impl.util.logging.SimLogger;
import de.tudarmstadt.maki.simonstrator.api.Host;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
/**
* A factory for creating FairshareNetLayer objects.
*/
public class FairshareNetLayerFactory extends AbstractNetLayerFactory {
/** The logger. */
private static Logger log = SimLogger
.getLogger(FairshareNetLayerFactory.class);
/** The subnet. */
private final FairshareSubnet subnet;
private DBHostListManager dbHostList;
private PositioningStrategy strategy_positioning;
private boolean useRegionGroups = true;
/**
* Instantiates a new fairshare net layer factory.
*/
public FairshareNetLayerFactory() {
this.subnet = new FairshareSubnet();
this.strategy_positioning = new GNPPositioning();
}
/*
* (non-Javadoc)
*
* @see
* de.tud.kom.p2psim.api.common.ComponentFactory#createComponent(de.tud.
* kom.p2psim.api.common.Host)
*/
@Override
public FairshareNode createComponent(Host phost) {
SimHost host = (SimHost) phost;
// create new node here and add to graph
log.debug("createComponent: Creating new node: " + host);
final 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(
FairshareNetLayerFactory.class).nextInt()));
}
final FairshareNode newHost = new FairshareNode(host, this.subnet, id,
getBandwidth(id), strategy_positioning.getPosition(host, db,
hostMeta), hostMeta);
this.subnet.registerNetLayer(newHost);
return newHost;
}
/**
* Sets the latency strategy.
*
* @param latency
* the new latency
*/
public void setLatency(LatencyStrategy latency) {
this.subnet.setLatencyStrategy(latency);
}
/**
* Sets the positioning strategy.
*
* @param positioning
* the new positioning
*/
public void setPositioning(PositioningStrategy positioning) {
strategy_positioning = positioning;
}
/**
* Sets the packet loss strategy.
*
* @param pLoss
* the new ploss
*/
public void setUDPPLoss(PLossStrategy pLoss) {
this.subnet.setPLossStrategy(pLoss);
}
/**
* Sets the use subgraph discovery.
*
* @param use
* the new use subgraph discovery
*/
public void setUseSubgraphDiscovery(boolean use) {
subnet.useSubgraphDiscovery(use);
}
/**
* Sets the use region groups.
*
* @param useRegionGroups
* the new use region groups
*/
public void setUseRegionGroups(boolean useRegionGroups) {
this.useRegionGroups = useRegionGroups;
}
/**
* Sets the use of monitor.
*
* @param use
* the new use monitor
*/
public void setUseMonitor(boolean use) {
if (use) {
FairshareLiveMonitoring.register();
}
subnet.useMonitor(use);
}
@Override
public void writeBackToXML(BackWriter bw) {
super.writeBackToXML(bw);
bw.writeSimpleType("useRegionGroups", useRegionGroups);
bw.writeComplexType("Subnet", subnet);
// bw.writeComplexType("PLoss", strategies.pLoss);
// bw.writeComplexType("Latency", st);
bw.writeComplexType("Positioning", strategy_positioning);
}
}
package de.tud.kom.p2psim.impl.network.fairshareng;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
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.FlowBasedNetlayer;
import de.tud.kom.p2psim.api.network.NetMessage;
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.modular.db.NetMeasurementDB;
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.NetID;
/**
* The Class Node.
*/
public class FairshareNode extends AbstractNetLayer implements
FlowBasedNetlayer {
/** The log. */
private static Logger log = SimLogger.getLogger(FairshareNode.class);
/** The subnet. */
private final FairshareSubnet subnet;
/** The host queues. */
private final Map<FairshareNode, LinkedList<NetMessage>> hostQueues;
/** The Constant FLOAT_DELTA to correct Floats 9.999 to 10. */
private final static float FLOAT_DELTA = 1e-7f;
/** The hash code. */
private final int hashCode;
/**
* Instantiates a new node.
* @param netID
* @param geoLoc
*/
public FairshareNode(SimHost host, FairshareSubnet subnet, NetID netID,
BandwidthImpl maxBandwidth, Position position,
NetMeasurementDB.Host hostMeta) {
super(host, netID, maxBandwidth, position, hostMeta);
this.subnet = subnet;
this.hostQueues = new LinkedHashMap<FairshareNode, LinkedList<NetMessage>>();
this.hashCode = this.getNetID().hashCode();
}
/**
* Adds rate to the current down rate.
*
* @param downRate
*
* the down rate
* @throws Exception
* the exception
*/
public void addCurrentDownRate(double downRate) throws Exception {
final double currentDownBW = this.getCurrentBandwidth().getDownBW();
double realDownRate = currentDownBW - downRate;
/* Fix float, in case we get 9.999 save 10. */
if( Math.abs(Math.round(realDownRate) - realDownRate) < FLOAT_DELTA ) {
realDownRate = Math.round(realDownRate);
}
this.getCurrentBandwidth().setDownBW(realDownRate);
}
/**
* Adds rate to the current up rate.
*
* @param upRate
* the up rate
* @throws Exception
* the exception
*/
public void addCurrentUpRate(double upRate) throws Exception {
final double currentUpBW = this.getCurrentBandwidth().getUpBW();
double realUpRate = currentUpBW - upRate;
/* Fix float, in case we get 9.999 save 10. */
if( Math.abs(Math.round(realUpRate) - realUpRate) < FLOAT_DELTA ) {
realUpRate = Math.round(realUpRate);
}
this.getCurrentBandwidth().setUpBW(realUpRate);
}
/**
* Resets the node by setting current rates to zero.
*/
public void reset() {
this.setCurrentBandwidth(this.getMaxBandwidth().clone());
}
/* (non-Javadoc)
* @see de.tud.kom.p2psim.impl.network.AbstractNetLayer#goOffline()
*/
@Override
public void goOffline() {
super.goOffline();
this.subnet.disconnectHost(this);
}
/* (non-Javadoc)
* @see de.tud.kom.p2psim.api.network.NetLayer#send(de.tud.kom.p2psim.api.common.Message, de.tud.kom.p2psim.api.network.NetID, de.tud.kom.p2psim.api.network.NetProtocol)
*/
@Override
public void send(Message msg, NetID receiverId, NetProtocol protocol) {
if (isOnline()) {
assert (msg.getSize() >= 0);
assert (isSupported(((AbstractTransMessage) msg).getProtocol()));
final NetMessage netMsg = new IPv4Message(msg, receiverId, this.getNetID());
final TransProtocol tpMsg = ((AbstractTransMessage) msg).getProtocol();
if (tpMsg.equals(TransProtocol.UDP)) {
if (hasAnalyzer) {
netAnalyzerProxy
.netMsgEvent(netMsg, getHost(), Reason.SEND);
}
this.subnet.sendUDP(netMsg);
} else if (tpMsg.equals(TransProtocol.TCP)) {
final FairshareNode receiver = this.subnet.getNetLayer(receiverId);
LinkedList<NetMessage> queuedMessages = this.hostQueues.get(receiver);
if (queuedMessages == null) {
queuedMessages = new LinkedList<NetMessage>();
this.hostQueues.put(receiver, queuedMessages);
}
if (hasAnalyzer) {
netAnalyzerProxy
.netMsgEvent(netMsg, getHost(), Reason.SEND);
}
if (queuedMessages.isEmpty()) {
try {
this.subnet.sendTCPMessage(netMsg);
} catch (final Exception e) {
/*
* Can't throw exception here as send(Message msg, NetID receiverId, NetProtocol protocol) is overwritten.
*/
log.error("Exception..: sendTCP failed: " + e);
assert(false) : "sendTCP failed: " + e;
}
}
queuedMessages.add(netMsg);
} else {
/*
* Can't throw exception here as send(Message msg, NetID receiverId, NetProtocol protocol) is overwritten.
*/
log.error("Unsupported transport protocol " + tpMsg);
assert (false) : "Unsupported transport protocol " + tpMsg;
}
} else {
log.warn("Host " + this + " is offline.");
}
}
/* (non-Javadoc)
* @see de.tud.kom.p2psim.impl.network.AbstractNetLayer#isSupported(de.tud.kom.p2psim.api.transport.TransProtocol)
*/
@Override
protected boolean isSupported(TransProtocol protocol) {
return (protocol.equals(TransProtocol.UDP) || protocol.equals(TransProtocol.TCP));
}
/**
* Checks if message queue is empty.
*
* @param receiver the receiver
* @return true, if is message queue empty
*/
public boolean isMessageQueueEmpty(FairshareNode receiver) {
return this.hostQueues.get(receiver).isEmpty();
}
/**
* Peek message queue and return size of next expected arrival.
*
* @param receiver the receiver
* @return the double
*/
public double peekMessageQueue(FairshareNode receiver) {
return this.hostQueues.get(receiver).get(0).getSize();
}
/**
* Gets a read-only view on message queue.
*
* @param receiver the receiver
* @return the view on message queue
*/
public List<NetMessage> getViewOnMessageQueue(FairshareNode receiver) {
return Collections.unmodifiableList(this.hostQueues.get(receiver));
}
/**
* Removes the message from queue.
*
* @param receiver the receiver
* @return the net message
*/
public NetMessage removeMessageFromQueue(FairshareNode receiver) {
return this.hostQueues.get(receiver).remove(0);
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
return (obj instanceof FairshareNode) ? ((FairshareNode) obj).getNetID().hashCode() == this.getNetID().hashCode() : super.equals(obj);
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return this.getLocalInetAddress() + " (U:"
+ this.getCurrentBandwidth().getUpBW() + "/D:"
+ this.getCurrentBandwidth().getDownBW() + ")";
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
/* Precomputed to save time. */
return this.hashCode;
}
}
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* PeerfactSim.KOM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network.fairshareng;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
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.api.network.NetMessage;
import de.tud.kom.p2psim.impl.network.AbstractSubnet;
import de.tud.kom.p2psim.impl.network.IPv4Message;
import de.tud.kom.p2psim.impl.network.IPv4NetID;
import de.tud.kom.p2psim.impl.network.fairshareng.livemon.FairshareLiveMonitoring;
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.latency.GNPLatency;
import de.tud.kom.p2psim.impl.network.modular.st.ploss.NoPacketLoss;
import de.tud.kom.p2psim.impl.transport.AbstractTransMessage;
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.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;
public class FairshareSubnet extends AbstractSubnet implements EventHandler,
BackToXMLWritable {
// Instantiate the logging facility.
private static Logger log = SimLogger.getLogger(FairshareSubnet.class);
// Actual graph with Nodes.
private final DirectedGraph fullGraph;
// Mapping from NetID to Nodes.
private final Map<NetID, FairshareNode> nodes;
// Scheduler List.
private final SchedulerList schedulerList;
// Next message arrival.
private long nextMessageArrival = 0;
// Enable subgraph discovery.
private boolean useSubgraphDiscovery = true;
// Enable subgraph Live monitor
private boolean useLiveMonitor = false;
// Net latency model, default GNP. User can overwrite to SimpleLatencyModel
private LatencyStrategy strategyLatency;
// Packet loss strategy
private PLossStrategy strategyPLoss;
private final static int EVENT_RECEIVE = 1;
private final static int EVENT_STATUS = 2;
private NetlayerAnalyzer netAnalyzerProxy = null;
private boolean analyzerInit = false;
private boolean hasAnalyzer = false;
/**
* Instantiates a new fairshare subnet.
*/
public FairshareSubnet() {
this.fullGraph = new DirectedGraph(DirectedGraph.USED_FOR_SCHEDULING);
this.nodes = new LinkedHashMap<NetID, FairshareNode>();
this.schedulerList = new SchedulerList(this.fullGraph);
/** DEFAULTS, override in XML: **/
/* Static latency */
this.strategyLatency = new GNPLatency();
/* No packet loss */
this.strategyPLoss = new NoPacketLoss();
}
private boolean hasAnalyzer() {
if (!analyzerInit) {
try {
analyzerInit = true;
netAnalyzerProxy = Monitor.get(NetlayerAnalyzer.class);
hasAnalyzer = true;
} catch (AnalyzerNotAvailableException e) {
//
}
}
return hasAnalyzer;
}
/* (non-Javadoc)
* @see de.tud.kom.p2psim.impl.network.AbstractSubnet#registerNetLayer(de.tud.kom.p2psim.api.network.NetLayer)
*/
@Override
public void registerNetLayer(NetLayer net) {
if( ! (net instanceof FairshareNode) ) {
/*
* Can't throw exception here as registerNetLayer is overwritten.
*/
log.error("Registered wrong netlayer with faireshare subnet.");
assert (false) : "Registered wrong netlayer with fairshare subnet.";
}
//log.debug("Registering new node " + net.getNetID() + " in graph. ");
net.goOnline();
this.nodes.put(net.getNetID(), (FairshareNode) net);
this.fullGraph.addNode((FairshareNode) net);
}
/* (non-Javadoc)
* @see de.tud.kom.p2psim.impl.network.AbstractSubnet#send(de.tud.kom.p2psim.api.network.NetMessage)
*/
@Override
public void send(NetMessage msg) {
/*
* Can't throw exception here as send(NetMessage msg) is overwritten.
*/
log.error("send(NetMessage msg) is not supported. Use sendUDP or sendTCP instead.");
assert (false) : "send(NetMessage msg) is not supported. Use sendUDP or sendTCP instead.";
}
/**
* Send a udp message through the subnet
*
* @param netMsg the net msg
*/
public void sendUDP(NetMessage netMsg) {
// Sender of msg
final FairshareNode sender = getNetLayer(netMsg.getSender());
// Receiver of msg
final FairshareNode receiver = getNetLayer(netMsg.getReceiver());
// Get latency
final long latency = this.strategyLatency.getMessagePropagationDelay(netMsg, sender, receiver, getDB());
if (netMsg.getSender().equals(netMsg.getReceiver())) {
log.fatal("Sender and receiver are the same ("
+ netMsg.getSender() + ") for msg "
+ netMsg.getPayload().getPayload());
}
if( strategyPLoss.shallDrop(netMsg, sender, receiver, getDB()) ) {
// Monitor dropped message. The message loss is assigned to the
// sender as the receiver does not know, that it would have
// almost received a message
final int assignedMsgId = determineTransMsgNumber(netMsg);
//log.debug("During Drop: Assigning MsgId " + assignedMsgId + " to dropped message");
((AbstractTransMessage) netMsg.getPayload()).setCommId(assignedMsgId);
if (hasAnalyzer()) {
netAnalyzerProxy.netMsgEvent(netMsg, sender.getHost(),
Reason.DROP);
}
//log.debug("Packet loss occured while transfer \"" + netMsg + "\" (packetLossProb: " + packetLossProb + ")");
} else {
//log.info("Sending UDP Message to " + receiver + " with latency of " + (latency/Simulator.MILLISECOND_UNIT) + "ms at " + (Simulator.getCurrentTime()/Simulator.MILLISECOND_UNIT) + "ms");
Event.scheduleWithDelay(latency, this, netMsg, EVENT_RECEIVE);
}
}
/**
* Send a tcp message through the subnet
*
* @param netMsg the net msg
* @throws Exception the exception if flow can't be added
*/
public void sendTCPMessage(NetMessage netMsg) throws Exception {
// Sender of msg
final FairshareNode sender = getNetLayer(netMsg.getSender());
// Receiver of msg
final FairshareNode receiver = getNetLayer(netMsg.getReceiver());
// Get latency
final long latency = this.strategyLatency.getMessagePropagationDelay(netMsg, sender, receiver, getDB());
//log.info("Sending TCP Message to " + receiver + " with latency of " + (latency/Simulator.MILLISECOND_UNIT) + "ms at " + (Simulator.getCurrentTime()/Simulator.MILLISECOND_UNIT) + "ms, size=" + messageSize);
// Create new flow. If flow already exists, Node would have taken care of burst.
final FairshareFlow triggeringFlow = new FairshareFlow(this, sender, receiver, netMsg.getSize(), latency);
if( this.useSubgraphDiscovery ) {
// Find affected subgraph
final DirectedGraph affectedGraph = this.fullGraph.discoverAffectedSubgraph_Alg02(triggeringFlow, DirectedGraph.EVENT_STREAM_NEW);
// Add flow to full graph
this.fullGraph.addFlow(triggeringFlow);
if( this.useLiveMonitor ) {
FairshareLiveMonitoring.addNewValue( affectedGraph.getAllFlows().size() / (float) this.fullGraph.getAllFlows().size() );
}
// Calculate new rates _only_ on subgraph. Fullgraph will automatically be updated as same objects used.
affectedGraph.allocateBandwidthOnFullGraph_Alg01();
} else {
// Add flow to full graph
this.fullGraph.addFlow(triggeringFlow);
// Fake affectedGraph -> everything is affected.
// Need for cloing as flows will get deleted in graph.
final DirectedGraph affectedGraph = new DirectedGraph(this.fullGraph);
// Calculate new rates _only_ on subgraph. Fullgraph will automatically be updated as same objects used.
affectedGraph.allocateBandwidthOnFullGraph_Alg01();
}
// Schedule only on affectedFlows.
scheduleNextMessageArrival();
}
/**
* Schedule next message arrival.
*/
private void scheduleNextMessageArrival() {
final long newNextMsgArrival = this.schedulerList.getNextArrival();
assert (newNextMsgArrival >= Time.getCurrentTime()) : "nextMsgArrival is "
+ newNextMsgArrival
+ "; current time is "
+ Time.getCurrentTime();
//log.debug("Scheduling next Msg arrival for " + newNextMsgArrival + "," + ((newNextMsgArrival -Simulator.getCurrentTime()) / Simulator.MILLISECOND_UNIT) + "ms from now.");
/* Only schedule if different arrival time is expected. */
if( this.nextMessageArrival != newNextMsgArrival ) {
Event.scheduleWithDelay(newNextMsgArrival - Time.getCurrentTime(),
this, null, EVENT_STATUS);
}
this.nextMessageArrival = newNextMsgArrival;
}
@Override
public void eventOccurred(Object content, int type) {
if (type == EVENT_RECEIVE) {
final IPv4Message msg = (IPv4Message) content;
/* Boardcast: Deliver msg to all hosts. */
if (msg.getReceiver().equals(IPv4NetID.LOCAL_BROADCAST)) {
for (FairshareNode receiver : nodes.values()) {
if (!receiver.getNetID().equals(msg.getSender())) {
receiver.receive(msg);
}
}
/* Else: Unicast. */
} else {
final FairshareNode receiver = getNetLayer(msg.getReceiver());
receiver.receive(msg);
}
} else if (type == EVENT_STATUS) {
if (this.schedulerList.hasCurrentlyArrivingFlow()) {
final List<FairshareFlow> obsoleteLinks = new LinkedList<FairshareFlow>();
final List<FairshareFlow> requeueLinks = new LinkedList<FairshareFlow>();
while (this.schedulerList.hasCurrentlyArrivingFlow()) {
// log.debug("New Message arrival at -----------------------------------------------------> "
// + Simulator.getCurrentTime() + "us");
final FairshareFlow flow = this.schedulerList
.getAndRemoveCurrentArrival();
assert (flow.getTransferEndTime() == Time.getCurrentTime()) : "Message arrived too late: "
+ flow.getTransferEndTime()
+ "/"
+ Time.getCurrentTime();
final FairshareNode sender = flow.getSrc();
final FairshareNode receiver = flow.getDst();
assert (sender.isMessageQueueEmpty(receiver) == false) : "Sender queue is empty";
final NetMessage message = sender
.removeMessageFromQueue(receiver);
Event.scheduleWithDelay(flow.getPropagationDelay(), this,
message, EVENT_RECEIVE);
assert ((Time.getCurrentTime() - flow.getCreationTime()) > 0);
// log.info(Simulator.getCurrentTime() +
// ">TCP Message arrived ("
// + message.getSender()
// + " -> "
// + message.getReceiver()
// + ") | "
// + message.getPayload()
// + ") | "
// + message.getPayload().getPayload()
// + " | Transmission time: "
// + ((Simulator.getCurrentTime() - flow.getCreationTime())
// / (double) Simulator.MILLISECOND_UNIT) + " ms"
// + "; Scheduling for " + (Simulator.getCurrentTime() +
// flow.getPropagationDelay()) + ".");
if (!sender.isMessageQueueEmpty(receiver)) {
requeueLinks.add(flow);
} else {
obsoleteLinks.add(flow);
}
}
for (FairshareFlow flow : requeueLinks) {
final FairshareNode sender = flow.getSrc();
final FairshareNode receiver = flow.getDst();
flow.addBurstMessage(sender.peekMessageQueue(receiver));
}
/* Assign new bandwidth. */
final DirectedGraph fullyAffectedGraph = new DirectedGraph(
false);
for (final FairshareFlow triggeringFlow : obsoleteLinks) {
// log.debug("Deleting " + triggeringFlow);
try {
/* Remove flow from full graph */
this.fullGraph.removeFlow(triggeringFlow);
/* Find affected subgraph */
fullyAffectedGraph.addGraph(this.fullGraph
.discoverAffectedSubgraph_Alg02(triggeringFlow,
DirectedGraph.EVENT_STREAM_ENDED));
} catch (final Exception e) {
// None.
}
}
/*
* Reset all flows. Has to be called *after* all
* subgraphDiscovery for all obsolete Flows.
*/
for (final FairshareFlow fairshareFlow : obsoleteLinks) {
fairshareFlow.reset();
this.schedulerList.removeEvent(fairshareFlow);
/*
* Try to remove flow from affected graph: May be included
* if multiple messages arrive at same time.
* allocateBandwidth will then only be called once.
*/
fullyAffectedGraph.tryRemoveFlow(fairshareFlow);
}
try {
if (this.useSubgraphDiscovery) {
if (this.useLiveMonitor) {
float ratio = fullyAffectedGraph.getAllFlows()
.size()
/ (float) this.fullGraph.getAllFlows()
.size();
if (Float.isNaN(ratio)) { /*
* Happens when
* fullyAffectedGraph is
* empty.
*/
ratio = 0f;
}
FairshareLiveMonitoring.addNewValue(ratio);
}
fullyAffectedGraph.allocateBandwidthOnFullGraph_Alg01();
} else {
final DirectedGraph affectedGraph = new DirectedGraph(
this.fullGraph);
// Calculate new rates _only_ on subgraph. Fullgraph
// will automatically be updated as same objects used.
affectedGraph.allocateBandwidthOnFullGraph_Alg01();
}
} catch (final Exception e) {
// None.
}
// Schedule next message.
scheduleNextMessageArrival();
}
}
}
/**
* Gets the net layer of given NetID
*
* @param receiverId the receiver id
* @return the net layer
*/
public FairshareNode getNetLayer(NetID receiverId) {
return this.nodes.get(receiverId);
}
/**
* Disconnect host, e.g. JUNIT test goOffline().
*
* @param fairshareNode the fairshare node to go offline.
*/
public void disconnectHost(FairshareNode fairshareNode) {
/* Get all affected Flows */
List<FairshareFlow> obsoleteLinks = new LinkedList<FairshareFlow>();
obsoleteLinks.addAll(this.fullGraph.getUploadingFlowsFrom(fairshareNode));
obsoleteLinks.addAll(this.fullGraph.getDownloadingFlowsTo(fairshareNode));
/* Assign new bandwidth. */
final DirectedGraph fullyAffectedGraph = new DirectedGraph(false);
for (final FairshareFlow triggeringFlow : obsoleteLinks) {
try {
/* Remove flow from full graph */
this.fullGraph.removeFlow(triggeringFlow);
/* Find affected subgraph */
fullyAffectedGraph.addGraph(this.fullGraph.discoverAffectedSubgraph_Alg02(triggeringFlow, DirectedGraph.EVENT_STREAM_ENDED));
}
catch (final Exception e) {
// None.
}
}
/* Reset all flows. Has to be called *after* all subgraphDiscovery for all obsolete Flows. */
for (final FairshareFlow fairshareFlow : obsoleteLinks) {
fairshareFlow.reset();
this.schedulerList.removeEvent(fairshareFlow);
/* Try to remove flow from affected graph: May be included if multiple messages arrive at same time.
* allocateBandwidth will then only be called once. */
fullyAffectedGraph.tryRemoveFlow(fairshareFlow);
}
try {
if( this.useSubgraphDiscovery ) {
fullyAffectedGraph.allocateBandwidthOnFullGraph_Alg01();
} else {
final DirectedGraph affectedGraph = new DirectedGraph(this.fullGraph);
// Calculate new rates _only_ on subgraph. Fullgraph will automatically be updated as same objects used.
affectedGraph.allocateBandwidthOnFullGraph_Alg01();
}
} catch (final Exception e) {
// None.
}
// Schedule next message.
scheduleNextMessageArrival();
}
/**
* Adds the event to schedule.
*
* @param fairshareFlow the fairshare flow
*/
public void addEventToSchedule(FairshareFlow fairshareFlow) {
this.schedulerList.addEvent(fairshareFlow);
}
/**
* Removes the event from schedule.
*
* @param fairshareFlow the fairshare flow
*/
public void removeEventFromSchedule(FairshareFlow fairshareFlow) {
this.schedulerList.removeEvent(fairshareFlow);
}
/**
* Use subgraph discovery.
*
* @param useSubgraphDiscovery the use subgraph discovery
*/
public void useSubgraphDiscovery(boolean useSubgraphDiscovery) {
this.useSubgraphDiscovery = useSubgraphDiscovery;
}
/**
* Use live monitor.
*
* @param useMonitor the use monitor
*/
public void useMonitor(boolean useMonitor) {
this.useLiveMonitor = useMonitor;
}
/**
* Sets the latency strategy.
*
* @param latency the new latency strategy
*/
public void setLatencyStrategy(LatencyStrategy latency) {
this.strategyLatency = latency;
}
/**
* Sets the p loss strategy.
*
* @param pLoss the new p loss strategy
*/
public void setPLossStrategy(PLossStrategy pLoss) {
this.strategyPLoss = pLoss;
}
@Override
public void writeBackToXML(BackWriter bw) {
// no types to write back
}
}
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* PeerfactSim.KOM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network.fairshareng;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import de.tudarmstadt.maki.simonstrator.api.Time;
/**
* The Class SchedulerList: Schedules flows according to their transfer-endtime.
*/
public class SchedulerList {
private static Comparator<? super FairshareFlow> TRANSFERENDTIME_COMPERATOR;
/** The sorted map. */
private final DirectedGraph fullGraph;
/** Recalculation needed: Set to yes once flow gets removed or added. */
private boolean recalculationNeeded = false;
/** The returned flows: Save all returned flows within one Simulator step in here to stop duplicates. */
private final LinkedHashSet<FairshareFlow> returnedFlows = new LinkedHashSet<FairshareFlow>();
/**
* Instantiates a new scheduler list.
* @param fullGraph
*/
public SchedulerList(DirectedGraph fullGraph) {
this.fullGraph = fullGraph;
this.TRANSFERENDTIME_COMPERATOR = new TransferEndTimeComp();
}
/**
* Adds the event.
*
* @param newFlow the fairshare flow
*/
public void addEvent(FairshareFlow newFlow) {
assert (newFlow.getTransferEndTime() >= Time.getCurrentTime()) : "Flow too old: "
+ newFlow.getTransferEndTime()
+ " / "
+ Time.getCurrentTime();
this.recalculationNeeded = true;
}
/**
* Removes the given event/flow.
*
* @param toCancel the to cancel
*/
public void removeEvent(FairshareFlow toCancel) {
this.recalculationNeeded = true;
}
/**
* Do recalculation.
*/
private void doRecalculation() {
assert( this.fullGraph.getAllFlows() instanceof LinkedList );
final LinkedList<FairshareFlow> graphToSort = (LinkedList<FairshareFlow>)this.fullGraph.getAllFlows();
Collections.sort(graphToSort, this.TRANSFERENDTIME_COMPERATOR);
this.recalculationNeeded = false;
this.returnedFlows.clear();
}
/**
* Gets the next arrival.
*
* @return the next arrival
*/
public long getNextArrival() {
if( this.recalculationNeeded == true ) {
doRecalculation();
}
return (this.fullGraph.getAllFlows().size() > 0) ? this.fullGraph.getAllFlows().iterator().next().getTransferEndTime() : Long.MAX_VALUE;
}
/**
* Checks for currently arriving flow.
*
* @return true, if flow is currently arriving.
*/
public boolean hasCurrentlyArrivingFlow() {
if( this.fullGraph.getAllFlows().isEmpty() ) {
return false;
}
/* Return true, if a least one flow is arriving right now (meaning at Simulator.getCurrentTime() ) */
return this.returnedFlows.contains(this.fullGraph.getAllFlows().iterator().next()) ? false : this.getNextArrival() == Time.getCurrentTime();
}
/**
* Gets the and remove currently arriving flow. If multiple flows are arriving, this
* function has to be called multiple times as well.
*
* @return the and remove current arrival
*/
public FairshareFlow getAndRemoveCurrentArrival() {
final LinkedList<FairshareFlow> flowList = (LinkedList<FairshareFlow>) this.fullGraph.getAllFlows();
final FairshareFlow nextArrival = flowList.remove(0);
flowList.addLast(nextArrival);
/* Save last seen to prevent returning flow twice. */
this.returnedFlows.add(nextArrival);
return nextArrival;
}
/**
* The Class TransferEndTimeComp, sort flows by TransferEndTime.
*/
class TransferEndTimeComp implements Comparator<FairshareFlow> {
/* (non-Javadoc)
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
*/
@Override
public int compare(FairshareFlow f1, FairshareFlow f2) {
if (f1.getTransferEndTime() < f2.getTransferEndTime()) {
return -1;
} else if (f1.getTransferEndTime() > f2.getTransferEndTime()) {
return +1;
} else {
if (f1.equals(f2)) {
return 0;
} else {
return (f1.hashCode() > f2.hashCode()) ? +1 : -1;
}
}
}
}
}
/*
* 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.fairshareng.livemon;
import de.tud.kom.p2psim.impl.util.LiveMonitoring;
import de.tud.kom.p2psim.impl.util.LiveMonitoring.ProgressValue;
/**
* The Class FairshareLiveMonitoring.
*/
public class FairshareLiveMonitoring {
/** The current subgraph value. */
private static SubgraphCurrentValue subgraphCurrentValue = new SubgraphCurrentValue();
/** The avg subgraph value. */
private static SubgraphAvgValue subgraphAvgValue = new SubgraphAvgValue();
/**
* Register a new value.
*/
public static void register() {
LiveMonitoring.addProgressValue(subgraphCurrentValue);
LiveMonitoring.addProgressValue(subgraphAvgValue);
}
/**
* Gets the subgraph value.
*
* @return the subgraph value
*/
public static SubgraphCurrentValue getSubgraphValue() {
return subgraphCurrentValue;
}
/**
* Adds the new value.
*
* @param d the d
*/
public static void addNewValue(float d) {
FairshareLiveMonitoring.subgraphCurrentValue.addNewValue(d);
FairshareLiveMonitoring.subgraphAvgValue.addNewValue(d);
}
}
class SubgraphCurrentValue implements ProgressValue {
private float currentValue = 1;
/* (non-Javadoc)
* @see de.tud.kom.p2psim.impl.util.LiveMonitoring.ProgressValue#getName()
*/
@Override
public String getName() {
return "Size of subgraphs (percent)";
}
/**
* Adds the new value, apply low pass filter to smooth peaks.
*
* @param d the d
*/
public void addNewValue(float d) {
final float alpha = 0.9f;
currentValue = alpha * currentValue + (1 - alpha ) * d;
}
/* (non-Javadoc)
* @see de.tud.kom.p2psim.impl.util.LiveMonitoring.ProgressValue#getValue()
*/
@Override
public String getValue() {
return (currentValue * 100) + "%";
}
}
/**
* The Class SubgraphAvgValue.
*/
class SubgraphAvgValue implements ProgressValue {
private float currentValue = 0;
private int currentCount = 0;
/* (non-Javadoc)
* @see de.tud.kom.p2psim.impl.util.LiveMonitoring.ProgressValue#getName()
*/
@Override
public String getName() {
return "Avg size of subgraphs (percent)";
}
/**
* Adds the new value.
*
* @param d the d
*/
public void addNewValue(float d) {
currentValue += d;
currentCount++;
}
/* (non-Javadoc)
* @see de.tud.kom.p2psim.impl.util.LiveMonitoring.ProgressValue#getValue()
*/
@Override
public String getValue() {
return (currentValue / currentCount * 100f) + "%";
}
}
\ 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.gnp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import de.tud.kom.p2psim.api.network.NetLayer;
import de.tud.kom.p2psim.impl.network.AbstractNetLayer;
/**
*
*
* Note: This class contains many inconsistencies. Discovered by simulating
* Gnutella06v2 with 10000 peers. Tried to fix them. Leo Nobach
*
* @author Gerald Klunker
* @version 0.1, 09.01.2008
*
*/
public abstract class AbstractGnpNetBandwidthManager {
public enum BandwidthAllocation {
PERIODICAL, EVENT
}
protected Map<AbstractNetLayer, Map<AbstractNetLayer, GnpNetBandwidthAllocation>> connectionsSenderToReceiver;
protected Map<AbstractNetLayer, Map<AbstractNetLayer, GnpNetBandwidthAllocation>> connectionsReceiverToSender;
public AbstractGnpNetBandwidthManager() {
connectionsSenderToReceiver = new HashMap<AbstractNetLayer, Map<AbstractNetLayer, GnpNetBandwidthAllocation>>();
connectionsReceiverToSender = new HashMap<AbstractNetLayer, Map<AbstractNetLayer, GnpNetBandwidthAllocation>>();
}
public GnpNetBandwidthAllocation addConnection(AbstractNetLayer sender,
AbstractNetLayer receiver, double bandwidth) {
if (!connectionsSenderToReceiver.containsKey(sender))
connectionsSenderToReceiver.put(sender,
new HashMap<AbstractNetLayer, GnpNetBandwidthAllocation>());
if (!connectionsSenderToReceiver.get(sender).containsKey(receiver))
connectionsSenderToReceiver.get(sender).put(receiver,
new GnpNetBandwidthAllocation(sender, receiver));
GnpNetBandwidthAllocation c = connectionsSenderToReceiver.get(sender)
.get(receiver);
if (!connectionsReceiverToSender.containsKey(receiver))
connectionsReceiverToSender.put(receiver,
new HashMap<AbstractNetLayer, GnpNetBandwidthAllocation>());
if (!connectionsReceiverToSender.get(receiver).containsKey(sender))
connectionsReceiverToSender.get(receiver).put(sender, c);
c.setAllocatedBandwidth(0);
sender.getCurrentBandwidth().setUpBW(sender.getMaxBandwidth().getUpBW());
receiver.getCurrentBandwidth().setDownBW(sender.getMaxBandwidth().getDownBW());
c.setBandwidthNeeds(c.getBandwidthNeeds() + bandwidth);
return c;
}
public GnpNetBandwidthAllocation removeConnection(AbstractNetLayer sender,
AbstractNetLayer receiver, double bandwidth) {
GnpNetBandwidthAllocation ba = null;
if (connectionsSenderToReceiver.containsKey(sender)) {
ba = connectionsSenderToReceiver.get(sender).get(receiver);
if (ba != null) { // Disabled a NullPointerException
if (bandwidth < 0)
ba.setBandwidthNeeds(0);
else {
ba.setBandwidthNeeds(ba.getBandwidthNeeds() - bandwidth);
}
if (ba.getBandwidthNeeds() == 0.0) {
connectionsSenderToReceiver.get(sender).remove(receiver);
if (connectionsSenderToReceiver.get(sender).isEmpty())
connectionsSenderToReceiver.remove(sender);
connectionsReceiverToSender.get(receiver).remove(sender);
if (connectionsReceiverToSender.get(receiver).isEmpty())
connectionsReceiverToSender.remove(receiver);
}
ba.setAllocatedBandwidth(0);
}
}
sender.getCurrentBandwidth().setUpBW(sender.getMaxBandwidth().getUpBW());
receiver.getCurrentBandwidth().setDownBW(sender.getMaxBandwidth().getDownBW());
return ba;
}
public Set<GnpNetBandwidthAllocation> removeConnections(
AbstractNetLayer netLayer) {
Set<GnpNetBandwidthAllocation> connections = new HashSet<GnpNetBandwidthAllocation>();
if (connectionsSenderToReceiver.containsKey(netLayer)) {
// Disabled a ConcurrentModificationException
for (AbstractNetLayer receiver : new ArrayList<AbstractNetLayer>(
connectionsSenderToReceiver.get(netLayer).keySet())) {
connections.add(removeConnection(netLayer, receiver, -1));
}
}
if (connectionsReceiverToSender.containsKey(netLayer)) {
// Disabled a ConcurrentModificationException
for (AbstractNetLayer sender : new ArrayList<AbstractNetLayer>(
connectionsReceiverToSender.get(netLayer).keySet())) {
connections.add(removeConnection(sender, netLayer, -1));
}
}
return connections;
}
public GnpNetBandwidthAllocation getBandwidthAllocation(NetLayer sender,
NetLayer receiver) {
if (connectionsSenderToReceiver.get(sender) == null)
return null; // Disabled a NullPointerException
else
return connectionsSenderToReceiver.get(sender).get(receiver);
}
public abstract void allocateBandwidth();
public abstract BandwidthAllocation getBandwidthAllocationType();
public abstract Set<GnpNetBandwidthAllocation> getChangedAllocations();
}
/*
* 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;
import java.io.FileInputStream;
import java.io.IOException;
/**
* Represents the header of a bitmap.
*
* @author Andr� Mink, Sebastian Kaune
*/
public class BitmapHeader {
public int nsize; // Size of file
public int nbisize; // Size of bitmapinfoheader
public int nwidth; // image width
public int nheight; // image height
public int nplanes; // # of planes
public int nbitcount; // bitcount
public int ncompression; // compression method
public int nsizeimage; // image size
public int nxpm; // pixels per meter (x axis)
public int nypm; // pixels per meter (y axis)
public int nclrused; // # used colors
public int nclrimp; // # important colors
public BitmapHeader() {
}
public void read(FileInputStream fs) throws IOException {
final int bflen = 14; // 14 byte BITMAPFILEHEADER
byte bf[] = new byte[bflen];
fs.read(bf, 0, bflen);
final int bilen = 40; // 40-byte BITMAPINFOHEADER
byte bi[] = new byte[bilen];
fs.read(bi, 0, bilen);
nsize = getInt(bf, 2);
nbisize = getInt(bi, 2);
nwidth = getInt(bi, 4);
nheight = getInt(bi, 8);
nplanes = getShort(bi, 12);
nbitcount = getShort(bi, 14);
ncompression = getInt(bi, 16);
nsizeimage = getInt(bi, 20);
nxpm = getInt(bi, 24);
nypm = getInt(bi, 28);
nclrused = getInt(bi, 32);
nclrimp = getInt(bi, 36);
}
public int getInt(byte[] in, int offset) {
int ret = ((int) in[offset + 3] & 0xff);
ret = (ret << 8) | ((int) in[offset + 2] & 0xff);
ret = (ret << 8) | ((int) in[offset + 1] & 0xff);
ret = (ret << 8) | ((int) in[offset + 0] & 0xff);
return (ret);
}
// build an int from a byte array - convert little to big endian
public int getInt3(byte[] in, int offset) {
int ret = 0xff;
ret = (ret << 8) | ((int) in[offset + 2] & 0xff);
ret = (ret << 8) | ((int) in[offset + 1] & 0xff);
ret = (ret << 8) | ((int) in[offset + 0] & 0xff);
return (ret);
}
// build an int from a byte array - convert little to big endian
public long getLong(byte[] in, int offset) {
long ret = ((long) in[offset + 7] & 0xff);
ret |= (ret << 8) | ((long) in[offset + 6] & 0xff);
ret |= (ret << 8) | ((long) in[offset + 5] & 0xff);
ret |= (ret << 8) | ((long) in[offset + 4] & 0xff);
ret |= (ret << 8) | ((long) in[offset + 3] & 0xff);
ret |= (ret << 8) | ((long) in[offset + 2] & 0xff);
ret |= (ret << 8) | ((long) in[offset + 1] & 0xff);
ret |= (ret << 8) | ((long) in[offset + 0] & 0xff);
return (ret);
}
// build an double from a byte array - convert little to big endian
public double getDouble(byte[] in, int offset) {
long ret = getLong(in, offset);
return (Double.longBitsToDouble(ret));
}
// build an short from a byte array - convert little to big endian
public static short getShort(byte[] in, int offset) {
short ret = (short) ((short) in[offset + 1] & 0xff);
ret = (short) ((ret << 8) | (short) ((short) in[offset + 0] & 0xff));
return (ret);
}
}
/*
* 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;
import java.awt.Color;
import java.awt.Point;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
/**
* Reads a bitmap byte by byte into a 2-dimensional array and extracts the
* colorTable of the bitmap. Currently, there are only 8bit bitmaps (256 colors)
* supported.
*
* @author Andr� Mink, Sebastian Kaune
*/
public class BitmapLoader {
public int[][] cartesianSpace;
public Color[] colorTable;
public int width;
public int height;
public BitmapLoader(String image) {
try {
FileInputStream in = new FileInputStream(image);
read(in);
this.width = cartesianSpace.length;
this.height = cartesianSpace[0].length;
String lastColor = "";
for (int i = 0; i < colorTable.length; i++) {
if (!lastColor.equals(colorTable[i].toString())) {
lastColor = colorTable[i].toString();
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
public double[][] getDistributionFromBitmap() {
Color c;
double sum = 0;
double tmp;
double[][] distribution = new double[this.width][this.height];
// iterate ever pixel
for (int width = 0; width < this.width; width++) {
for (int height = 0; height < this.height; height++) {
// get the color for this pixel and calculate the ratio for this
// pixel accoring to its grey value
c = this.colorTable[this.cartesianSpace[width][height]];
// use only grey colors
if (c.getBlue() == c.getGreen() && c.getBlue() == c.getRed()) {
tmp = 1.0 - (c.getBlue() / 255.0);
distribution[width][height] = tmp;
sum += tmp;
} else
distribution[width][height] = 0;
}
}
// iterate ever pixel again and calculate the overall ratio
for (int width = 0; width < this.width; width++) {
for (int height = 0; height < this.height; height++) {
distribution[width][height] = distribution[width][height] / sum;
}
}
return distribution;
}
public ArrayList assignPeers(int nbPeers, double[][] distribution) {
ArrayList al = new ArrayList(nbPeers);
int sum = 0;
int value = 0;
double deviation = 0;
int[][] result = new int[this.width][this.height];
for (int width = 0; width < this.width; width++) {
for (int height = 0; height < this.height; height++) {
if (deviation > 0)
value = (int) Math.ceil(distribution[width][height]
* nbPeers);
else if (deviation <= 0)
value = (int) Math.floor(distribution[width][height]
* nbPeers);
sum += value;
deviation += (distribution[width][height] * nbPeers) - value;
result[width][height] = value;
if (value > 0) {
for (int i = 0; i < value; i++) {
al.add(new Point(width, height));
}
}
}
}
return al;
}
public void read(FileInputStream fs) {
try {
BitmapHeader bh = new BitmapHeader();
bh.read(fs);
if (bh.nbitcount == 24)
this.cartesianSpace = read24BitMap(fs, bh);
else if (bh.nbitcount == 32)
this.cartesianSpace = read32BitMap(fs, bh);
else if (bh.nbitcount == 8)
this.cartesianSpace = read8BitMap(fs, bh);
fs.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
private int[][] read8BitMap(FileInputStream fs, BitmapHeader bh)
throws IOException {
// get the number of colors
int nNumColors = 0;
// # colors is in bitmap header
if (bh.nclrused > 0) {
nNumColors = bh.nclrused;
}
// calculate colors based on bitsperpixel
else {
nNumColors = (1 & 0xff) << bh.nbitcount;
}
// some images have no imagesize in the bitmap header => calculate
if (bh.nsizeimage == 0) {
bh.nsizeimage = ((((bh.nwidth * bh.nbitcount) + 31) & ~31) >> 3);
bh.nsizeimage *= bh.nheight;
}
// get the color table
Color colorTable[] = new Color[nNumColors];
byte byteColorTable[] = new byte[nNumColors * 4];
fs.read(byteColorTable, 0, nNumColors * 4);
int colorTableIndex = 0;
Color c;
// Field1 = Blue, Field2 = Green, Field3 = Red, Field4 = reserved
for (int n = 0; n < byteColorTable.length; n = n + 4) {
c = new Color(byteColorTable[n + 2] & 0xff,
byteColorTable[n + 1] & 0xff, byteColorTable[n] & 0xff);
colorTable[colorTableIndex] = c;
colorTableIndex++;
}
// Read the image data.
// calculate the padding for each line
int npad = (bh.nsizeimage / bh.nheight) - bh.nwidth;
// cartesianSpace stores the pointers to the colorTable
int[][] cartesianSpace = new int[bh.nwidth][bh.nheight];
byte bdata[] = new byte[(bh.nwidth + npad) * bh.nheight];
fs.read(bdata, 0, (bh.nwidth + npad) * bh.nheight);
int nindex = 0;
for (int j = 0; j < bh.nheight; j++) {
for (int i = 0; i < bh.nwidth; i++) {
cartesianSpace[i][j] = bdata[nindex] & 0xff;
nindex++;
}
nindex += npad;
}
this.colorTable = colorTable;
return cartesianSpace;
}
private int[][] read24BitMap(FileInputStream fs, BitmapHeader bh)
throws IOException {
// not supported yet
return new int[0][0];
}
private int[][] read32BitMap(FileInputStream fs, BitmapHeader bh)
throws IOException {
// not supported yet
return new int[0][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;
public class GeoLocation {
private String countryCode;
private String region;
private String city;
private String isp;
private String continentalArea;
private double latitude;
private double longitude;
public GeoLocation(String conArea, String countryCode, String region,
String city, String isp, double latitude, double longitude) {
super();
this.continentalArea = conArea;
this.countryCode = countryCode;
this.region = region;
this.city = city;
this.isp = isp;
this.latitude = latitude;
this.longitude = longitude;
}
public String getContinentalArea() {
return continentalArea;
}
public String getCountryCode() {
return countryCode;
}
public String getRegion() {
return region;
}
public String getCity() {
return city;
}
public String getIsp() {
return isp;
}
public double getLatitude() {
return latitude;
}
public double getLongitude() {
return longitude;
}
}
/*
* 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;
import de.tud.kom.p2psim.api.network.NetLayer;
import de.tudarmstadt.maki.simonstrator.api.Time;
import de.tudarmstadt.maki.simonstrator.api.component.network.NetID;
public class GeoLocationOracle {
private static GnpSubnet subnet;
private static GnpLatencyModel lm;
GeoLocationOracle(GnpSubnet subnet) {
this.subnet = subnet;
}
void setLatencyModel(GnpLatencyModel lm) {
this.lm = lm;
}
/**
* This method determines the priority level of the specified remote host by
* considering the geographical(-regional) underlay awareness between this
* host and the specified local host.
*
* The priority level is calculated as follows. Both hosts are located in
* the same: - city => Priority 4 - region => Priority 3 - country =>
* Priority 2 - "continental" region => Priority 1 - world/untraceable =>
* Priority 0
*
* @param local
* IP-address of the local host
* @param remote
* IP-address of the remote host
* @return the priority level
*/
public static int getGeoPriority(NetID local, NetID remote) {
GeoLocation localGeo = subnet.getNetLayer(local).getGeoLocation();
GeoLocation remoteGeo = subnet.getNetLayer(remote).getGeoLocation();
if (!remoteGeo.getCity().equals("--")
&& localGeo.getCity().equals(remoteGeo.getCity()))
return 4;
else if (!remoteGeo.getRegion().equals("--")
&& localGeo.getRegion().equals(remoteGeo.getRegion()))
return 3;
else if (!remoteGeo.getCountryCode().equals("--")
&& localGeo.getCountryCode().equals(remoteGeo.getCountryCode()))
return 2;
else if (!remoteGeo.getContinentalArea().equals("--")
&& localGeo.getContinentalArea().equals(
remoteGeo.getContinentalArea()))
return 1;
else
return 0;
}
/**
* Normally, the propagation of messages through channels and routers of the
* Internet is affected by the propagation delays (of the physical media),
* and the processing-, queuing-, and transmission delays of the routers.
* The so called Internet propagation delay is modeled as the sum of a fixed
* part that combines the aforementioned router and propagation delays, and
* a variable part to reproduce the jitter.
*
* Invoking this method returns the Internet propagation delay (in ms)
* between two hosts in the Internet. Note that this delay is derived from
* measurement data, and it therefore estimates the one-way delay of the
* measured round-trip-times between the specified hosts.
*
* @param local
* IP-address of the local host
* @param remote
* IP-address of the remote host
* @return the Internet propagation delay in ms
*/
public static double getInternetPropagationDelay(NetID local, NetID remote) {
NetLayer localNet = subnet.getNetLayer(local);
NetLayer remoteNet = subnet.getNetLayer(remote);
return lm.getPropagationDelay((GnpNetLayer) localNet,
(GnpNetLayer) remoteNet) / (double) Time.MILLISECOND;
}
/**
* Calculates the distance in kilometers (km) from one host to another,
* using the Haversine formula. The squashed shape of the earth into account
* (approximately)
*
* @param local
* IP-address of the local host
* @param remote
* IP-address of the remote host
* @return the distance between the specified hosts in km
*
*/
public static double getGeographicalDistance(NetID local, NetID remote) {
GeoLocation localGeo = subnet.getNetLayer(local).getGeoLocation();
GeoLocation remoteGeo = subnet.getNetLayer(remote).getGeoLocation();
double lat1 = HaversineHelpers.radians(localGeo.getLatitude());
double lat2 = HaversineHelpers.radians(remoteGeo.getLatitude());
double dlat = lat2 - lat1;
double dlong = HaversineHelpers.radians(remoteGeo.getLongitude())
- HaversineHelpers.radians(localGeo.getLongitude());
double a = HaversineHelpers.square(Math.sin(dlat / 2)) + Math.cos(lat1)
* Math.cos(lat2) * HaversineHelpers.square(Math.sin(dlong / 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) / 1000d;
}
}
/*
* 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;
import java.awt.geom.Point2D;
import java.util.HashSet;
import java.util.Set;
import org.apache.log4j.Logger;
import de.tud.kom.p2psim.api.common.SimHost;
import de.tud.kom.p2psim.api.network.BandwidthImpl;
import de.tud.kom.p2psim.impl.network.IPv4NetID;
import de.tud.kom.p2psim.impl.network.gnp.topology.GnpPosition;
import de.tud.kom.p2psim.impl.util.logging.SimLogger;
import de.tudarmstadt.maki.simonstrator.api.Host;
import de.tudarmstadt.maki.simonstrator.api.Time;
import de.tudarmstadt.maki.simonstrator.api.component.HostComponentFactory;
public class GnpBitmapNetLayerFactory implements HostComponentFactory {
private static Logger log = SimLogger.getLogger(GnpBitmapNetLayerFactory.class);
private final GnpSubnet subnet;
private final static long DEFAULT_DOWN_BANDWIDTH = 1000l;
private final static long DEFAULT_UP_BANDWIDTH = 1000l;
private long downBandwidth;
private long upBandwidth;
private int experimentSize = 0;
private PeerDistributionFromBitmap peerDistribution;
private Long idCounter = 0l;
private Set<Long> usedIds = new HashSet<Long>();
public GnpBitmapNetLayerFactory() {
subnet = new GnpSubnet();
this.downBandwidth = DEFAULT_DOWN_BANDWIDTH;
this.upBandwidth = DEFAULT_UP_BANDWIDTH;
}
public GnpNetLayer createComponent(Host pureHost) {
SimHost host = (SimHost) pureHost;
GnpNetLayer netLayer = newNetLayer(host, host.getProperties()
.getGroupID());
return netLayer;
}
/**
* random node form group
*
* @param id
* @return
*/
public GnpNetLayer newNetLayer(SimHost host, String id) {
IPv4NetID netId = createNewID();
return newNetLayer(host, netId);
}
/**
* Create new GnpNetLayer based on the distribution from the bitmap
*
* @param netID
* @return
*/
private GnpNetLayer newNetLayer(SimHost host, IPv4NetID netID) {
// Get next position from peer distribution
Point2D.Double p = peerDistribution.getNextPeerLocation();
// Create an instance of GnpPosition
double[] coordinates = {p.x, p.y};
GnpPosition gnpPos = new GnpPosition(coordinates);
// Create stub GeoLocation
GeoLocation geoLoc = new GeoLocation("","","","","",0,0);
// Create the NetLayer
GnpNetLayer nw = new GnpNetLayer(host, this.subnet, netID, gnpPos,
geoLoc, new BandwidthImpl(this.downBandwidth, this.upBandwidth));
return nw;
}
public void setDownBandwidth(long downBandwidth) {
this.downBandwidth = downBandwidth;
}
public void setUpBandwidth(long upBandwidth) {
this.upBandwidth = upBandwidth;
}
public void setLatencyModel(GnpLatencyModel model) {
subnet.setLatencyModel(model);
}
public void setBandwidthManager(AbstractGnpNetBandwidthManager bm) {
subnet.setBandwidthManager(bm);
}
public void setPbaPeriod(double seconds) {
subnet.setPbaPeriod(Math.round(seconds * Time.SECOND));
}
public void setExperimentSize(int size) {
this.experimentSize = size;
}
/**
* Setup PeerDistributionFromBitmap with image from given path
*
* @param path
*/
public void setBitmapPath(String path) {
this.peerDistribution = new PeerDistributionFromBitmap();
/* Initialize the peer distribution with the path of the bitmap and
* the number of peers.
*/
peerDistribution.initialize(path, this.experimentSize);
}
private class GnpHostInfo {
private GnpPosition gnpPosition;
private GeoLocation geoLoc;
public GnpHostInfo(GeoLocation geoLoc, GnpPosition gnpPos) {
this.gnpPosition = gnpPos;
this.geoLoc = geoLoc;
}
}
/**
* @return a new NetID
*/
private IPv4NetID createNewID() {
while (usedIds.contains(idCounter))
idCounter++;
IPv4NetID nextId = new IPv4NetID(idCounter);
usedIds.add(idCounter++);
return nextId;
}
}
/*
* 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;
import java.util.Random;
import org.apache.log4j.Logger;
import umontreal.iro.lecuyer.probdist.LognormalDist;
import de.tud.kom.p2psim.api.common.Position;
import de.tud.kom.p2psim.api.linklayer.mac.PhyType;
import de.tud.kom.p2psim.api.network.NetLatencyModel;
import de.tud.kom.p2psim.api.network.NetLayer;
import de.tud.kom.p2psim.api.network.NetProtocol;
import de.tud.kom.p2psim.api.transport.TransProtocol;
import de.tud.kom.p2psim.impl.network.IPv4Message;
import de.tud.kom.p2psim.impl.network.gnp.topology.CountryLookup;
import de.tud.kom.p2psim.impl.network.gnp.topology.PingErLookup;
import de.tud.kom.p2psim.impl.util.logging.SimLogger;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.Time;
public class GnpLatencyModel implements NetLatencyModel {
private static Logger log = SimLogger.getLogger(GnpLatencyModel.class);
private Random rnd = Randoms.getRandom(GnpLatencyModel.class);
public static final int MSS = PhyType.ETHERNET.getDefaultMTU()
- NetProtocol.IPv4.getHeaderSize()
- TransProtocol.TCP.getHeaderSize();
private static PingErLookup pingErLookup;
private static CountryLookup countryLookup;
private boolean usePingErInsteadOfGnp = false;
private boolean useAnalyticalFunctionInsteadOfGnp = false;
private boolean usePingErJitter = false;
private boolean usePingErPacketLoss = false;
public void init(PingErLookup pingErLookup, CountryLookup countryLookup) {
GnpLatencyModel.pingErLookup = pingErLookup;
GnpLatencyModel.countryLookup = countryLookup;
}
private double getMinimumRTT(GnpNetLayer sender, GnpNetLayer receiver) {
String ccSender = sender.getCountryCode();
String ccReceiver = receiver.getCountryCode();
double minRtt = 0.0;
if (usePingErInsteadOfGnp) {
minRtt = pingErLookup.getMinimumRtt(ccSender, ccReceiver, countryLookup);
} else if (useAnalyticalFunctionInsteadOfGnp) {
double distance = GeoLocationOracle.getGeographicalDistance(sender.getNetID(), receiver.getNetID());
minRtt = 62 + (0.02 * distance);
} else {
Position senderPos = sender.getNetPosition();
Position receiverPos = receiver.getNetPosition();
minRtt = senderPos.getDistance(receiverPos);
}
log.info("Minimum RTT for " + ccSender + " to " + ccReceiver + ": " + minRtt + " ms");
return minRtt;
}
private double getPacketLossProbability(GnpNetLayer sender, GnpNetLayer receiver) {
String ccSender = sender.getCountryCode();
String ccReceiver = receiver.getCountryCode();
double twoWayLossRate = 0.0;
double oneWayLossRate = 0.0;
if (usePingErPacketLoss) {
twoWayLossRate = pingErLookup.getPacktLossRate(ccSender, ccReceiver, countryLookup);
twoWayLossRate /= 100;
oneWayLossRate = 1 - Math.sqrt(1 - twoWayLossRate);
}
log.debug("Packet Loss Probability for " + ccSender + " to " + ccReceiver + ": " + (oneWayLossRate * 100) + " %");
return oneWayLossRate;
}
private double getNextJitter(GnpNetLayer sender, GnpNetLayer receiver) {
String ccSender = sender.getCountryCode();
String ccReceiver = receiver.getCountryCode();
double randomJitter = 0.0;
if (usePingErJitter) {
LognormalDist distri = pingErLookup.getJitterDistribution(ccSender, ccReceiver, countryLookup);
randomJitter = distri.inverseF(rnd.nextDouble());
}
log.debug("Random Jitter for " + ccSender + " to " + ccReceiver + ": " + randomJitter + " ms");
return randomJitter;
}
private double getAverageJitter(GnpNetLayer sender, GnpNetLayer receiver) {
String ccSender = sender.getCountryCode();
String ccReceiver = receiver.getCountryCode();
double jitter = 0.0;
if (usePingErJitter) {
jitter = pingErLookup.getAverageRtt(ccSender, ccReceiver, countryLookup) - pingErLookup.getMinimumRtt(ccSender, ccReceiver, countryLookup);
}
log.debug("Average Jitter for " + ccSender + " to " + ccReceiver + ": " + jitter + " ms");
return jitter;
}
public double getUDPerrorProbability(GnpNetLayer sender, GnpNetLayer receiver, IPv4Message msg) {
if (msg.getPayload().getSize() > 65507)
throw new IllegalArgumentException("Message-Size ist too big for a UDP-Datagramm (max 65507 byte)");
double lp = getPacketLossProbability(sender, receiver);
double errorProb = 1 - Math.pow(1 - lp, msg.getNoOfFragments());
log.debug("Error Probability for a " + msg.getPayload().getSize() + " byte UDP Datagram from " + sender.getCountryCode() + " to " + receiver.getCountryCode() + ": " + errorProb * 100 + " %");
return errorProb;
}
public double getTcpThroughput(GnpNetLayer sender, GnpNetLayer receiver) {
double minRtt = getMinimumRTT(sender, receiver);
double averageJitter = getAverageJitter(sender, receiver);
double packetLossRate = getPacketLossProbability(sender, receiver);
double mathisBW = ((MSS * 1000) / (minRtt + averageJitter)) * Math.sqrt(1.5 / packetLossRate);
return mathisBW;
}
public long getTransmissionDelay(double bytes, double bandwidth) {
double messageTime = bytes / bandwidth;
long delay = Math.round((messageTime * Time.SECOND));
log.debug("Transmission Delay (s): " + messageTime + " ( " + bytes + " bytes / " + bandwidth + " bytes/s )");
return delay;
}
public long getPropagationDelay(GnpNetLayer sender, GnpNetLayer receiver) {
double minRtt = getMinimumRTT(sender, receiver);
double randomJitter = getNextJitter(sender, receiver);
double receiveTime = (minRtt + randomJitter) / 2.0;
long latency = Math.round(receiveTime * Time.MILLISECOND);
log.debug("Propagation Delay for " + sender.getCountryCode() + " to " + receiver.getCountryCode() + ": " + receiveTime + " ms");
return latency;
}
public long getLatency(NetLayer sender, NetLayer receiver) {
return getPropagationDelay((GnpNetLayer) sender, (GnpNetLayer) receiver);
}
public void setUsePingErRttData(boolean pingErRtt) {
usePingErInsteadOfGnp = pingErRtt;
}
public void setUseAnalyticalRtt(boolean analyticalRtt) {
useAnalyticalFunctionInsteadOfGnp = analyticalRtt;
}
public void setUsePingErJitter(boolean pingErRtt) {
usePingErJitter = pingErRtt;
}
public void setUsePingErPacketLoss(boolean pingErPacketLoss) {
usePingErPacketLoss = pingErPacketLoss;
}
}
\ 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.gnp;
import de.tud.kom.p2psim.impl.network.AbstractNetLayer;
/**
*
* @author Gerald Klunker
* @version 0.01, 07/12/12
*/
public class GnpNetBandwidthAllocation {
private double allocatedBandwidth = 0.0;
private double bandwidthNeeds = 0.0;
private AbstractNetLayer receiver;
private AbstractNetLayer sender;
private double bidSender[] = new double[2];
private double bidReciever[] = new double[2];
private boolean minBidSender = false;
private boolean minBidReceiver = false;
public GnpNetBandwidthAllocation(AbstractNetLayer sender,
AbstractNetLayer receiver) {
this.sender = sender;
this.receiver = receiver;
bidSender[0] = 0;
bidSender[1] = 0;
bidReciever[0] = 0;
bidReciever[1] = 0;
}
public double getAllocatedBandwidth() {
return allocatedBandwidth;
}
public void setAllocatedBandwidth(double allocatedBandwidth) {
this.allocatedBandwidth = allocatedBandwidth;
}
public double getBandwidthNeeds() {
return bandwidthNeeds;
}
public void setBandwidthNeeds(double bandwidthNeeds) {
this.bandwidthNeeds = bandwidthNeeds;
}
public AbstractNetLayer getReceiver() {
return receiver;
}
public AbstractNetLayer getSender() {
return sender;
}
/*
* Eventbased Allocation only
*/
public void initConnection() {
bidSender[0] = 0;
bidSender[1] = 0;
bidReciever[0] = 0;
bidReciever[1] = 0;
minBidSender = false;
minBidReceiver = false;
sender.getCurrentBandwidth().setUpBW(sender.getMaxBandwidth().getUpBW());
receiver.getCurrentBandwidth().setDownBW(sender.getMaxBandwidth().getDownBW());
}
public void setBid(double bid, boolean isMinimal, boolean sender, long step) {
if (sender) {
int posC = (int) (step % 2);
bidSender[posC] = bid;
minBidSender = isMinimal;
} else {
int posC = (int) (step % 2);
bidReciever[posC] = bid;
minBidReceiver = isMinimal;
}
}
public double getCurrentBid(boolean sender, long step) {
if (sender) {
return bidSender[(int) (step % 2)];
} else {
return bidReciever[(int) (step % 2)];
}
}
public double getPreviousBid(boolean sender, long step) {
if (sender) {
return bidSender[(int) ((step + 1) % 2)];
} else {
return bidReciever[(int) ((step + 1) % 2)];
}
}
public boolean isBidRepeated(boolean sender) {
if (sender) {
return Math.abs(bidSender[0] - bidSender[1]) <= 0.0001;
} else {
return Math.abs(bidReciever[0] - bidReciever[1]) <= 0.0001;
}
}
public boolean isMinBid(boolean sender) {
if (sender) {
return minBidSender;
} else {
return minBidReceiver;
}
}
}
\ No newline at end of file
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