Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
2 changes: 1 addition & 1 deletion src/main/java/dev/oxoo2a/sim4da/Node.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,6 @@ public void stop () {
}

protected final int myId;
private Node2Simulator simulator;
protected Node2Simulator simulator;
private final Thread t_main;
}
1 change: 1 addition & 0 deletions src/main/java/dev/oxoo2a/sim4da/Simulator.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public void runSimulation ( int duration ) throws InstantiationException {
// Check that all nodes are attached
for ( Simulator2Node n : nodes.values() ) {
if (n == null) throw new InstantiationException();
System.out.println("set simulator");
n.setSimulator(this);
}

Expand Down
26 changes: 26 additions & 0 deletions src/main/java/dev/oxoo2a/sim4da/TokenRingNode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package dev.oxoo2a.sim4da;

public class TokenRingNode extends Node{
public TokenRingNode(int my_id) {
super(my_id);
}

@Override
protected void main() {
Message m = new Message();
if(myId == 0){
m.add("counter", 0);
sendUnicast(1, m);
}
while (true){
Network.Message m_raw = receive();
if(m_raw == null) break;
m = Message.fromJson(m_raw.payload);
int counter = Integer.parseInt(m.query("counter"));
emit("%d: counter == %d", myId, counter);
counter++;
m.add("counter", counter);
sendUnicast((myId + 1) % numberOfNodes(),m);
}
}
}
6 changes: 6 additions & 0 deletions src/main/java/dev/oxoo2a/sim4da/clock/ClockType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package dev.oxoo2a.sim4da.clock;

public enum ClockType {
LAMPORT,
VECTOR
}
12 changes: 12 additions & 0 deletions src/main/java/dev/oxoo2a/sim4da/clock/ClockUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package dev.oxoo2a.sim4da.clock;

public class ClockUtil {

public static LogicClock create(int id, ClockType type){
return switch (type) {
case LAMPORT -> new LampertClock(id);
case VECTOR -> new VectorClock(id);
};
}

}
52 changes: 52 additions & 0 deletions src/main/java/dev/oxoo2a/sim4da/clock/LampertClock.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package dev.oxoo2a.sim4da.clock;

public class LampertClock extends LogicClock{

public LampertClock(int nodeId){
super(nodeId, ClockType.LAMPORT);
this.time = 0;
}

@Override
public void synchronize(String timeStamp) {
super.synchronize(timeStamp);


if(this.tempTimestamps.keySet().size()>1){
System.err.println("more than one timestamp was extracted from string, should not happen with lamportClock");
System.out.println(timeStamp);
}
for (Integer senderId : tempTimestamps.keySet()){
System.out.println("Node " + this.nodeId + " syncing " + this.getTime() + " with "+ tempTimestamps.get(senderId));


this.time = Math.max(this.time, tempTimestamps.get(senderId));
}

}



@Override
public void tick() {
this.time++;
}

@Override
public ClockType getType() {
return type;
}

@Override
protected void printTimeStamps(){
System.out.println("TimeStampts of Node " + this.nodeId + " | Time " + this.time);
}

public int getTime() {
return time;
}

public int getNodeId() {
return this.getNodeId();
}
}
78 changes: 78 additions & 0 deletions src/main/java/dev/oxoo2a/sim4da/clock/LogicClock.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package dev.oxoo2a.sim4da.clock;


import java.util.HashMap;
import java.util.StringTokenizer;

/**
* LogicClock is instantiated for each TimedNode. A LogicClock saves its NodeID, timestamp, and temporary timestamps
* as received from other Nodes to synchronize. Further data and functionality is handled by Subclasses LamportClock/VectorClock.
*/

public abstract class LogicClock {

protected int nodeId;
protected int time;
public final ClockType type;
protected HashMap<Integer, Integer> tempTimestamps = new HashMap<>();

public LogicClock(int nodeId, ClockType type){
this.nodeId = nodeId;
this.type = type;
this.time =0;
}

public ClockType getType(){
return this.type;
}


public void tick(){
this.time++;
}

/**
* Parent Method to synchronize a Clock with a Time String as received in a Message (raw payload).
* synchronize() utilizes String Tokenization to extract all Timestamps from the Payload string. A Timestamp in the
* Payload always leads with the Characters '%T' + NodeID.
* The IDs and Times are saved in a Hashmap 'tempTimestamps' that is cleared with every new call of the method.
* tempTimestamps is used in the child class method to access all timestamps. When using Lamport time,
* the tempTimestamps Map always contains exactly one entry.
* Subclasses Override this Function by adding statements regarding the handling of the extracted Time information.
* @param payload the entire Payload string from the Message
*/
public void synchronize(String payload){
//First Tokenizer to collect all entrys from the payload
StringTokenizer tokenizer = new StringTokenizer(payload, ",");
// clear temporary timestamp field.
tempTimestamps.clear();
while (tokenizer.hasMoreTokens()){
int senderId = -1;
String token = tokenizer.nextToken();
String s = "";
// if token is marked as containing a timestamp
if (token.contains("%T")) {
// Seconds Tokenizer splits entry into Node ID and associated timestamp
StringTokenizer subTokenizer = new StringTokenizer(token, ":");
s = subTokenizer.nextToken();
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == 'T') {
senderId = Integer.parseInt(s.substring(i + 1, s.length() - 1));
break;
}

}

s = subTokenizer.nextToken();
int senderTime = Integer.parseInt(s.substring(1, s.length()-1));
tempTimestamps.put(senderId, senderTime);
}
}

}
protected void printTimeStamps(){}
public int getTime(){
return this.time;
}

}
73 changes: 73 additions & 0 deletions src/main/java/dev/oxoo2a/sim4da/clock/TimedNode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package dev.oxoo2a.sim4da.clock;

