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>