package routing; /* * SimpleRouterPromote.java * * Copyright 2011 by Matthew Orlinski, released under GPLv3. * Simple Router logic adapted from code by PJ Dillon http://www.cs.pitt.edu/~pdillon/one/ also GPLv3 */ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Map.Entry; import core.Connection; import core.DTNHost; import core.Message; import core.Settings; import core.SimClock; import core.Tuple; public class SimpleRouterPromote extends ActiveRouter { /** Prophet router's setting namespace ({@value})*/ public static final String SIMPLE_NS = "SimpleRouterPromote"; /** Threshold value for adding a host to the local community -setting id * {@value} */ public static final String LAMBDA_SETTING = "lambda"; /** Threshold value for merging the local community with a peer -setting id * {@value} */ public static final String GAMMA_SETTING = "gamma"; /** Total contact time threshold for adding a node to the familiar set * -setting id {@value} */ public static final String FAMILIAR_SETTING = "familiarThreshold"; public static final String DEGRADE = "degrade"; // current working variables public Map neighbourSet; public Set markedForDeletion; public Set localCommunity; //protected Map> neighbourSetCache; protected double lambda; protected double gamma; protected double familiarThreshold; //protected double degrade; public SimpleRouterPromote(Settings s) { super(s); Settings simpleSettings = new Settings(SIMPLE_NS); this.lambda = simpleSettings.getDouble(LAMBDA_SETTING); this.gamma = simpleSettings.getDouble(GAMMA_SETTING); this.familiarThreshold = simpleSettings.getDouble(FAMILIAR_SETTING); //this.degrade = simpleSettings.getDouble(DEGRADE); } public SimpleRouterPromote(SimpleRouterPromote proto) { super(proto); this.lambda = proto.lambda; this.gamma = proto.gamma; this.familiarThreshold = proto.familiarThreshold; //this.degrade = proto.degrade; //neighbourSetCache = new HashMap>(); neighbourSet = new HashMap(); localCommunity = new HashSet(); markedForDeletion = new HashSet(); } @Override public SimpleRouterPromote replicate() { return new SimpleRouterPromote(this); } @Override public void changedConnection(Connection con) { DTNHost myHost = getHost(); DTNHost otherNode = con.getOtherNode(myHost); SimpleRouterPromote otherRouter = (SimpleRouterPromote)otherNode.getRouter(); if(con.isUp()) { if(this.neighbourSet.containsKey(otherNode)) { this.neighbourSet.put(otherNode, this.neighbourSet.get(otherNode) + 1); } else this.neighbourSet.put(otherNode, 1.0); /* * * When this meets vi: * * 1) First thing this does when meeting vi is to start the clock (coded) * 2) aquires M, C, D and N * if vi is in this.C * 3) check records in Di for devices which match this.D if they match delete from this.D and this.C and scd.D and scd.C * 4) if a record is in Do and in Ni then we delete node from Do but not Ni * 5) Store the latest copy of C for vi. */ // 2) aquires M, C, D and N // you can get these by using //scd.metaCommunity //scd.localCommunity //scd.markedForDeletion //scd.neighbourSet // check local community information with new connections checkLocalCommunity(con); // Do node deletion if(this.localCommunity.contains(otherNode)) { // 3) check records in Di for devices which match this.D if they match delete from this.D and this.C and scd.D and scd.C Iterator it = this.markedForDeletion.iterator(); while (it.hasNext()) { DTNHost host = it.next(); if(otherRouter.markedForDeletion.contains(host)) { it.remove(); otherRouter.localCommunity.remove(host); this.localCommunity.remove(host); otherRouter.markedForDeletion.remove(host); } } // 4) if a record is in Do and in Ni then we delete node from Do but not Ni Iterator its = this.markedForDeletion.iterator(); while (its.hasNext()) { DTNHost host = its.next(); if(otherRouter.neighbourSet.containsKey(host)) { its.remove(); } } // 5) Store the latest copy of C for vi. //this.neighbourSetCache.put(peer, scd.neighbourSet); } } } public void checkLocalCommunity(Connection con) { DTNHost peer = con.getOtherNode(getHost()); SimpleRouterPromote peerC = (SimpleRouterPromote) con.getOtherNode(getHost()).getRouter(); this.localCommunity.add(getHost()); peerC.localCommunity.add(peer); // 2) check that the connection has met the time threshold. If so: if(this.neighbourSet.get(peer) >= this.familiarThreshold) { //System.out.println("Peer " + peer + " passed familiar threshold."); // 3) if device is in Do then remove it if(this.markedForDeletion.contains(peer)) this.markedForDeletion.remove(peer); // 4) possibly add to the local community for future transactions if(!this.localCommunity.contains(peer)) { /* * The algorithm calls for computing the size of the intersection of * peer's neighbourSet and this host's localCommunity. We divide that by * the size of the peer's familiar set */ // compute set intersection int count=0, peerFsize = peerC.neighbourSet.size(); Iterator> it = peerC.neighbourSet.entrySet().iterator(); while (it.hasNext()) { Map.Entry pairs = it.next(); if(this.localCommunity.contains(pairs.getKey())) count++; } //if(count > 1) // System.out.println("Count" + count); // add peer to local community if enough nodes in common if(((double)count)/peerFsize > this.lambda) { //System.out.println("Peer added to local comunity"); System.out.println("Peer " + peer + " added to LC."); this.localCommunity.add(peer); //this.neighbourSetCache.put(peer, new HashMap(peerC.neighbourSet)); // recalculate Meta Community //System.out.println("1) recalculating meta community -> "); //META TAKEN OUT: this.recalculateMetaCommunity(); //System.out.println(this.isHostInMetaCommunity(peer)); //System.out.println(metaCommunity.size() + " : " + this.isHostInMetaCommunity(peer)); } } // 4.1 if the node is still ot in the local community, give it another chance with this secondary promotion mechanism if(!this.localCommunity.contains(peer)) { // if the device is not in the local community, but is also the highest scoring node we have in the neighbour table // and is above the familiar threshold, then promote it. if(this.neighbourSet.get(peer) >= this.familiarThreshold && isMostConnected(peer)) { System.out.println("Peer " + peer + " secondary promoted to LC."); this.localCommunity.add(peer); } } // 5) Test for conditions when the local communities should be merged if(this.localCommunity.contains(peer)) { // Compute set union Set commUnion = new HashSet(this.localCommunity.size() + peerC.localCommunity.size() + 2); commUnion.addAll(this.localCommunity); commUnion.addAll(peerC.localCommunity); // compute intersection of the two local communities // (the result is the same from both node's perspective) int count = 0; for(DTNHost h : this.localCommunity) if(peerC.localCommunity.contains(h)) count++; // merge communities if enough nodes are common if(count > this.gamma * commUnion.size()) { //System.out.println("merging complete"); this.localCommunity.addAll(peerC.localCommunity); // recalculate Meta Community //META TAKEN OUT: this.recalculateMetaCommunity(); //System.out.println(this.isHostInMetaCommunity(peer)); } } } } private boolean isMostConnected(DTNHost peer) { // loop over all neighbours Iterator> it = this.neighbourSet.entrySet().iterator(); while (it.hasNext()) { Map.Entry pairs = it.next(); if((Double) pairs.getValue() > this.neighbourSet.get(peer)) return false; } return true; } protected boolean commumesWithHost(DTNHost h) { return(this.localCommunity.contains(h)); //META TAKEN OUT: return community.isHostInMetaCommunity(h); } /* protected boolean commumesWithHostIndirectly(DTNHost h) { return(this.neighbourSetCache.contains(h)); } */ /** * Tries to send all other messages to all connected hosts * * @return The return value of {@link #tryMessagesForConnected(List)} */ private Tuple tryOtherMessages() { List> messages = new ArrayList>(); Collection msgCollection = getMessageCollection(); /* for all connected hosts collect all messages that have a higher probability of delivery by the other host */ for (Connection con : getConnections()) { DTNHost other = con.getOtherNode(getHost()); SimpleRouterPromote othRouter = (SimpleRouterPromote)other.getRouter(); if (othRouter.isTransferring()) { continue; // skip hosts that are transferring } for (Message m : msgCollection) { if (othRouter.hasMessage(m.getId())) { continue; // skip messages that the other one has } // Which of us has the dest in our local communities, this host or the peer boolean peerInCommunity = othRouter.commumesWithHost(m.getTo()); boolean meInCommunity = this.commumesWithHost(m.getTo()); boolean deliver = false; if(peerInCommunity && !meInCommunity) // peer is in local commun. of dest deliver = true; if (deliver) { // the other node has higher probability of delivery messages.add(new Tuple(m,con)); } } } if (messages.size() == 0) { return null; } // sort the message-connection tuples return tryMessagesForConnected(messages); // try to send messages } @Override public void update() { super.update(); if (isTransferring() || !canStartTransfer()) { return; } if (exchangeDeliverableMessages() != null) { return; } tryOtherMessages(); /** * * Start of Simple logic * */ // Do refreshing of nodes in degrade version double simTime = SimClock.getTime(); // (seconds since start) // For each connection increment the connection time by 1 for(Connection c : getConnections()) { DTNHost peer = c.getOtherNode(getHost()); SimpleRouterPromote peerC = (SimpleRouterPromote) c.getOtherNode(getHost()).getRouter(); if(this.neighbourSet.containsKey(peer)) { this.neighbourSet.put(peer, this.neighbourSet.get(peer) + 1); } else this.neighbourSet.put(peer, 1.0); } double timeInDay = simTime % 120; // ever 120 seconds check local community information with connected nodes if(timeInDay == 0) { for(Connection c : getConnections()) { checkLocalCommunity(c); } } } /** * We'll probably use this in a version where we monitor duplicates of the message * @Override protected void transferDone(Connection con) { Message transferred = this.getMessage(con.getMessage().getId()); for(Iterator> i = outgoingMessages.iterator(); i.hasNext();) { Tuple t = i.next(); if(t.getKey().getId().equals(transferred.getId()) && t.getValue().equals(con)) { i.remove(); break; } } if(decider.shouldDeleteSentMessage(transferred, con.getOtherNode(getHost()))) { //if(transferred.getId().equals("M7")) //System.out.println("Host: " + getHost() + " deleting M7 after transfer"); this.deleteMessage(transferred.getId(), false); } } */ }