Author: mrogers
Date: 2006-07-13 11:39:14 +0000 (Thu, 13 Jul 2006)
New Revision: 9590
Added:
trunk/freenet/src/load-balancing-sims/
trunk/freenet/src/load-balancing-sims/phase1/
trunk/freenet/src/load-balancing-sims/phase1/Event.java
trunk/freenet/src/load-balancing-sims/phase1/EventTarget.java
trunk/freenet/src/load-balancing-sims/phase1/Network.java
trunk/freenet/src/load-balancing-sims/phase1/NetworkInterface.java
trunk/freenet/src/load-balancing-sims/phase1/Node.java
trunk/freenet/src/load-balancing-sims/phase1/Packet.java
trunk/freenet/src/load-balancing-sims/phase1/Peer.java
trunk/freenet/src/load-balancing-sims/phase1/Sim.java
trunk/freenet/src/load-balancing-sims/phase2/
trunk/freenet/src/load-balancing-sims/phase2/Event.java
trunk/freenet/src/load-balancing-sims/phase2/EventTarget.java
trunk/freenet/src/load-balancing-sims/phase2/Network.java
trunk/freenet/src/load-balancing-sims/phase2/NetworkInterface.java
trunk/freenet/src/load-balancing-sims/phase2/Node.java
trunk/freenet/src/load-balancing-sims/phase2/Packet.java
trunk/freenet/src/load-balancing-sims/phase2/Peer.java
trunk/freenet/src/load-balancing-sims/phase2/Sim.java
trunk/freenet/src/load-balancing-sims/phase4/
trunk/freenet/src/load-balancing-sims/phase4/Event.java
trunk/freenet/src/load-balancing-sims/phase4/EventTarget.java
trunk/freenet/src/load-balancing-sims/phase4/Network.java
trunk/freenet/src/load-balancing-sims/phase4/NetworkInterface.java
trunk/freenet/src/load-balancing-sims/phase4/Node.java
trunk/freenet/src/load-balancing-sims/phase4/Packet.java
trunk/freenet/src/load-balancing-sims/phase4/Peer.java
trunk/freenet/src/load-balancing-sims/phase4/Sim.java
Log:
Added load balancing sims to repository
Added: trunk/freenet/src/load-balancing-sims/phase1/Event.java
===================================================================
--- trunk/freenet/src/load-balancing-sims/phase1/Event.java 2006-07-13
08:26:47 UTC (rev 9589)
+++ trunk/freenet/src/load-balancing-sims/phase1/Event.java 2006-07-13
11:39:14 UTC (rev 9590)
@@ -0,0 +1,92 @@
+import java.util.TreeSet; // Gotta love the collections framework...
+
+class Event implements Comparable
+{
+ // Static variables and methods for the event queue
+
+ private static TreeSet<Event> queue = new TreeSet<Event>();
+ private static double clockTime = 0.0;
+ private static int nextId = 0;
+ public static double duration = 0.0;
+
+ public static void reset()
+ {
+ queue.clear();
+ clockTime = 0.0;
+ nextId = 0;
+ duration = 0.0;
+ }
+
+ public static void schedule (EventTarget target, double time,
+ int type, Object data)
+ {
+ queue.add (new Event (target, time + clockTime, type, data));
+ }
+
+ public static boolean nextEvent()
+ {
+ try {
+ Event e = queue.first();
+ queue.remove (e);
+ // Update the clock
+ clockTime = e.time;
+ // Quit if the simulation's alloted time has run out
+ if (clockTime > duration) return false;
+ // Pass the packet to the target's callback method
+ e.target.handleEvent (e.type, e.data);
+ return true;
+ }
+ catch (java.util.NoSuchElementException x) {
+ // No more events to dispatch
+ return false;
+ }
+ }
+
+ public static double time()
+ {
+ return clockTime;
+ }
+
+ public static void log (String message)
+ {
+ System.out.print (clockTime + ": " + message + "\n");
+ }
+
+ // Non-static variables and methods for individual events
+
+ private EventTarget target;
+ private double time;
+ private int id;
+ private int type;
+ private Object data;
+
+ public Event (EventTarget target, double time, int type, Object data)
+ {
+ this.target = target;
+ this.time = time;
+ this.type = type;
+ this.data = data;
+ id = nextId++;
+ }
+
+ // Must be consistent with compareTo()
+ public boolean equals (Object o)
+ {
+ Event e = (Event) o;
+ if (e.time == time && e.id == id) return true;
+ return false;
+ }
+
+ // Must be consistent with equals()
+ public int compareTo (Object o)
+ {
+ Event e = (Event) o;
+ // Sort events by time (order of occurrence)
+ if (e.time > time) return -1;
+ if (e.time < time) return 1;
+ // Break ties by ID (order of scheduling)
+ if (e.id > id) return -1;
+ if (e.id < id) return 1;
+ return 0;
+ }
+}
Added: trunk/freenet/src/load-balancing-sims/phase1/EventTarget.java
===================================================================
--- trunk/freenet/src/load-balancing-sims/phase1/EventTarget.java
2006-07-13 08:26:47 UTC (rev 9589)
+++ trunk/freenet/src/load-balancing-sims/phase1/EventTarget.java
2006-07-13 11:39:14 UTC (rev 9590)
@@ -0,0 +1,4 @@
+interface EventTarget
+{
+ public void handleEvent (int type, Object data);
+}
Added: trunk/freenet/src/load-balancing-sims/phase1/Network.java
===================================================================
--- trunk/freenet/src/load-balancing-sims/phase1/Network.java 2006-07-13
08:26:47 UTC (rev 9589)
+++ trunk/freenet/src/load-balancing-sims/phase1/Network.java 2006-07-13
11:39:14 UTC (rev 9590)
@@ -0,0 +1,29 @@
+import java.util.HashMap;
+
+class Network
+{
+ private static HashMap<Integer,NetworkInterface> interfaces
+ = new HashMap<Integer,NetworkInterface>();
+ private static int nextAddress = 0;
+ // Can packets arrive out of order?
+ public static boolean reorder = false;
+
+ // Deliver a packet to an endpoint
+ public static void deliver (Packet p)
+ {
+ NetworkInterface ni = interfaces.get (p.destination);
+ if (ni == null) return; // Node doesn't exist or is offline
+ // If the network allows reordering, randomise the latency a bit
+ if (reorder) p.latency *= Math.random() * 0.2 + 0.9;
+ // Schedule the arrival of the packet at the destination
+ Event.schedule (ni, p.latency, NetworkInterface.RX_Q_ADD, p);
+ }
+
+ // Attach an interface to the network - returns the address
+ public static int register (NetworkInterface ni)
+ {
+ int address = nextAddress++;
+ interfaces.put (address, ni);
+ return address;
+ }
+}
Added: trunk/freenet/src/load-balancing-sims/phase1/NetworkInterface.java
===================================================================
--- trunk/freenet/src/load-balancing-sims/phase1/NetworkInterface.java
2006-07-13 08:26:47 UTC (rev 9589)
+++ trunk/freenet/src/load-balancing-sims/phase1/NetworkInterface.java
2006-07-13 11:39:14 UTC (rev 9590)
@@ -0,0 +1,28 @@
+class NetworkInterface implements EventTarget
+{
+ public int address; // Represents an IP address and port
+ private Node owner; // The owner of this network interface
+
+ public NetworkInterface (Node owner)
+ {
+ this.owner = owner;
+ // Attach the interface to the network
+ address = Network.register (this);
+ }
+
+ // Called by Peer
+ public void send (Packet p)
+ {
+ p.source = address;
+ Network.deliver (p);
+ }
+
+ // EventTarget interface
+ public void handleEvent (int type, Object data)
+ {
+ if (type == RX_Q_ADD) owner.handlePacket ((Packet) data);
+ }
+
+ // Each EventTarget class has its own event codes
+ public final static int RX_Q_ADD = 1;
+}
Added: trunk/freenet/src/load-balancing-sims/phase1/Node.java
===================================================================
--- trunk/freenet/src/load-balancing-sims/phase1/Node.java 2006-07-13
08:26:47 UTC (rev 9589)
+++ trunk/freenet/src/load-balancing-sims/phase1/Node.java 2006-07-13
11:39:14 UTC (rev 9590)
@@ -0,0 +1,64 @@
+import java.util.HashMap;
+import java.util.ArrayList;
+
+class Node implements EventTarget
+{
+ private HashMap<Integer,Peer> peers; // Look up a peer by its address
+ private NetworkInterface net;
+ public int sent, received;
+
+ public Node()
+ {
+ peers = new HashMap<Integer,Peer>();
+ net = new NetworkInterface (this);
+ sent = received = 0;
+ }
+
+ public void connect (Node n, double latency)
+ {
+ Peer p = new Peer (n.net.address, latency, net);
+ peers.put (n.net.address, p);
+ }
+
+ // Called by NetworkInterface
+ public void handlePacket (Packet p)
+ {
+ if (p.type == Packet.PING) {
+ Event.log (this + " received ping " + p.seq);
+ Peer source = peers.get (p.source);
+ source.sendPacket (new Packet (Packet.PONG, p.seq));
+ Event.log (this + " sent pong " + p.seq);
+ }
+ else if (p.type == Packet.PONG) {
+ Event.log (this + " received pong " + p.seq);
+ received++;
+ }
+ }
+
+ // Event callback
+ private void generatePing()
+ {
+ // Choose a random peer
+ int randomIndex = (int) (Math.random() * peers.size());
+ ArrayList<Peer> a = new ArrayList<Peer> (peers.values());
+ Peer randomPeer = a.get (randomIndex);
+
+ // Each ping/pong pair is identified by a random nonce
+ int seq = (int) (Math.random() * 1000000);
+ randomPeer.sendPacket (new Packet (Packet.PING, seq));
+ Event.log (this + " sent ping " + seq);
+ sent++;
+
+ // Schedule another ping after a random delay
+ Event.schedule (this, Math.random(), GENERATE_PING, null);
+ }
+
+ // EventTarget interface
+ public void handleEvent (int type, Object data)
+ {
+ if (type == GENERATE_PING) generatePing();
+ }
+
+ // Each EventTarget class has its own event codes
+ public final static int GENERATE_PING = 1;
+}
Added: trunk/freenet/src/load-balancing-sims/phase1/Packet.java
===================================================================
--- trunk/freenet/src/load-balancing-sims/phase1/Packet.java 2006-07-13
08:26:47 UTC (rev 9589)
+++ trunk/freenet/src/load-balancing-sims/phase1/Packet.java 2006-07-13
11:39:14 UTC (rev 9590)
@@ -0,0 +1,17 @@
+class Packet
+{
+ // Packet types
+ public final static int PING = 1, PONG = 2;
+
+ public int source, destination; // Network addresses
+ public int type; // Ping, pong, etc
+ public int seq; // Sequence number (actually just a nonce at the moment)
+ public double latency; // Stored here for convenience
+
+ public Packet (int type, int seq)
+ {
+ // Addresses and latency will be filled in later
+ this.type = type;
+ this.seq = seq;
+ }
+}
Added: trunk/freenet/src/load-balancing-sims/phase1/Peer.java
===================================================================
--- trunk/freenet/src/load-balancing-sims/phase1/Peer.java 2006-07-13
08:26:47 UTC (rev 9589)
+++ trunk/freenet/src/load-balancing-sims/phase1/Peer.java 2006-07-13
11:39:14 UTC (rev 9590)
@@ -0,0 +1,21 @@
+class Peer
+{
+ public int address; // The remote node's address
+ public double latency; // Latency of the connection in seconds
+ public NetworkInterface net; // The local node's network interface
+
+ public Peer (int address, double latency, NetworkInterface net)
+ {
+ this.address = address;
+ this.latency = latency;
+ this.net = net;
+ }
+
+ public void sendPacket (Packet p)
+ {
+ // Source address will be filled in by the network interface
+ p.destination = address;
+ p.latency = latency;
+ net.send (p);
+ }
+}
Added: trunk/freenet/src/load-balancing-sims/phase1/Sim.java
===================================================================
--- trunk/freenet/src/load-balancing-sims/phase1/Sim.java 2006-07-13
08:26:47 UTC (rev 9589)
+++ trunk/freenet/src/load-balancing-sims/phase1/Sim.java 2006-07-13
11:39:14 UTC (rev 9590)
@@ -0,0 +1,35 @@
+class Sim
+{
+ public static void main (String[] args)
+ {
+ Node n1 = new Node();
+ Node n2 = new Node();
+ Node n3 = new Node();
+
+ // Connect the nodes in a triangle (symmetric link latencies)
+ double latency = Math.random() / 10.0;
+ n1.connect (n2, latency);
+ n2.connect (n1, latency);
+ latency = Math.random() / 10.0;
+ n1.connect (n3, latency);
+ n3.connect (n1, latency);
+ latency = Math.random() / 10.0;
+ n2.connect (n3, latency);
+ n3.connect (n2, latency);
+
+ Network.reorder = true;
+
+ // Start the nodes pinging
+ Event.schedule (n1, Math.random(), Node.GENERATE_PING, null);
+ Event.schedule (n2, Math.random(), Node.GENERATE_PING, null);
+ Event.schedule (n3, Math.random(), Node.GENERATE_PING, null);
+
+ // Run for 10 seconds
+ Event.duration = 10.0;
+ while (Event.nextEvent()) {}
+
+ System.out.println (n1 + " sent " + n1.sent + ", received " +
n1.received);
+ System.out.println (n2 + " sent " + n2.sent + ", received " +
n2.received);
+ System.out.println (n3 + " sent " + n3.sent + ", received " +
n3.received);
+ }
+}
Added: trunk/freenet/src/load-balancing-sims/phase2/Event.java
===================================================================
--- trunk/freenet/src/load-balancing-sims/phase2/Event.java 2006-07-13
08:26:47 UTC (rev 9589)
+++ trunk/freenet/src/load-balancing-sims/phase2/Event.java 2006-07-13
11:39:14 UTC (rev 9590)
@@ -0,0 +1,92 @@
+import java.util.TreeSet; // Gotta love the collections framework...
+
+class Event implements Comparable
+{
+ // Static variables and methods for the event queue
+
+ private static TreeSet<Event> queue = new TreeSet<Event>();
+ private static double clockTime = 0.0;
+ private static int nextId = 0;
+ public static double duration = 0.0;
+
+ public static void reset()
+ {
+ queue.clear();
+ clockTime = 0.0;
+ nextId = 0;
+ duration = 0.0;
+ }
+
+ public static void schedule (EventTarget target, double time,
+ int type, Object data)
+ {
+ queue.add (new Event (target, time + clockTime, type, data));
+ }
+
+ public static boolean nextEvent()
+ {
+ try {
+ Event e = queue.first();
+ queue.remove (e);
+ // Update the clock
+ clockTime = e.time;
+ // Quit if the simulation's alloted time has run out
+ if (clockTime > duration) return false;
+ // Pass the packet to the target's callback method
+ e.target.handleEvent (e.type, e.data);
+ return true;
+ }
+ catch (java.util.NoSuchElementException x) {
+ // No more events to dispatch
+ return false;
+ }
+ }
+
+ public static double time()
+ {
+ return clockTime;
+ }
+
+ public static void log (String message)
+ {
+ System.out.print (clockTime + ": " + message + "\n");
+ }
+
+ // Non-static variables and methods for individual events
+
+ private EventTarget target;
+ private double time;
+ private int id;
+ private int type;
+ private Object data;
+
+ public Event (EventTarget target, double time, int type, Object data)
+ {
+ this.target = target;
+ this.time = time;
+ this.type = type;
+ this.data = data;
+ id = nextId++;
+ }
+
+ // Must be consistent with compareTo()
+ public boolean equals (Object o)
+ {
+ Event e = (Event) o;
+ if (e.time == time && e.id == id) return true;
+ return false;
+ }
+
+ // Must be consistent with equals()
+ public int compareTo (Object o)
+ {
+ Event e = (Event) o;
+ // Sort events by time (order of occurrence)
+ if (e.time > time) return -1;
+ if (e.time < time) return 1;
+ // Break ties by ID (order of scheduling)
+ if (e.id > id) return -1;
+ if (e.id < id) return 1;
+ return 0;
+ }
+}
Added: trunk/freenet/src/load-balancing-sims/phase2/EventTarget.java
===================================================================
--- trunk/freenet/src/load-balancing-sims/phase2/EventTarget.java
2006-07-13 08:26:47 UTC (rev 9589)
+++ trunk/freenet/src/load-balancing-sims/phase2/EventTarget.java
2006-07-13 11:39:14 UTC (rev 9590)
@@ -0,0 +1,4 @@
+interface EventTarget
+{
+ public void handleEvent (int type, Object data);
+}
Added: trunk/freenet/src/load-balancing-sims/phase2/Network.java
===================================================================
--- trunk/freenet/src/load-balancing-sims/phase2/Network.java 2006-07-13
08:26:47 UTC (rev 9589)
+++ trunk/freenet/src/load-balancing-sims/phase2/Network.java 2006-07-13
11:39:14 UTC (rev 9590)
@@ -0,0 +1,29 @@
+import java.util.HashMap;
+
+class Network
+{
+ private static HashMap<Integer,NetworkInterface> interfaces
+ = new HashMap<Integer,NetworkInterface>();
+ private static int nextAddress = 0;
+ // Can packets arrive out of order?
+ public static boolean reorder = false;
+
+ // Deliver a packet to an endpoint
+ public static void deliver (Packet p)
+ {
+ NetworkInterface ni = interfaces.get (p.destination);
+ if (ni == null) return; // Node doesn't exist or is offline
+ // If the network allows reordering, randomise the latency a bit
+ if (reorder) p.latency *= Math.random() * 0.2 + 0.9;
+ // Schedule the arrival of the packet at the destination
+ Event.schedule (ni, p.latency, NetworkInterface.RX_Q_ADD, p);
+ }
+
+ // Attach an interface to the network - returns the address
+ public static int register (NetworkInterface ni)
+ {
+ int address = nextAddress++;
+ interfaces.put (address, ni);
+ return address;
+ }
+}
Added: trunk/freenet/src/load-balancing-sims/phase2/NetworkInterface.java
===================================================================
--- trunk/freenet/src/load-balancing-sims/phase2/NetworkInterface.java
2006-07-13 08:26:47 UTC (rev 9589)
+++ trunk/freenet/src/load-balancing-sims/phase2/NetworkInterface.java
2006-07-13 11:39:14 UTC (rev 9590)
@@ -0,0 +1,130 @@
+import java.util.LinkedList;
+import java.util.NoSuchElementException;
+
+class NetworkInterface implements EventTarget
+{
+ public int address; // Represents an IP address and port
+ private Node owner; // The owner of this network interface
+ private double txSpeed, rxSpeed; // Bytes per second
+
+ private LinkedList<Packet> txQueue; // Queue of outgoing packets
+ private LinkedList<Packet> rxQueue; // Queue of incoming packets
+ private int txQueueSize, rxQueueSize; // Limited-size drop-tail queues
+
+ public NetworkInterface (Node owner)
+ {
+ this.owner = owner;
+ txSpeed = rxSpeed = 2000;
+ txQueue = new LinkedList<Packet>();
+ rxQueue = new LinkedList<Packet>();
+ txQueueSize = rxQueueSize = 5;
+ // Attach the interface to the network
+ address = Network.register (this);
+ }
+
+ // Called by Peer
+ public void send (Packet p)
+ {
+ Event.log (owner + " adding " + p.seq + " to txQueue");
+ p.source = address;
+ if (txQueue.size() >= txQueueSize) {
+ Event.log (owner + " has no room in txQueue!");
+ return; // Packet lost
+ }
+ txQueue.add (p);
+ Event.log (owner + " has " + txQueue.size() + " outgoing");
+ // If there are no other packets in the queue, start to transmit
+ if (txQueue.size() == 1) txStart (p);
+ }
+
+ // Event callbacks
+
+ // Add a packet to the rx queue
+ private void rxQueueAdd (Packet p)
+ {
+ Event.log (owner + " adding " + p.seq + " to rxQueue");
+ if (rxQueue.size() >= rxQueueSize) {
+ Event.log (owner + " has no room in rxQueue!");
+ return; // Packet lost
+ }
+ rxQueue.add (p);
+ Event.log (owner + " has " + rxQueue.size() + " incoming");
+ // If there are no other packets in the queue, start to receive
+ if (rxQueue.size() == 1) rxStart (p);
+ }
+
+ // Start receiving a packet
+ private void rxStart (Packet p)
+ {
+ Event.log (owner + " starting to receive " + p.seq);
+ // Delay depends on rx speed
+ Event.schedule (this, p.size / rxSpeed, RX_END, p);
+ }
+
+ // Finish receiving a packet, pass it to the node
+ private void rxEnd (Packet p)
+ {
+ Event.log (owner + " finished receiving " + p.seq);
+ owner.handlePacket (p);
+ // If there's another packet waiting, start to receive
+ try {
+ rxQueue.removeFirst();
+ rxStart (rxQueue.getFirst());
+ }
+ catch (NoSuchElementException nse) {}
+ }
+
+ // Start transmitting a packet
+ private void txStart (Packet p)
+ {
+ Event.log (owner + " starting to transmit " + p.seq);
+ // Delay depends on tx speed
+ Event.schedule (this, p.size / txSpeed, TX_END, p);
+ }
+
+ // Finish transmitting a packet
+ private void txEnd (Packet p)
+ {
+ Event.log (owner + " finished transmitting " + p.seq);
+ Network.deliver (p);
+ // If there's another packet waiting, start to transmit
+ try {
+ txQueue.removeFirst();
+ txStart (txQueue.getFirst());
+ }
+ catch (NoSuchElementException nse) {}
+ }
+
+ // EventTarget interface
+ public void handleEvent (int type, Object data)
+ {
+ switch (type) {
+ case RX_Q_ADD:
+ rxQueueAdd ((Packet) data);
+ break;
+
+ case RX_START:
+ rxStart ((Packet) data);
+ break;
+
+ case RX_END:
+ rxEnd ((Packet) data);
+ break;
+
+ case TX_START:
+ txStart ((Packet) data);
+ break;
+
+ case TX_END:
+ txEnd ((Packet) data);
+ break;
+ }
+ }
+
+ // Each EventTarget class has its own event codes
+ public final static int RX_Q_ADD = 1;
+ public final static int RX_START = 2;
+ public final static int RX_END = 3;
+ public final static int TX_START = 4;
+ public final static int TX_END = 5;
+}
Added: trunk/freenet/src/load-balancing-sims/phase2/Node.java
===================================================================
--- trunk/freenet/src/load-balancing-sims/phase2/Node.java 2006-07-13
08:26:47 UTC (rev 9589)
+++ trunk/freenet/src/load-balancing-sims/phase2/Node.java 2006-07-13
11:39:14 UTC (rev 9590)
@@ -0,0 +1,66 @@
+import java.util.HashMap;
+import java.util.ArrayList;
+
+class Node implements EventTarget
+{
+ private NetworkInterface net;
+ private HashMap<Integer,Peer> peers; // Look up a peer by its address
+ public int sent, received;
+
+ public Node()
+ {
+ peers = new HashMap<Integer,Peer>();
+ net = new NetworkInterface (this);
+ sent = received = 0;
+ }
+
+ public void connect (Node n, double latency)
+ {
+ Peer p = new Peer (n.net.address, latency, net);
+ peers.put (n.net.address, p);
+ }
+
+ // Called by NetworkInterface
+ public void handlePacket (Packet p)
+ {
+ if (p.type == Packet.PING) {
+ Event.log (this + " received ping " + p.seq);
+ Peer source = peers.get (p.source);
+ source.sendPacket (new Packet (Packet.PONG, p.seq));
+ Event.log (this + " sent pong " + p.seq);
+ }
+ else if (p.type == Packet.PONG) {
+ Event.log (this + " received pong " + p.seq);
+ received++;
+ }
+ }
+
+ // Event callback
+ private void generatePing()
+ {
+ // Choose a random peer
+ int randomIndex = (int) (Math.random() * peers.size());
+ ArrayList<Peer> a = new ArrayList<Peer> (peers.values());
+ Peer randomPeer = a.get (randomIndex);
+
+ // Each ping/pong pair is identified by a random nonce
+ int seq = (int) (Math.random() * 1000000);
+ randomPeer.sendPacket (new Packet (Packet.PING, seq));
+ Event.log (this + " sent ping " + seq);
+ sent++;
+ // Each node sends 10 pings
+ if (sent == 10) return;
+
+ // Schedule another ping after a random delay
+ Event.schedule (this, Math.random(), GENERATE_PING, null);
+ }
+
+ // EventTarget interface
+ public void handleEvent (int type, Object data)
+ {
+ if (type == GENERATE_PING) generatePing();
+ }
+
+ // Each EventTarget class has its own event codes
+ public final static int GENERATE_PING = 1;
+}
Added: trunk/freenet/src/load-balancing-sims/phase2/Packet.java
===================================================================
--- trunk/freenet/src/load-balancing-sims/phase2/Packet.java 2006-07-13
08:26:47 UTC (rev 9589)
+++ trunk/freenet/src/load-balancing-sims/phase2/Packet.java 2006-07-13
11:39:14 UTC (rev 9590)
@@ -0,0 +1,18 @@
+class Packet
+{
+ // Packet types
+ public final static int PING = 1, PONG = 2;
+
+ public int source, destination; // Network addresses
+ public int type; // Ping, pong, etc
+ public int seq; // Sequence number (actually just a nonce at the moment)
+ public int size = 1000; // Packet size in bytes, including headers
+ public double latency; // Stored here for convenience
+
+ public Packet (int type, int seq)
+ {
+ // Addresses and latency will be filled in later
+ this.type = type;
+ this.seq = seq;
+ }
+}
Added: trunk/freenet/src/load-balancing-sims/phase2/Peer.java
===================================================================
--- trunk/freenet/src/load-balancing-sims/phase2/Peer.java 2006-07-13
08:26:47 UTC (rev 9589)
+++ trunk/freenet/src/load-balancing-sims/phase2/Peer.java 2006-07-13
11:39:14 UTC (rev 9590)
@@ -0,0 +1,21 @@
+class Peer
+{
+ public int address; // The remote node's address
+ public double latency; // Latency of the connection in seconds
+ public NetworkInterface net; // The local node's network interface
+
+ public Peer (int address, double latency, NetworkInterface net)
+ {
+ this.address = address;
+ this.latency = latency;
+ this.net = net;
+ }
+
+ public void sendPacket (Packet p)
+ {
+ // Source address will be filled in by the network interface
+ p.destination = address;
+ p.latency = latency;
+ net.send (p);
+ }
+}
Added: trunk/freenet/src/load-balancing-sims/phase2/Sim.java
===================================================================
--- trunk/freenet/src/load-balancing-sims/phase2/Sim.java 2006-07-13
08:26:47 UTC (rev 9589)
+++ trunk/freenet/src/load-balancing-sims/phase2/Sim.java 2006-07-13
11:39:14 UTC (rev 9590)
@@ -0,0 +1,35 @@
+class Sim
+{
+ public static void main (String[] args)
+ {
+ Node n1 = new Node();
+ Node n2 = new Node();
+ Node n3 = new Node();
+
+ // Connect the nodes in a triangle (symmetric link latencies)
+ double latency = Math.random() / 10.0;
+ n1.connect (n2, latency);
+ n2.connect (n1, latency);
+ latency = Math.random() / 10.0;
+ n1.connect (n3, latency);
+ n3.connect (n1, latency);
+ latency = Math.random() / 10.0;
+ n2.connect (n3, latency);
+ n3.connect (n2, latency);
+
+ Network.reorder = true;
+
+ // Start the nodes pinging
+ Event.schedule (n1, Math.random(), Node.GENERATE_PING, null);
+ Event.schedule (n2, Math.random(), Node.GENERATE_PING, null);
+ Event.schedule (n3, Math.random(), Node.GENERATE_PING, null);
+
+ // Run until there are no more events to process
+ Event.duration = Double.POSITIVE_INFINITY;
+ while (Event.nextEvent()) {}
+
+ System.out.println (n1 + " sent " + n1.sent + " pings, received
" + n1.received + " pongs");
+ System.out.println (n2 + " sent " + n2.sent + " pings, received
" + n2.received + " pongs");
+ System.out.println (n3 + " sent " + n3.sent + " pings, received
" + n3.received + " pongs");
+ }
+}
Added: trunk/freenet/src/load-balancing-sims/phase4/Event.java
===================================================================
--- trunk/freenet/src/load-balancing-sims/phase4/Event.java 2006-07-13
08:26:47 UTC (rev 9589)
+++ trunk/freenet/src/load-balancing-sims/phase4/Event.java 2006-07-13
11:39:14 UTC (rev 9590)
@@ -0,0 +1,98 @@
+import java.util.TreeSet; // Gotta love the collections framework...
+
+class Event implements Comparable
+{
+ // Static variables and methods for the event queue
+
+ private static TreeSet<Event> queue = new TreeSet<Event>();
+ private static double clockTime = 0.0;
+ private static int nextId = 0;
+ public static double duration = Double.POSITIVE_INFINITY;
+
+ public static void reset()
+ {
+ queue.clear();
+ clockTime = 0.0;
+ nextId = 0;
+ duration = Double.POSITIVE_INFINITY;
+ }
+
+ public static void schedule (EventTarget target, double time,
+ int type, Object data)
+ {
+ queue.add (new Event (target, time + clockTime, type, data));
+ }
+
+ public static boolean nextEvent()
+ {
+ try {
+ Event e = queue.first();
+ queue.remove (e);
+ // Update the clock
+ clockTime = e.time;
+ // Quit if the simulation's alloted time has run out
+ if (clockTime > duration) return false;
+ // Pass the packet to the target's callback method
+ e.target.handleEvent (e.type, e.data);
+ return true;
+ }
+ catch (java.util.NoSuchElementException x) {
+ // No more events to dispatch
+ return false;
+ }
+ }
+
+ public static double time()
+ {
+ return clockTime;
+ }
+
+ public static void log (String message)
+ {
+ System.out.print (clockTime + " " + message + "\n");
+ }
+
+ // Run until the duration expires or there are no more events to process
+ public static void run()
+ {
+ while (nextEvent()) {}
+ }
+
+ // Non-static variables and methods for individual events
+
+ private EventTarget target;
+ private double time;
+ private int id;
+ private int type;
+ private Object data;
+
+ public Event (EventTarget target, double time, int type, Object data)
+ {
+ this.target = target;
+ this.time = time;
+ this.type = type;
+ this.data = data;
+ id = nextId++;
+ }
+
+ // Must be consistent with compareTo()
+ public boolean equals (Object o)
+ {
+ Event e = (Event) o;
+ if (e.time == time && e.id == id) return true;
+ return false;
+ }
+
+ // Must be consistent with equals()
+ public int compareTo (Object o)
+ {
+ Event e = (Event) o;
+ // Sort events by time (order of occurrence)
+ if (e.time > time) return -1;
+ if (e.time < time) return 1;
+ // Break ties by ID (order of scheduling)
+ if (e.id > id) return -1;
+ if (e.id < id) return 1;
+ return 0;
+ }
+}
Added: trunk/freenet/src/load-balancing-sims/phase4/EventTarget.java
===================================================================
--- trunk/freenet/src/load-balancing-sims/phase4/EventTarget.java
2006-07-13 08:26:47 UTC (rev 9589)
+++ trunk/freenet/src/load-balancing-sims/phase4/EventTarget.java
2006-07-13 11:39:14 UTC (rev 9590)
@@ -0,0 +1,4 @@
+interface EventTarget
+{
+ public void handleEvent (int type, Object data);
+}
Added: trunk/freenet/src/load-balancing-sims/phase4/Network.java
===================================================================
--- trunk/freenet/src/load-balancing-sims/phase4/Network.java 2006-07-13
08:26:47 UTC (rev 9589)
+++ trunk/freenet/src/load-balancing-sims/phase4/Network.java 2006-07-13
11:39:14 UTC (rev 9590)
@@ -0,0 +1,34 @@
+import java.util.HashMap;
+
+class Network
+{
+ private static HashMap<Integer,NetworkInterface> interfaces
+ = new HashMap<Integer,NetworkInterface>();
+ private static int nextAddress = 0;
+ public static boolean reorder = false; // Can packets be reordered?
+ public static double lossRate = 0.0; // Random packet loss
+ // FIXME: duplication
+
+ // Deliver a packet to an address
+ public static void deliver (Packet p)
+ {
+ NetworkInterface ni = interfaces.get (p.dest);
+ if (ni == null) return; // Node doesn't exist or is offline
+ // If the network allows reordering, randomise the latency a bit
+ if (reorder) p.latency *= (0.95 + Math.random() * 0.1);
+ if (Math.random() < lossRate) {
+ Event.log ("packet lost by network");
+ return;
+ }
+ // Schedule the arrival of the packet at the destination
+ Event.schedule (ni, p.latency, NetworkInterface.RX_Q_ADD, p);
+ }
+
+ // Attach an interface to the network - returns the address
+ public static int register (NetworkInterface ni)
+ {
+ int address = nextAddress++;
+ interfaces.put (address, ni);
+ return address;
+ }
+}
Added: trunk/freenet/src/load-balancing-sims/phase4/NetworkInterface.java
===================================================================
--- trunk/freenet/src/load-balancing-sims/phase4/NetworkInterface.java
2006-07-13 08:26:47 UTC (rev 9589)
+++ trunk/freenet/src/load-balancing-sims/phase4/NetworkInterface.java
2006-07-13 11:39:14 UTC (rev 9590)
@@ -0,0 +1,134 @@
+import java.util.LinkedList;
+import java.util.NoSuchElementException;
+
+class NetworkInterface implements EventTarget
+{
+ public int address; // Represents an IP address and port
+ private Node owner; // The owner of this network interface
+ private double txSpeed, rxSpeed; // Bytes per second
+
+ private LinkedList<Packet> txQueue; // Queue of outgoing packets
+ private LinkedList<Packet> rxQueue; // Queue of incoming packets
+ private int txQueueSize, rxQueueSize; // Limited-size drop-tail queues
+ private int txQueueMaxSize, rxQueueMaxSize; // Bytes
+
+ public NetworkInterface (Node owner, double txSpeed, double rxSpeed)
+ {
+ this.owner = owner;
+ this.txSpeed = txSpeed;
+ this.rxSpeed = rxSpeed;
+ txQueue = new LinkedList<Packet>();
+ rxQueue = new LinkedList<Packet>();
+ txQueueSize = rxQueueSize = 0; // Bytes
+ txQueueMaxSize = 10000;
+ rxQueueMaxSize = 20000;
+ // Attach the interface to the network
+ address = Network.register (this);
+ }
+
+ // Called by Peer
+ public void send (Packet p, int dest, double latency)
+ {
+ p.src = address;
+ p.dest = dest;
+ p.latency = latency;
+ if (txQueueSize + p.size > txQueueMaxSize) {
+ Event.log (address + " no room in txQueue");
+ return; // Packet lost
+ }
+ txQueue.add (p);
+ txQueueSize += p.size;
+ Event.log (address + " " + txQueueSize + " bytes in txQueue");
+ // If there are no other packets in the queue, start to transmit
+ if (txQueue.size() == 1) txStart (p);
+ }
+
+ // Event callbacks
+
+ // Add a packet to the rx queue
+ private void rxQueueAdd (Packet p)
+ {
+ if (rxQueueSize + p.size > rxQueueMaxSize) {
+ Event.log (address + " no room in rxQueue");
+ return; // Packet lost
+ }
+ rxQueue.add (p);
+ rxQueueSize += p.size;
+ Event.log (address + " " + rxQueueSize + " bytes in rxQueue");
+ // If there are no other packets in the queue, start to receive
+ if (rxQueue.size() == 1) rxStart (p);
+ }
+
+ // Start receiving a packet
+ private void rxStart (Packet p)
+ {
+ // Delay depends on rx speed
+ Event.schedule (this, p.size / rxSpeed, RX_END, p);
+ }
+
+ // Finish receiving a packet, pass it to the node
+ private void rxEnd (Packet p)
+ {
+ owner.handlePacket (p);
+ // If there's another packet waiting, start to receive it
+ try {
+ rxQueueSize -= p.size;
+ rxQueue.remove (p);
+ rxStart (rxQueue.getFirst());
+ }
+ catch (NoSuchElementException nse) {}
+ }
+
+ // Start transmitting a packet
+ private void txStart (Packet p)
+ {
+ // Delay depends on tx speed
+ Event.schedule (this, p.size / txSpeed, TX_END, p);
+ }
+
+ // Finish transmitting a packet
+ private void txEnd (Packet p)
+ {
+ Network.deliver (p);
+ // If there's another packet waiting, start to transmit it
+ try {
+ txQueueSize -= p.size;
+ txQueue.remove (p);
+ txStart (txQueue.getFirst());
+ }
+ catch (NoSuchElementException nse) {}
+ }
+
+ // EventTarget interface
+ public void handleEvent (int type, Object data)
+ {
+ switch (type) {
+ case RX_Q_ADD:
+ rxQueueAdd ((Packet) data);
+ break;
+
+ case RX_START:
+ rxStart ((Packet) data);
+ break;
+
+ case RX_END:
+ rxEnd ((Packet) data);
+ break;
+
+ case TX_START:
+ txStart ((Packet) data);
+ break;
+
+ case TX_END:
+ txEnd ((Packet) data);
+ break;
+ }
+ }
+
+ // Each EventTarget class has its own event codes
+ public final static int RX_Q_ADD = 1;
+ public final static int RX_START = 2;
+ public final static int RX_END = 3;
+ public final static int TX_START = 4;
+ public final static int TX_END = 5;
+}
Added: trunk/freenet/src/load-balancing-sims/phase4/Node.java
===================================================================
--- trunk/freenet/src/load-balancing-sims/phase4/Node.java 2006-07-13
08:26:47 UTC (rev 9589)
+++ trunk/freenet/src/load-balancing-sims/phase4/Node.java 2006-07-13
11:39:14 UTC (rev 9590)
@@ -0,0 +1,47 @@
+import java.util.HashMap;
+
+class Node implements EventTarget
+{
+ public final static int PACKET_SIZE = 500; // Excluding headers
+
+ private NetworkInterface net;
+ private HashMap<Integer,Peer> peers; // Look up a peer by its address
+
+ public Node (double txSpeed, double rxSpeed)
+ {
+ peers = new HashMap<Integer,Peer>();
+ net = new NetworkInterface (this, txSpeed, rxSpeed);
+ }
+
+ public void connect (Node n, double latency)
+ {
+ Peer p = new Peer (n.net.address, latency, net);
+ peers.put (n.net.address, p);
+ }
+
+ // Called by NetworkInterface
+ public void handlePacket (Packet packet)
+ {
+ Peer peer = peers.get (packet.src);
+ if (peer == null) Event.log (net.address + " unknown peer!");
+ else peer.handlePacket (packet);
+ }
+
+ // Event callback
+ private void start()
+ {
+ // Give each peer some work to do
+ for (Peer p : peers.values())
+ for (int i = 0; i < 1000000 / PACKET_SIZE; i++)
+ p.write (new Packet (Packet.DATA, PACKET_SIZE));
+ }
+
+ // EventTarget interface
+ public void handleEvent (int type, Object data)
+ {
+ if (type == START) start();
+ }
+
+ // Each EventTarget class has its own event codes
+ public final static int START = 1;
+}
Added: trunk/freenet/src/load-balancing-sims/phase4/Packet.java
===================================================================
--- trunk/freenet/src/load-balancing-sims/phase4/Packet.java 2006-07-13
08:26:47 UTC (rev 9589)
+++ trunk/freenet/src/load-balancing-sims/phase4/Packet.java 2006-07-13
11:39:14 UTC (rev 9590)
@@ -0,0 +1,20 @@
+class Packet
+{
+ // Packet types
+ public final static int DATA = 1, ACK = 2;
+ public final static int HEADER_SIZE = 50;
+
+ public int src, dest; // Network addresses
+ public int type; // Data, ack, etc
+ public int size; // Packet size in bytes, including headers
+ public int seq; // Sequence number or explicit ack
+
+ public double latency; // Link latency (stored here for convenience)
+ public double sent; // Time at which the packet was last transmitted
+
+ public Packet (int type, int dataSize)
+ {
+ this.type = type;
+ size = dataSize + HEADER_SIZE;
+ }
+}
Added: trunk/freenet/src/load-balancing-sims/phase4/Peer.java
===================================================================
--- trunk/freenet/src/load-balancing-sims/phase4/Peer.java 2006-07-13
08:26:47 UTC (rev 9589)
+++ trunk/freenet/src/load-balancing-sims/phase4/Peer.java 2006-07-13
11:39:14 UTC (rev 9590)
@@ -0,0 +1,285 @@
+import java.util.LinkedList;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+class Peer implements EventTarget
+{
+ public final static double TIMER = 0.5; // Coarse-grained timer, seconds
+ public final static double RTO = 4.0; // Retransmission timeout in RTTs
+ public final static double FRTO = 1.5; // Fast retx timeout in RTTs
+ public final static double RTT_DECAY = 0.9; // Exp moving average
+ public final static int MIN_CWIND = 3000; // Minimum congestion window
+ public final static int MAX_CWIND = 100000; // Maximum congestion window
+ // Note: RWIND must be at least 2 * FRTO * MAX_CWIND
+ public final static int RWIND = 400000; // Maximum bytes buffered at rx
+ public final static double ALPHA = 0.1615; // AIMD increase parameter
+ public final static double BETA = 0.9375; // AIMD decrease parameter
+ public final static double GAMMA = 3.0; // Slow start divisor
+
+ public int address; // The remote node's address
+ private double latency; // Latency of the connection in seconds
+ private NetworkInterface net; // The local node's network interface
+
+ // Sender
+ private double rtt = 3.0; // Estimated round-trip time in seconds
+ private double cwind = MIN_CWIND; // Congestion window in bytes
+ private boolean slowStart = true; // Are we in the slow start phase?
+
+ private double lastTransmission = 0.0; // Clock time
+ private double lastCongestionDecrease = 0.0; // Clock time
+ private boolean timerRunning = false; // Is the retx timer running?
+
+ private int inflight = 0; // Bytes sent but not acked
+ private int txSeq = 0; // Sequence number of next outgoing packet
+ private LinkedList<Packet> txBuffer; // Retransmission buffer
+ private LinkedList<Packet> txQueue; // Packets waiting to be sent
+
+ // Receiver
+ private int buffered = 0; // Bytes buffered for reassembly
+ private int rxSeq = 0; // Sequence number of next incoming packet
+ private LinkedList<Packet> rxBuffer; // Reassembly buffer
+ private LinkedList<Packet> rxQueue; // Packets waiting to be collected
+
+ public Peer (int address, double latency, NetworkInterface net)
+ {
+ this.address = address;
+ this.latency = latency;
+ this.net = net;
+ txBuffer = new LinkedList<Packet>();
+ txQueue = new LinkedList<Packet>();
+ rxBuffer = new LinkedList<Packet>();
+ rxQueue = new LinkedList<Packet>();
+ }
+
+ // Queues a packet for transmission
+ public void write (Packet p)
+ {
+ // Length of transmission queue is umlimited - be careful!
+ txQueue.add (p);
+ if (txQueue.size() == 1) sendData();
+ }
+
+ // Returns a reassembled packet, or null if there are none waiting
+ public Packet read()
+ {
+ try { return rxQueue.removeFirst(); }
+ catch (NoSuchElementException nse) { return null; }
+ }
+
+ // Send as much data as the receiver window and congestion window allow
+ private void sendData()
+ {
+ Iterator<Packet> i = txQueue.iterator();
+ while (i.hasNext()) {
+ if (sendData (i.next())) i.remove();
+ else break;
+ }
+ }
+
+ // Try to send a packet, return true if it was sent
+ private boolean sendData (Packet p)
+ {
+ // Don't send more bytes than the link can handle
+ if (inflight + p.size > cwind) {
+ log ("no room in congestion window");
+ return false;
+ }
+ // Return to slow start when the link is idle
+ double now = Event.time();
+ if (now - lastTransmission > RTO * rtt) {
+ log ("returning to slow start");
+ cwind = MIN_CWIND;
+ slowStart = true;
+ }
+ lastTransmission = now;
+ // Send the packet
+ p.seq = txSeq++;
+ log ("sending data " + p.seq);
+ net.send (p, address, latency);
+ // Buffer the packet for retransmission
+ p.sent = now;
+ inflight += p.size;
+ log (inflight + " bytes in flight");
+ txBuffer.add (p);
+ // Start the coarse-grained retransmission timer if necessary
+ if (!timerRunning) {
+ log ("starting timer");
+ Event.schedule (this, TIMER, CHECK_TIMEOUTS, null);
+ timerRunning = true;
+ }
+ return true;
+ }
+
+ private void sendAck (int seq)
+ {
+ Packet p = new Packet (Packet.ACK, 0);
+ p.seq = seq; // Explicit ack
+ log ("sending ack " + seq);
+ net.send (p, address, latency);
+ }
+
+ // Called by Node when a packet arrives
+ public void handlePacket (Packet p)
+ {
+ switch (p.type) {
+ case Packet.DATA:
+ handleData (p);
+ break;
+
+ case Packet.ACK:
+ handleAck (p);
+ break;
+ }
+ }
+
+ private void handleData (Packet p)
+ {
+ log ("received data " + p.seq);
+ // Is this the packet we've been waiting for?
+ if (p.seq == rxSeq) {
+ log ("data in order");
+ rxSeq++;
+ rxQueue.add (p);
+ // Reassemble contiguous packets
+ Iterator<Packet> i = rxBuffer.iterator();
+ while (i.hasNext()) {
+ Packet q = i.next();
+ if (q.seq == rxSeq) {
+ log ("adding contiguous data " + q.seq);
+ i.remove();
+ buffered -= q.size;
+ rxQueue.add (q);
+ rxSeq++;
+ }
+ else break;
+ }
+ log (buffered + " bytes buffered");
+ log ("expecting data " + rxSeq);
+ // FIXME: notify the node that there are packets waiting
+ }
+ else if (p.seq > rxSeq) {
+ log ("data out of order, expected " + rxSeq);
+ // Buffer the packet until all previous packets arrive
+ int index;
+ Iterator<Packet> i = rxBuffer.iterator();
+ for (index = 0; i.hasNext(); index++) {
+ Packet q = i.next();
+ if (q.seq == p.seq) {
+ log ("duplicate data " + p.seq);
+ sendAck (p.seq);
+ return;
+ }
+ if (q.seq > p.seq) break;
+ }
+ if (buffered + p.size > RWIND) {
+ // This shouldn't happen under normal conditions
+ log ("no space in buffer - packet dropped");
+ return;
+ }
+ buffered += p.size;
+ log (buffered + " bytes buffered");
+ rxBuffer.add (index, p);
+ // DEBUG
+ if (!rxBuffer.isEmpty()) {
+ for (Packet z : rxBuffer)
+ System.out.print (z.seq + " ");
+ System.out.println();
+ }
+ }
+ else log ("duplicate data " + p.seq); // Ack may have been lost
+ sendAck (p.seq);
+ }
+
+ private void handleAck (Packet p)
+ {
+ log ("received ack " + p.seq);
+ double now = Event.time();
+ boolean windowIncreased = false;
+ Iterator<Packet> i = txBuffer.iterator();
+ while (i.hasNext()) {
+ Packet q = i.next();
+ double age = now - q.sent;
+ // Explicit ack
+ if (q.seq == p.seq) {
+ log ("data " + q.seq + " acknowledged");
+ i.remove();
+ inflight -= q.size;
+ log (inflight + " bytes in flight");
+ // Increase the congestion window
+ if (slowStart) cwind += q.size / GAMMA;
+ else cwind += q.size * q.size * ALPHA / cwind;
+ if (cwind > MAX_CWIND) cwind = MAX_CWIND;
+ log ("congestion window increased to " + cwind);
+ // Update the average round-trip time
+ rtt = rtt * RTT_DECAY + age * (1.0 - RTT_DECAY);
+ log ("round-trip time " + age);
+ log ("average round-trip time " + rtt);
+ windowIncreased = true;
+ break;
+ }
+ // Fast retransmission
+ if (q.seq < p.seq && age > FRTO * rtt) {
+ q.sent = now;
+ log ("fast retransmitting data " + q.seq);
+ log (inflight + " bytes in flight");
+ net.send (q, address, latency);
+ decreaseCongestionWindow (now);
+ }
+ }
+ if (windowIncreased) sendData();
+ }
+
+ private void decreaseCongestionWindow (double now)
+ {
+ // The congestion window should only be decreased once per RTT
+ if (now - lastCongestionDecrease < rtt) return;
+ lastCongestionDecrease = now;
+ cwind *= BETA;
+ if (cwind < MIN_CWIND) cwind = MIN_CWIND;
+ log ("congestion window decreased to " + cwind);
+ // The slow start phase ends when the first packet is lost
+ if (slowStart) {
+ log ("leaving slow start");
+ slowStart = false;
+ }
+ }
+
+ private void log (String message)
+ {
+ Event.log (net.address + ":" + address + " " + message);
+ }
+
+ // Event callback
+ private void checkTimeouts()
+ {
+ log ("checking timeouts");
+ // If there are no packets in flight, stop the timer
+ if (txBuffer.isEmpty()) {
+ log ("stopping timer");
+ timerRunning = false;
+ return;
+ }
+ double now = Event.time();
+ for (Packet p : txBuffer) {
+ // Slow retransmission
+ if (now - p.sent > RTO * rtt) {
+ p.sent = now;
+ log ("retransmitting data " + p.seq);
+ log (inflight + " bytes in flight");
+ net.send (p, address, latency);
+ decreaseCongestionWindow (now);
+ }
+ }
+ // Reset the timer
+ Event.schedule (this, TIMER, CHECK_TIMEOUTS, null);
+ }
+
+ // EventTarget interface
+ public void handleEvent (int type, Object data)
+ {
+ if (type == CHECK_TIMEOUTS) checkTimeouts();
+ }
+
+ // Each EventTarget class has its own event codes
+ private final static int CHECK_TIMEOUTS = 1;
+}
Added: trunk/freenet/src/load-balancing-sims/phase4/Sim.java
===================================================================
--- trunk/freenet/src/load-balancing-sims/phase4/Sim.java 2006-07-13
08:26:47 UTC (rev 9589)
+++ trunk/freenet/src/load-balancing-sims/phase4/Sim.java 2006-07-13
11:39:14 UTC (rev 9590)
@@ -0,0 +1,34 @@
+// Interesting parameters to play with: txSpeed and rxSpeed, retransmission
+// timeout, window size, AIMD increase and decrease (Peer.java), queue size
+// (NetworkInterface.java), packet size (Node.java).
+
+class Sim
+{
+ public static void main (String[] args)
+ {
+ double txSpeed = 15000, rxSpeed = 15000; // Bytes per second
+ // rxSpeed = Math.exp (rand.nextGaussian() + 11.74);
+ // txSpeed = rxSpeed / 5.0;
+
+ Network.reorder = true;
+ Network.lossRate = 0.001;
+
+ Node n0 = new Node (txSpeed, rxSpeed);
+ Node n1 = new Node (txSpeed, rxSpeed);
+ Node n2 = new Node (txSpeed, rxSpeed);
+
+ n0.connect (n1, 0.1);
+ n0.connect (n2, 0.1);
+ n1.connect (n0, 0.1);
+ n1.connect (n2, 0.1);
+ n2.connect (n0, 0.1);
+ n2.connect (n1, 0.1);
+
+ Event.schedule (n0, Math.random(), Node.START, null);
+ Event.schedule (n1, Math.random(), Node.START, null);
+ Event.schedule (n2, Math.random(), Node.START, null);
+
+ // Run the simulation
+ Event.run();
+ }
+}