import dev.oxoo2a.sim4da.Message;
import dev.oxoo2a.sim4da.Network;
import dev.oxoo2a.sim4da.Node;


/**
* Basic Parent class for implementing Nodes with Logic Clocks.
* Time keeping is handled in send and receive methods using an Instance of LogicClock for each Node.
* Sending includes adding the nodes timestamp according to the used ClockType.
* Receiving includes parsing the time Information and updating a node's timestamp (synchronize(), see LogicClock.java)
*/
public class TimedNode extends Node {
LogicClock lc;

public TimedNode(int my_id, ClockType type) {
super(my_id);
this.lc = ClockUtil.create(my_id, type);
}

protected void sendUnicast ( int receiver_id, Message m ) {

this.lc.tick();
emit("%d ticked to %d",this.myId ,this.lc.getTime());


// clear all entries from message containing the timestamp identifier '%T'.
m.getMap().entrySet().removeIf(entry -> entry.getKey().contains("%T"));

if(this.lc instanceof LampertClock){
m.add("%T"+ myId, lc.getTime());
}
if(this.lc instanceof VectorClock){
for (Integer id: ((VectorClock) lc).getTimeVector().keySet()){
m.add("%T"+id, ((VectorClock) lc).getTimeVector().get(id));
}
}
if(this.lc instanceof VectorClock){
((VectorClock) this.lc).printVectorLine(((VectorClock) this.lc).getTimeVector());
}
System.out.println();

this.simulator.sendUnicast(myId,receiver_id, m.toJson());
}

protected Network.Message receive () {

Network.Message m = simulator.receive(myId);

lc.tick();
emit("%d ticked to %d",this.myId ,this.lc.getTime());

// synchronisation of clocks
if(m != null){
this.lc.synchronize(m.payload);
}


return m;
}


public LogicClock getLc() {
return lc;
}

@Override
protected void main() {}



}
85 changes: 85 additions & 0 deletions src/main/java/dev/oxoo2a/sim4da/clock/VectorClock.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package dev.oxoo2a.sim4da.clock;

import dev.oxoo2a.sim4da.Simulator;

import java.util.HashMap;


public class VectorClock extends LogicClock{
private final HashMap<Integer, Integer> timeVector;

public VectorClock (int nodeId){
super(nodeId, ClockType.VECTOR);
this.timeVector = new HashMap<>();
this.timeVector.put(nodeId, 0);
}

@Override
public void tick() {
this.timeVector.replace(this.nodeId, this.timeVector.get(this.nodeId) + 1);
}

@Override
public void synchronize(String timeStamp) {
super.synchronize(timeStamp);
System.out.print("Node " +this.getNodeId() + " is synchronizing " );
this.printVectorLine(this.getTimeVector());
System.out.print("(own) and ");
this.printVectorLine(this.tempTimestamps);

for(Integer id: this.tempTimestamps.keySet()){
if(!this.timeVector.containsKey(id)){
this.timeVector.put(id, this.tempTimestamps.get(id));
}else{
this.timeVector.put(id, Math.max(this.timeVector.get(id), this.tempTimestamps.get(id)));
}
}

System.out.println();

this.printTimeStamps();
this.time = this.timeVector.get(getNodeId());
}

@Override
public ClockType getType() {
return this.type;
}
@Override
public int getTime() {
return this.timeVector.get(nodeId);
}
public int getTime(int id){
return this.timeVector.get(id);
}

public HashMap<Integer, Integer> getTimeVector() {
return this.timeVector;
}

@Override
protected void printTimeStamps(){
System.out.print("CurrentVector of Node " + this.nodeId + " | Time = ");
printVectorLine(this.timeVector);
System.out.println();
}


protected void printVectorLine(HashMap<Integer,Integer> vector){
System.out.print("[");
int counter = 0;
int max = vector.size();
for (Integer k : vector.keySet()){
System.out.print(k + ":" + vector.get(k));
if(!(vector.size()== ++counter)){
System.out.print(",");
}
}
System.out.print("] ");
}


public int getNodeId() {
return this.nodeId;
}
}
25 changes: 25 additions & 0 deletions src/main/java/dev/oxoo2a/sim4da/example/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package dev.oxoo2a.sim4da.example;

import dev.oxoo2a.sim4da.Node;
import dev.oxoo2a.sim4da.Simulator;
import dev.oxoo2a.sim4da.clock.ClockType;

public class Main {
public static void main(String[] args) {
int n_nodes = 5;
Simulator s = Simulator.createDefaultSimulator(n_nodes);

for (int id=0; id<n_nodes; id++) {
//TimedTokenRingNode extends TimedNode -> Constructor expects ClockType
Node n = new TimedTokenRingNode(id, ClockType.VECTOR);
s.attachNode(id,n);
}

try{
s.runSimulation(1);
}catch (InstantiationException e){
System.err.println("Instantiation failed. Time to investigate.");
}

}
}
Loading