On Fri, Apr 10, 2009 at 09:03:12PM +0100, Matthew Toseland wrote:
> 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:

> > 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???

Good you spotted this! However, this is a rare event so it should not
have had any impact on previous simulations.

> > +                  }
> > +              }
> > +          }
> > +          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...

No. It has been used to re-insert data/keys into the network.

> > +            * 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?

If you mean preferential attachment to the nodes that are online: to
ensure the nodes that are online form a connected component. Normally
this code is *not* used, but nodes join randomly (from the set of
offline nodes) and vice-versa.

> > 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?

One could clearly simulate and compare.

> > +
> > +   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...

Yes, routes only cross specific nodes once (except when they backtrack). 
This is the best approximation I have found since I was unable to understand a 
few
heuristics in the node. I am looking forward to a good (but short!) summary of 
routing
heuristics or I will need to read code myself to make routing more realistic in 
further
versions.

> > +
> > +                     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?

It depends on the realism of phase7. It could be a start.

> 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?

It may be way off, but I checked that the load on the border nodes was fairly
low. I found that the success rate depends on the data finding its way over
the network borders once or twice, before becoming available in a different
component. Swapping specialization happens very slow with few border nodes,
which leads to content specialization and failed routes in the other component.
With more border nodes, specialization goes faster but at the same time there
are more border nodes able to take the load...

No, there is no simulation of the load-mgmt that nodes do. Its not event-based
down on a fine level of detail, high-level events such as routing and swapping
only *complete* at certain times. I am currently working on an event-based 
version.

> > +
> > +   /**
> > +    * 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?

Yes. This is based on irc discussions about such behavior. If there is a 
configured
limit, the available nodes are picked at random.

> ...
> > +
> > +   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?

Exactly.

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

Ok, its configurable.

> > +                   }
> > +           }
> > +           
> > +           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...

Yes, but it could also be based on some heuristic. Storing join and leave time
in the simulation is no problem. Do you have any suggestion for why it is 
needed?

> > +
> > +   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.

Are you sure?!

> > +
> > +       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?
> ...

Some experiments ... 

> > +
> > +   /**
> > +    * 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?

If they have the same location it does not matter... right? The switch can
not load to any difference.

> > +           }
> > +           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!)

Its just a matter of implemetation. The routes terminate for different reasons.
When a route has terminated, the implementation checks if the data was found. It
corresponds to the node checking the message directly in the real node.

> > +   //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...

In the original path folding algorithm all the nodes on the return path 
potentially
connect to the target. While this is not entirely realistic in a real network, 
this
heuristic is (AFAIK after reading the code) used in Freenet. For some value of 
"used"
as some months ago...

> > +                 }
> > +                 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?

Yes, this is just additional stuff to make it potentially more general. IIRC.

> > +    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?

Yeah, the program reads a configuration file ...  optionally also a settings 
file.

> > +                   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?

Yes, this is old stuff.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 195 bytes
Desc: not available
URL: 
<https://emu.freenetproject.org/pipermail/devl/attachments/20090424/e0af6b5a/attachment.pgp>

Reply via email to