Author: robert
Date: 2008-02-14 19:19:49 +0000 (Thu, 14 Feb 2008)
New Revision: 17902

Modified:
   trunk/freenet/src/freenet/node/NetworkIDManager.java
Log:
probabilistic getConsensus


Modified: trunk/freenet/src/freenet/node/NetworkIDManager.java
===================================================================
--- trunk/freenet/src/freenet/node/NetworkIDManager.java        2008-02-14 
19:16:28 UTC (rev 17901)
+++ trunk/freenet/src/freenet/node/NetworkIDManager.java        2008-02-14 
19:19:49 UTC (rev 17902)
@@ -632,7 +632,7 @@
                        PeerNetworkGroup newGroup=(PeerNetworkGroup)i.next();
                        newGroup.setForbiddenIds(takenNetworkIds);

-                       int id=newGroup.getConsensus();
+                       int id=newGroup.getConsensus(true);
                        if (id==NO_NETWORKID)
                                id=node.random.nextInt();
                        newGroup.assignNetworkId(id);
@@ -821,12 +821,15 @@
                                        haveFoundIt=true;
                                        //should be the same: 
png.setForbiddenIds(nowTakenIds);
                                        int oldId=png.networkid;
-                                       int newId=png.getConsensus();
+                                       int newId=png.getConsensus(true);
+                                       /*
                                        if (png.ourGroup) {
                                                //Even if the consensus 
changes, we'll hold onto our group network id label.
                                                //Important for stability and 
future routing.
                                                return;
-                                       } else if (oldId==newId) {
+                                       } else
+                                        */
+                                       if (oldId==newId) {
                                                //Maybe they agree with us, 
maybe not; but it doesn't change our view of the group.
                                                return;
                                        } else {
@@ -847,7 +850,7 @@
                                        int oldId=png.networkid;
                                        int newId=oldId;
                                        if (nowTakenIds.contains(new 
Integer(oldId))) {
-                                               newId=png.getConsensus();
+                                               newId=png.getConsensus(true);
                                                png.assignNetworkId(newId);
                                        }
                                        nowTakenIds.add(new Integer(newId));
@@ -862,21 +865,30 @@
        /**
         A list of peers that we have assigned a network id to, and some logic 
as to why.
         */
-       public static class PeerNetworkGroup {
+       public class PeerNetworkGroup {
                List members;
                int networkid=NO_NETWORKID;
                boolean ourGroup;
                HashSet forbiddenIds;
                long lastAssign;
+               ///True if the last call to getConsensus() found only one 
network id for all members of this group
+               boolean unanimous;
+               
                /*
                 Returns the group consensus. If no peer in this group has 
advertised an id, then the last-assigned id is returned.
+                As a side effect, unanimous is set if there is only one 
network id for all peers in this group.
+                
+                @param probabilistic if true, may return any id from the set 
with increased probability towards the greater consensus.
                 @todo should be explict or weighted towards most-successful 
(not neccesarily just 'consensus')
                 */
-               int getConsensus() {
+               int getConsensus(boolean probabilistic) {
                        HashMap h=new HashMap();
                        Integer lastId=new Integer(networkid);
                        synchronized (this) {
                                Iterator i=members.iterator();
+                               int totalWitnesses=0;
+                               int maxId=networkid;
+                               int maxCount=0;
                                while (i.hasNext()) {
                                        PeerNode p=(PeerNode)i.next();
                                        Integer id=new 
Integer(p.providedNetworkID);
@@ -885,30 +897,45 @@
                                                continue;
                                        if (id.intValue()==NO_NETWORKID)
                                                continue;
-                                       Integer count=(Integer)h.get(id);
-                                       if (count==null)
-                                               count=new Integer(1);
-                                       else
-                                               count=new 
Integer(count.intValue()+1);
-                                       h.put(id, count);
+                                       totalWitnesses++;
+                                       int count=1;
+                                       Integer prev=(Integer)h.get(id);
+                                       if (prev!=null)
+                                               count=prev.intValue()+1;
+                                       h.put(id, new Integer(count));
+                                       if (count>maxCount) {
+                                               maxCount=count;
+                                               maxId=id.intValue();
+                                       }
                                        lastId=id;
                                }
                                //Should we include ourselves in the count? 
Probably not, as we generally determine our network id on consensus.
-                               //If there is only one option, it is most 
likely NO_NETWORKID anyway; or everyone agrees?!
+                               //If there is only one option everyone agrees 
(NO_NETWORKID is stripped out)
+                               unanimous=(h.size()==1);
                                if (h.size()<=1)
                                        return lastId.intValue();
-                               int maxId=networkid;
-                               int maxCount=0;
+                               if (!probabilistic)
+                                       return maxId;
+                               /*
+                                To choose a prob. network id, choose a random 
number between 0.0-1.0 and pick a network id such that if
+                                lined up they occupy as much of the number 
space (0.0-1.0) as there are peers in the group to that id.
+                                */
+                               double incrementPerWitness=1.0/totalWitnesses;
+                               double winningTarget=node.random.nextDouble();
+                               if (logMINOR) Logger.minor(this, 
"winningTarget="+winningTarget+", totalWitnesses="+totalWitnesses+", 
inc="+incrementPerWitness);
+                               double sum=0.0;
                                Iterator entries=h.entrySet().iterator();
                                while (entries.hasNext()) {
                                        Map.Entry e=(Map.Entry)entries.next();
                                        int id=((Integer)e.getKey()).intValue();
                                        int 
count=((Integer)e.getValue()).intValue();
-                                       if (count>maxCount) {
-                                               maxCount=count;
-                                               maxId=id;
+                                       sum+=count*incrementPerWitness;
+                                       if (logMINOR) Logger.minor(this, 
"network "+id+" "+count+" peers, "+sum);
+                                       if (sum>=winningTarget) {
+                                               return id;
                                        }
                                }
+                               Logger.error(this, "logic error; 
winningTarget="+winningTarget+", sum at end="+sum+", count="+h.size()); 
                                return maxId;
                        }
                }


Reply via email to