On Wednesday 11 February 2009 13:53:50 vive at freenetproject.org wrote:
> Author: vive
> Date: 2009-02-11 13:53:49 +0000 (Wed, 11 Feb 2009)
> New Revision: 25585
> 
> Added:
>    trunk/apps/simsalabim/AggregateCommand.java
>    trunk/apps/simsalabim/BasicDataSpace.java
>    trunk/apps/simsalabim/BuildTask.java
>    trunk/apps/simsalabim/CDataAggregator.java
>    trunk/apps/simsalabim/CircleKey.java
>    trunk/apps/simsalabim/Darknet.java
>    trunk/apps/simsalabim/DarknetNode.java
>    trunk/apps/simsalabim/DarknetRoute.java
>    trunk/apps/simsalabim/Data.java
>    trunk/apps/simsalabim/DataAggregator.java
>    trunk/apps/simsalabim/DataSpace.java
>    trunk/apps/simsalabim/EventLogger.java
>    trunk/apps/simsalabim/Feedback.java
>    trunk/apps/simsalabim/HBuildTask.java
>    trunk/apps/simsalabim/HDualStats.java
>    trunk/apps/simsalabim/HJoinTask.java
>    trunk/apps/simsalabim/HammingKey.java
>    trunk/apps/simsalabim/HistDataAggregator.java
>    trunk/apps/simsalabim/InfoCommand.java
>    trunk/apps/simsalabim/InfoObject.java
>    trunk/apps/simsalabim/JoinTask.java
>    trunk/apps/simsalabim/Key.java
>    trunk/apps/simsalabim/KeyFactory.java
>    trunk/apps/simsalabim/LimitedDataSpace.java
>    trunk/apps/simsalabim/MBuildTask.java
>    trunk/apps/simsalabim/MJoinTask.java
>    trunk/apps/simsalabim/Main.java
>    trunk/apps/simsalabim/MersenneTwister.java
>    trunk/apps/simsalabim/Node.java
>    trunk/apps/simsalabim/Person.java
>    trunk/apps/simsalabim/PopularityDataSpace.java
>    trunk/apps/simsalabim/PositionKey.java
>    trunk/apps/simsalabim/RandomEngine.java
>    trunk/apps/simsalabim/RunTask.java
>    trunk/apps/simsalabim/Script.java
>    trunk/apps/simsalabim/ScriptCommand.java
>    trunk/apps/simsalabim/ScriptCommandType.java
>    trunk/apps/simsalabim/ScriptException.java
>    trunk/apps/simsalabim/Settings.java
>    trunk/apps/simsalabim/SimulationException.java
>    trunk/apps/simsalabim/Simulator.java
>    trunk/apps/simsalabim/StringEventLogger.java
>    trunk/apps/simsalabim/TestSimulator.java
>    trunk/apps/simsalabim/TreeKey.java
>    trunk/apps/simsalabim/XorKey.java
>    trunk/apps/simsalabim/darknet/
>    trunk/apps/simsalabim/darknet/Darknet.java
>    trunk/apps/simsalabim/darknet/DarknetNode.java
>    trunk/apps/simsalabim/darknet/DarknetRoute.java
>    trunk/apps/simsalabim/darknet/Person.java
>    trunk/apps/simsalabim/rembre/
>    trunk/apps/simsalabim/rembre/Rembre.java
>    trunk/apps/simsalabim/rembre/RembreNode.java
>    trunk/apps/simsalabim/rembre/RembreRoute.java
>    trunk/apps/simsalabim/rembre/test.java
>    trunk/apps/simsalabim/utils/
>    trunk/apps/simsalabim/utils/Contains.java
>    trunk/apps/simsalabim/utils/DataStore.java
>    trunk/apps/simsalabim/utils/Heap.java
>    trunk/apps/simsalabim/utils/LRUHash.java
>    trunk/apps/simsalabim/utils/RandTester.java
>    trunk/apps/simsalabim/utils/RoutingTable.java
> Log:
> simsalabim: Freenet 0.7 simulator
> 
...
> +     
> +     /*
> +      * Generate a Kleinberg small-world of size, with a fixed number of 
> links 
added to
> +      * each node (resulting in a random number of links for nodes)
> +      */
> +     public Person[] swgraph(int size, int offset, int outdeg) {
> +
> +            Person [] people = new Person[size];
> +            for (int i=0; i<size; i++) {
> +                people[i] = new Person(i+offset);
> +            }
> +
> +            for (int i=0; i<size; i++) {
> +                Person source = people[i];
> +
> +                for (int j=0; j<outdeg; j++) {
> +                    boolean found = false;
> +                    while (!found) {
> +                          double u = re.nextDouble();
> +                          int dist = (int) 
> Math.floor(Math.exp(u*Math.log(size/2)));
> +                          int dest = i + ((re.nextDouble() < 0.5) ? -dist : 
> dist);
> +                          if (dest < 0) dest = dest + size;
> +                          if (dest > size-1) dest = dest - size;
> +                          Person target = people[dest];
> +
> +                          if (!source.linksTo(target) && 
> !target.linksTo(source)) {
> +                             source.addOut(target);
> +                             target.addOut(source);
> +                             found = true;
> +                          }

I think it is possible for a node to link to itself here???

> +                    }
> +                }
> +            }
> +            System.err.println("Created ideal Kleinberg graph (w.o. local 
connections) of size " + size);
> +            return people;
> +     }
> +             
> +        protected void setParameters() {
> +             // Settings
> +             INITIAL_SWITCHES = st.getInt("dnInitialSwitches",100);
> +             MAINT_SWITCHES = st.getInt("dnMaintSwitches",100);
> +             RAND_STEPS = st.getInt("dnRandSteps",10);
> +             HTL = st.getInt("dnHTL",20);
> +             STORE_SIZE = st.getInt("dnStoreSize",50);
> +             CACHE_SIZE = st.getInt("dnCacheSize",STORE_SIZE);               
>   // 
Default: same size as store
> +             VARDIST_RESOLUTION = st.getInt("varDistResolution", 100);
> +             N_BEST = st.getInt("dnNBest",3);
> +             MAXPEERS = st.getInt("dnMaxPeers",50);
> +             RECACHE_PROB = (float) st.getDouble("dnRecacheProb",0.0);       
>   // 
Whether to recache data after each successful request

What's RECACHE_PROB? The chance of storing to the store as well as the cache 
on a request? You are using LRU storage ... previous simulations suggest no 
significant difference between this and random replacement...

> +             RELINK_PROB = (float) st.getDouble("dnRelinkProb",1.0);
> +             DARKLINKS_ONLY_PROB = (float) 
> st.getDouble("dnLinksOnlyProb",1.0);
> +             if ((DARKLINKS_ONLY_PROB>1) || (DARKLINKS_ONLY_PROB<0))
> +                throw new Error("DARKLINKS_ONLY_PROB (dnLinksOnlyProb) needs 
> to be in 
[0,1]");
> +
> +             OPENNET_NODES_SWAP_PROB = (float) st.getDouble("onSwapProb", 
> 0.0);
> +             if (!(OPENNET_NODES_SWAP_PROB==0 || 
> (OPENNET_NODES_SWAP_PROB==1)))
> +                throw new Error("OPENNET_NODES_SWAP_PROB (onSwapProb) needs 
> to be 0 or 
1");
> +
> +             HYBRID_NODES_SWAP_PROB = (float) st.getDouble("hnSwapProb", 
> 0.0);
> +             if (!(HYBRID_NODES_SWAP_PROB==0 || HYBRID_NODES_SWAP_PROB==1))
> +                throw new Error("HYBRID_NODES_SWAP_PROB (hnSwapProb) needs 
> to be in 0 
or 1");         
> +
> +             RANDOM_GROWTH_MODEL = (int) st.getInt("randomGrowth",0);        
>   // 
Default growth is F2F, else persons with nodes are picked at random
> +             if (!(RANDOM_GROWTH_MODEL==0 || RANDOM_GROWTH_MODEL==1))
> +
> +             LEAVE_PERM_PROB = (float) st.getDouble("dnLeavePermProb",0.1);
> +             if ((LEAVE_PERM_PROB>1.0) || (LEAVE_PERM_PROB<0.0))
> +                 throw new Error("LEAVE_PERM_PROB (dnLeavePermProb) needs to 
> be in 
[0,1]");
> +
> +             // As in the freenet implementation
> +             OPENNET_MIN_SUCCESS_BETWEEN_DROP_CONNS = 
> st.getInt("onMinSuccess",10); // 
Min successful requests between folding (Freenet 0.7)
> +             OPENNET_RESET_PATH_FOLDING_PROB = (float) 
st.getDouble("onResetFoldProb",0.05); // Probability to steal folding 
reference (Freenet 0.7)
> +             OPENNET_DROP_MIN_AGE = st.getInt("onDropMinAge",30);            
>   // 
FIXME implement: Min age for node before we can drop it (Freenet 0.7)
> +             OPENNET_MIN_TIME_BEFORE_OFFERS = 
> st.getInt("onMinTimeOffers",30); // 
FIXME implement: Min age between we give offers (Freenet 0.7)
> +             OPENNET_MINPEERS = st.getInt("onMinPeers",10);
> +             OPENNET_MAXPEERS = st.getInt("onMaxPeers",20);
> +
> +             if (OPENNET_RESET_PATH_FOLDING_PROB > 1 || 
OPENNET_RESET_PATH_FOLDING_PROB < 0)
> +                     throw new Error("OPENNET_RESET_PATH_FOLDING_PROB 
> (onResetFoldProb) needs 
to be in [0,1]");
> +     }
> +
...
> +
> +      /**
> +              * Chooses the next person to join the network.
> +              */
> +      protected Person growNetwork() {
> +              // System.err.println("TS SIZE: " + ts.size());
> +              if (ts.isEmpty()) // no more people left
> +                      return null; 
> +              Person cand = ts.last();
> +              // System.err.println("Score: " + cand.score);
> +              ts.remove(cand);
> +
> +              for (Iterator<Person> it = cand.neighbors() ; it.hasNext() ; ) 
> {
> +                      Person p = it.next();
> +
> +                      if (ts.contains(p)) {
> +                              ts.remove(p);
> +                              p.score++;             
> +                              ts.add(p);
> +                      } else {
> +                              p.score++;
> +                              if (!p.isInNetwork()) {
> +                                      ts.add(p);
> +                              }
> +                      }
> +              }
> +
> +              return cand;
> +      }       

Preferential attachment?

> Added: trunk/apps/simsalabim/DarknetNode.java
> ===================================================================
> --- trunk/apps/simsalabim/DarknetNode.java                            (rev 0)
> +++ trunk/apps/simsalabim/DarknetNode.java    2009-02-11 13:53:49 UTC (rev 
25585)
> @@ -0,0 +1,504 @@
> +package simsalabim;
> +import java.util.*;
> +import simsalabim.utils.*;
> +
> +public class DarknetNode extends Node<Darknet, CircleKey> {
> +
> +     protected LRUHash data; 
> +     protected LRUHash cache;

We use LRU here. Other simulations have shown it to be very similar to random 
replacement. I guess there's no reason to complicate matters further?
> +
> +     public DarknetRoute findRoute(CircleKey k, DarknetRoute dnr) {
> +
> +             if (!inNetwork)
> +                     throw new Error("Node not in Network routed to: "  + 
> this);
> +             if (!isActive())
> +                     throw new Error("Node that is active routed to: " + 
> this);
> +
> +             /*
> +              * Routing with
> +              * 1) Backtracking
> +              * 2) HTL (fixed decrease per node, not probabilistic as in 
> freenet)
> +              *
> +              * Cache/Store: when route has completed
> +              */
> +
> +             if (dnr == null)
> +                     dnr = new DarknetRoute(god.N_BEST, god.HTL);
> +
> +             dnr.atNode(this, k);
> +             numQueries++;
> +
> +             if (data.contains(k) || cache.contains(k))              // 
> terminate on success
> +                     return dnr;
> +
> +             while (dnr.htl > 0) {
> +                   double bd = Double.MAX_VALUE;
> +                   DarknetNode cand = null;
> +
> +                   for (Iterator<DarknetNode> it = neighbors() ; 
> it.hasNext() ;) {
> +                       DarknetNode t = it.next();
> +                       if (dnr.contains(t))
> +                          continue;

We never route to the same node twice even to be rejected in your simulation. 
I wonder what impact this has? I mean, it would be easy enough to use a local 
set in this function, and check contains at the beginning of the function...

> +
> +                       double cd = t.pos.dist(k);
> +
> +                       if (cd < bd) {
> +                          bd = cd;
> +                          cand = t;
> +                       }
> +                   }
> +
> +                   if (cand != null) {
> +                       DarknetRoute branch = cand.findRoute(k, dnr);
> +                       dnr.atNode(this,k);
> +
> +                       if (branch.findData(k) != null) {
> +                           if (hasOpennetNeighbor(cand))
> +                                   moveUpOpennet(cand);             // 
> Freenet 0.7: Keep opennet 
nodes at LRU
> +
> +                           return dnr;
> +                       }
> +                   } else {
> +                       return dnr;           // Dead end
> +                   }
> +             }
> +
> +             return dnr;
> +             
> +     }

So routes are found in a recursive manner. This means this is a fairly high 
level (= fast) simulation. Cool. That means that load management simulations 
should be based on the event-based phase7?

Is there some basic load simulation? Your conclusions about network merging 
may be way off if you're not taking into account the limited capacity of the 
bridge nodes...? Or have you eliminated that somehow?
> +
> +     /**
> +      * To keep opennet peers sorted in most-recently used
> +      */
> +     public void moveUpOpennet(DarknetNode on) {
> +             if (!hasOpennetNeighbor(on))
> +                     throw new SimulationException("moveUpOpennet(): Lacking 
> neighbor");
> +
> +             openNeighbors.remove(on);
> +             openNeighbors.addFirst(on);             
> +     }
> +
> +     public int nKeys() { return data.size(); }
> +
> +     /**
> +      *  Connect to online darknet nodes up to a limit. With many available, 
pick at random.
> +      */

What does this function do? I mean, what does it model? When a user joins the 
darknet, he immediately connects to all his friends up to the connection 
limit?

...
> +
> +     public int leave(boolean permanent) {
> +             inNetwork = false; //NB: person disappears before node, to 
> avoid peers 
reconnecting
> +             user.leftNetwork();
> +             int n = neighbors.size() + openNeighbors.size();
> +
> +             for (Iterator<Person> it = user.neighbors() ; it.hasNext() ; ) {
> +                     Person p = it.next();
> +                     if (p.isInNetwork()) {
> +                             removeNeighbor(p.getNode());
> +                             p.getNode().refreshDarknet();

So when a user leaves, their peers who were up to their darknet peers limit 
will connect to their friends who were excluded by said limit?

There isn't really any limit, although we do warn the user ... performance may 
be a practical limit...

> +                     }
> +             }
> +             
> +             for (Iterator<DarknetNode> it = openNeighbors.iterator() ; 
it.hasNext() ; ) {
> +                 DarknetNode open = it.next();
> +                 open.openNeighbors.remove(this);
> +             }
> +             openNeighbors.clear();
> +
> +             // Dormant nodes dont remove data
> +             if (permanent) {
> +                 for (Iterator<Data> it = data.data() ; it.hasNext() ;) {
> +                     it.next().removedFrom(this);
> +                 }
> +
> +                 for (Iterator<Data> it = cache.data() ; it.hasNext() ;) {
> +                     it.next().removedFrom(this);
> +                 }
> +             }
> +
> +             return n;
> +     }
> +
> +     public boolean isSink(CircleKey k) {
> +             for (DarknetNode n : neighbors) {
> +                     if (k.dist(n.pos) < k.dist(pos))
> +                             return false;
> +             }
> +             return true;
> +     }

We have uptime requirements in this in the real node, it'd be nice to have 
some theoretical support for that decision... I guess it would require some 
sort of distribution of uptimes though...
> +
> +     public boolean hasData(CircleKey k) {
> +             return data.contains(k) || cache.contains(k);
> +     }
> +
> +     public Data findData(CircleKey k) {
> +             Data cached = cache.get(k);
> +
> +             return (cached != null) ? cached : data.get(k);
> +     }
> +
> +     /**
> +      * Always store in cache
> +      * @sink: Whether to store in the long-term storage
> +      */
> +       
> +     public void storeData(Data<CircleKey> d, boolean sink) {
> +         if (sink) {
> +             if (!data.contains(d.key()))
> +                 d.addedTo(this);
> +             Data r = data.put(d);
> +             if (r != null)
> +                     r.removedFrom(this);
> +         }

We don't store in the cache if we have stored in the store.
> +
> +         if (!cache.contains(d.key()))
> +             d.addedTo(this);
> +         Data r = cache.put(d);
> +         if (r != null)
> +             r.removedFrom(this);
> +
> +     }
> +
> +     /**
> +      * Stores at this node, and depth generation neighbors.
> +      */
> +     public void explosiveStore(Data d, int depth) {
> +             storeData(d, true); // Default option to put into store/cache
> +             if (depth > 0) {
> +                     for (Iterator<DarknetNode> it = neighbors.iterator() ; 
> it.hasNext() ;) {
> +                             it.next().explosiveStore(d, depth - 1);
> +                     }
> +             }
> +     }

Oooh, what did you use this for?
...
> +
> +     /**
> +      * Calculates the log distance to the neighbors of this node from 
> newpos. 
If
> +      * a neighbor has position newpos, then it is given my current position.
> +      */
> +     private double logdist(CircleKey newpos) {
> +             double val = 0.0f;
> +             for (Iterator<DarknetNode> it = neighbors.iterator() ; 
> it.hasNext() ;) {
> +                     DarknetNode dn = it.next();
> +                     val += Math.log(dn.pos == newpos ? pos.dist(newpos) : 
> +                             dn.pos.dist(newpos));

Doh! We just ignore it if we are neighbours in LocationManager.java! Granted 
this is a pretty small effect, but it needs to be fixed...

Hmm. Because of network bugs / race conditions, it is occasionally possible 
for two nodes to have the same location... Should we ignore when a peer of 
his has our location, or should we assume they are us and calculate it for 
their location? Is this different for before vs after calculations?

> +             }
> +             return val;
> +     } 
> +
> +
...
> Added: trunk/apps/simsalabim/DarknetRoute.java
> ===================================================================
> --- trunk/apps/simsalabim/DarknetRoute.java                           (rev 0)
> +++ trunk/apps/simsalabim/DarknetRoute.java   2009-02-11 13:53:49 UTC (rev 
25585)
...
> +
> +     public Data findData(CircleKey k) {
> +             for (Iterator<DarknetNode> it = route.iterator() ; it.hasNext() 
> ;) {
> +                     Data d  = it.next().findData(k);
> +                     if (d != null)
> +                             return d;
> +             }
> +             return null;
> +     }

You don't check on each hop as you reach it? Is this some idea about visiting 
all the nodes on the route even if we find the data early on, so we can store 
it everywhere for better data robustness? (And considerably worse performance 
on popular data!)

> +     //public void storeData(Data d) {
> +     //      for (Iterator<DarknetNode> it = route.iterator() ; it.hasNext() 
> ;) {
> +     //              it.next().storeData(d);
> +     //      }
> +     //}
> +
> +     /**
> +      * Store data in the route (always in cache, maybe also permanent)
> +      *
> +      * @d: data
> +      * @sink: to attempt storage in sink
> +      * @full: to store in the full (forward) path, else only in the return 
path
> +      */
> +     
> +     public int storeData(Data<CircleKey> d, boolean sink, boolean full) {
> +
> +             int nsink = 0;
> +
> +             LinkedList<DarknetNode> target;
> +             if (full)
> +                target = route;
> +             else
> +                target = retpath();
> +
> +             for (DarknetNode n : target) {
> +                     if (sink && n.isSink(d.key())) {
> +                             n.storeData(d, true);
> +                             nsink++;
> +                     }
> +                     else
> +                             n.storeData(d, false);
> +             }
> +
> +             return nsink;
> +     }
> +
> +     //public void storeBest(Data d) {
> +     //      for (int i = 0 ; i < nBest ; i++) {
> +     //              if (bestNodes[i] != null)
> +     //                      bestNodes[i].storeData(d);
> +     //      }
> +     //}
> +
> +     /**
> +      * ASSUMES: a successful query route (source ... dest ... source)
> +      *
> +      * Returns the return path (dest to source)
> +      */
> +
> +     public LinkedList<DarknetNode> retpath() {
> +         LinkedList<DarknetNode> retpath = new LinkedList<DarknetNode>();
> +
> +         /* Obtain the return path */
> +         ListIterator<DarknetNode> li = route.listIterator(route.size());
> +         while (li.hasPrevious()) {
> +             DarknetNode n = li.previous();
> +             if (retpath.contains(n))
> +                 break;
> +             retpath.addFirst(n);
> +         }
> +         return retpath;
> +     }
> +
> +
> +     /**
> +      * Relinks nodes open neighbors to one of the best nodes with given
> +      * probability, if possible.
> +      * ASSUMES: that this DarknetRoute contains WHOLE PATH (source ... 
dest ... source)
> +      */
> +     public void reLink(RandomEngine re, float prob, float rewrite_prob) {
> +             LinkedList<DarknetNode> retpath = retpath();
> +
> +             // Each node, when it wants to, may add its own ref to a 
> back-propagating 
request
> +
> +             DarknetNode target = (retpath.getFirst().isOpennet() && 
retpath.getFirst().needsOpennet()) ? retpath.getFirst() : null;
> +             ListIterator<DarknetNode> retitr = retpath.listIterator(1);
> +             while (retitr.hasNext()) {
> +                   DarknetNode current = retitr.next();
> +                   if (!current.isOpennet() || !current.needsOpennet())
> +                      continue;
> +
> +                   if (target == null) {
> +                           target = current;         // Always seek 
> connections
> +                           continue;
> +                   }
> +                   else if (re.nextFloat() < rewrite_prob) { // Maybe steal 
> the 
reference (as in Freenet 0.7)
> +                           target = current;

If we steal the reference, don't we get connected forwards as well as having a 
chance of getting connected backwards? I don't remember...

> +                   }
> +                   else if (re.nextFloat() < prob) {
> +                      current.reLink(target);
> +
> +                      // Maybe propagate ref backwards
> +                      if (current.needsOpennet()) {
> +                         target = current;
> +                      } else {
> +                         target = null;
> +                      }
> +
> +                   }
> +             }
> +     }
> +}
> 
> Added: trunk/apps/simsalabim/Data.java
> ===================================================================
> --- trunk/apps/simsalabim/Data.java                           (rev 0)
> +++ trunk/apps/simsalabim/Data.java   2009-02-11 13:53:49 UTC (rev 25585)
> @@ -0,0 +1,113 @@
> +package simsalabim;
> +
> +public class Data<K extends Key> implements InfoObject {
> +
> +    private long size;

What is data size for? You are assuming a file equals a key, correct?

> +    private K key;
> +
> +    private long createTime;
> +    private long placeTime = -1;
> +    private long deathTime = -1;
> +    private long forgetTime = -1;
> +
> +    private int storeCount = 0;
> +    private int retrieveCount = 0;
> +
> +    // For network partitioning
> +    private int sourceNetwork = 0;
> +
> +    public Data(Simulator god, K key, long size) {
> +     this(key, size, god.time());
> +    }
> +
> +    public Data(K key, long size, long createTime) {
> +        this.key = key;
> +        this.size = size;
> +        this.createTime = createTime;
> +    }
> +
> +    public K key() {
> +        return key;
> +    }
> +
> +    public long size() {
> +        return size;
> +    }
> +
> +    public void addedTo(Node n) {
> +     if (deathTime != -1)
> +             System.err.println("Added to node although deathtime set " + 
> this);
> +        if (placeTime == -1) {
> +            if (storeCount != 0)
> +                throw new SimulationException("Storage Count of data 
object " +
> +                                              "not zero on insert!");
> +            placeTime = n.time();
> +        }
> +        storeCount++;
> +    }
> +
> +    public void removedFrom(Node n) {
> +        if (storeCount == 0)
> +            throw new SimulationException("Data removed more times than 
stored"
> +                                          + ". Node: " + n);
> +        storeCount--;
> +        
> +        if (storeCount == 0)
> +            deathTime = n.time();
> +    }
> +    
> +    public void forgotten(long time) {
> +     this.forgetTime = time;
> +    }
> +    
> +    public void retrieved() {
> +     this.retrieveCount++;
> +    }
> +
> +    public int fieldnum() {
> +        return 8;
> +    }
> +
> +    public void sourceNetwork(int id) {
> +         sourceNetwork = id;
> +    }
> +
> +    public int sourceNetwork() {
> +         return sourceNetwork;
> +    }
> +
> +    // Info fields
> +    private static final String[] flds = {
> +        "Key",
> +        "Size",
> +        "Created",
> +        "Placed",
> +        "Died",
> +        "Forgotten",
> +        "Node Count",
> +        "RetrieveCount"
> +    };
> +
> +    public String[] fields() {
> +        return flds;
> +    }
> +
> +    public String[] info() {
> +        return new String[] {
> +            key.stringVal(),
> +            Long.toString(size),
> +            Long.toString(createTime),
> +            Long.toString(placeTime),
> +            Long.toString(deathTime),
> +            Long.toString(forgetTime),
> +            Long.toString(storeCount),
> +            Long.toString(retrieveCount)
> +        };
> +    }
> +    
> +    
> +    public String toString() {
> +        return "D/" + "K:" + key.toString() + "/S:" + size + "/";
> +    }
> +
> +}
> 
...
> Added: trunk/apps/simsalabim/Main.java
> ===================================================================
> --- trunk/apps/simsalabim/Main.java                           (rev 0)
> +++ trunk/apps/simsalabim/Main.java   2009-02-11 13:53:49 UTC (rev 25585)
> @@ -0,0 +1,93 @@
> +package simsalabim;
> +
> +import java.io.*;
> +import java.util.*;
> +
> +/**
> + * The Main run class. The only arguments needed to run is the name of the
> + * script file, and log file (which may be - ). Optionally a PRNG seed.
> + */
> +
> +public class Main {
> +
> +     public static void main(String[] args) {
> +             if (args.length < 3) {
> +                     System.err.println("Usage:  simsalabim.Main  
> <scriptfile> <settings> 
<logfile> [prng seed]");
> +                     System.exit(1);
> +             }    
> +
> +             int seed;
> +             if (args.length > 3)
> +                     seed = Integer.parseInt(args[3]);
> +             else
> +                     seed = (int) (System.currentTimeMillis() % 100000000l);
> +
> +             System.err.println("Using PRNG seed: " + seed);
> +
> +             RandomEngine re = new MersenneTwister(seed);
> +
> +             Settings st = new Settings(args[1]);
> +             
> +             DataSpace ds = createDataSpace(st);
> +
> +             Script sc;
> +             Simulator sim;
> +             PrintWriter out;
> +
> +             try {
> +                     BufferedReader br = new BufferedReader(new 
> FileReader(args[0]));
> +                     sc = new Script(br);
> +                     if (args[1].equals("-"))
> +                             out = new PrintWriter(new 
> OutputStreamWriter(System.out));
> +                     else
> +                             out = new PrintWriter(new FileWriter(args[2]));

args[1] surely? Or do you have to specify the filename twice? Or am I missing 
something?

> +                     EventLogger ev = new StringEventLogger(out);
> +
> +                     sim = sc.makeSim(re, ds, st, ev);
> +
> +                     long rtime = System.currentTimeMillis();
> +
> +                     ScriptCommand scom;
> +                     while ((scom = sc.nextCommand()) != null) {
> +                             System.err.println("Executing command: " + 
> scom);
> +                             scom.execute(sim);
> +                     }
> +
> +                     System.err.println("Simulation ran in: " 
> +                                     + (System.currentTimeMillis() - rtime) 
> + " ms.");
> +
> +             } catch (IOException e) {
> +                     System.err.println("IO Error reading script: " + e);
> +                     System.exit(1);
> +                     return; // for compiler
> +             } catch (ScriptException e) {
> +                     System.err.println("Error in script: " + 
> e.getMessage());
> +                     System.exit(1);
> +                     return; // for compiler
> +             }
> +
> +             out.println(sim.info());
> +             out.println(ds.info());
> +
> +             out.flush();
> +             out.close();
> +     }
> +
> +     private static DataSpace createDataSpace(Settings st) {
> +             String name = st.get("dsType", "PopularityDataSpace");
> +             if (name.equals("LimitedDataSpace")) {
> +                     return new LimitedDataSpace(st.getInt("dsMaxDocs", 
> 10000), st.getInt(
> +                                     "dsMinSize", 1000), 
> st.getInt("dsMaxSize", 2000));
> +                     /* /* */
> +
> +             } else if (name.equals("PopularityDataSpace")) {
> +                     return new PopularityDataSpace(st.getInt("dsMaxDocs", 
> 10000), st
> +                                     .getDouble("dsPopDecay", 1.0),
> +                                     st.getInt("dsMinSize", 1000), 
> st.getInt("dsMaxSize", 2000));
> +             } else {
> +                     throw new SimulationException("DataSpace type " + name
> +                                     + " unknown.");
> +             }
> +     }
> +
> +}
> 
...

> Added: trunk/apps/simsalabim/darknet/DarknetNode.java
> ===================================================================
> --- trunk/apps/simsalabim/darknet/DarknetNode.java                            
(rev 0)
> +++ trunk/apps/simsalabim/darknet/DarknetNode.java    2009-02-11 13:53:49 UTC 
(rev 25585)
> @@ -0,0 +1,323 @@
> +package simsalabim.darknet;
> +import simsalabim.*;
> +import java.util.*;
> +import simsalabim.utils.*;
> +
> +public class DarknetNode extends Node<Darknet, CircleKey> {
> +
> +     protected LRUHash data;
> +
> +     protected Person user;
> +
> +     protected CircleKey pos;
> +     protected LinkedList<DarknetNode> neighbors;
> +     protected LinkedList<DarknetNode> openNeighbors;
> +     final int nOpen;
> +
> +     private boolean inNetwork = false;
> +
> +     private int numQueries = 0;
> +
> +     public DarknetNode(Darknet god, int num, Person user, CircleKey pos,
> +                     int nOpen) {
> +             super(god, num);
> +             this.user = user;
> +
> +             this.pos = pos;
> +             this.nOpen = nOpen;
> +
> +             data = new LRUHash(god.STORE_SIZE);
> +             neighbors = new LinkedList<DarknetNode>();
> +             openNeighbors = new LinkedList<DarknetNode>();
> +     }
> +
> +
> +
> +     public DarknetRoute findRoute(CircleKey k, DarknetRoute dnr,
> +                     int maxNoImprove) {
> +
> +             if (!inNetwork)
> +                     throw new Error("Node not in Network routed to: "  + 
> this);
> +             if (!isActive())
> +                     throw new Error("Node that is active routed to: " + 
> this);
> +
> +             /*
> +              * This deviates in two ways from true Freenet routing. Firstly 
> I don't
> +              * backtrack, which I should, but which adds complication. 
> Secondly
> +              * Freenet doesn't have a fixed maxSteps, but stops after 
> taking x steps
> +              * without coming closer to the target value.

That hasn't been true for a long time. The simulator in darknet/ is a 
separate, older simulator?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 835 bytes
Desc: This is a digitally signed message part.
URL: 
<https://emu.freenetproject.org/pipermail/devl/attachments/20090410/e431b295/attachment.pgp>

Reply via email to