Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: Freenet/node/StandardDataStore.java


1   /*
2    *$Id: StandardDataStore.java,v 1.10 2000/04/08 20:48:17 hobbex Exp $
3   
4     This code is part of the Java Adaptive Network Client by Ian Clarke.
5     It is distributed under the GNU Public Licence (GPL) version 2.  See
6     http://www.gnu.org/ for further details of the GPL.
7   
8     Explanation of Code Versions:
9       0.0.0      = Initial Description
10      0.0.1      = API Specified
11      0.x (x>0)  = Partial Implementation
12      x.0 (x>0)  = Operational
13  
14    Requires Classes: Address
15                      Data
16   */
17  
18  /**
19   * DataStore.java
20   *
21   * This class is used by a node to store references and data.
22   *
23   * @version 0.0
24   * @author Ian Clarke (I.Clarke@strs.co.uk)
25   **/
26  
27  package Freenet.node;
28  import Freenet.*;
29  import Freenet.support.*;
30  import java.io.*;
31  import java.util.*;
32  
33  public class StandardDataStore implements DataStore
34  {
35       static private long write_interval;
36       static public String filename = ".freenet/store";
37  
38    // Debugging stuff to test this class
39      /* not working since Ian removed test code from data class
40    public static void main(String[] args) {
41      System.out.println("DataStore test routine\n-------");
42      System.out.println("Creating datastore size 20 with room for 30 bytes of data");
43      DataStore ds = new DataStore(30, 20);
44      System.out.println("Adding 10 data items");
45      for (int x = 0; x < 100; x += 5)
46        ds.put(new StringKey("Key "+x), new Address("local/"+x),
47               new Data("Data "+x));
48      System.out.println("Adding 10 reference items");
49      for (int x = 100; x < 200; x += 5)
50        ds.put(new StringKey("Key "+x), new Address("local/"+x), null);
51      Key last = null;
52      for (int x = 0; x < 10; x++) {
53        System.out.println("Finding closest key to Key 138 with mask "+
54                           last);
55        last = ds.findClosestKey(new StringKey("Key 138"), last);
56        System.out.println("Found "+last);
57        }
58      }
59      */
60    public static DataStore makeDataStore(Node node,  long maxData, int maxItems)
61    {
62      Object o=null;
63  
64      try
65      {
66        System.out.println(filename);
67        FileInputStream stream=new FileInputStream(filename);
68        ObjectInputStream ostream=new ObjectInputStream(stream);
69        o=ostream.readObject();
70        ostream.close();
71        if(!(o instanceof DataStore))
72          o=new StandardDataStore(maxData, maxItems);
73      }
74      catch(Exception e) 
75    {
76        Logger.log("DataStore.java", 
77             "Couldn't load DataStore from "+filename, 
78             Logger.NORMAL);
79        o=new StandardDataStore(maxData, maxItems); 
80    }
81  
82      write_interval=1000*Node.params.getlong("checkpointInterval",5*60);
83      Node.timer.add(23, write_interval, (Callback)o);
84      return (DataStore)o;
85    }
86  
87    public void tofile(String fname) throws IOException
88    {
89      synchronized(this)
90      {
91        Logger.log("DataStore.java","Writing datastore to disk",Logger.MINOR);
92        FileOutputStream stream=new FileOutputStream(fname);
93        ObjectOutputStream ostream=new ObjectOutputStream(stream);
94        ostream.writeObject(this);
95        ostream.close();
96      }
97    }
98  
99    public void callback()
100   {
101     try {
102       tofile(filename);
103       Node.timer.add(23, write_interval, this);
104     } catch(Exception e) {e.printStackTrace();}
105   }
106 
107   // Public Fields
108   public long maxData;
109 
110   // Protected Fields
111   protected CyclicArray ar;
112   protected Hashtable h;
113 
114   // Constructor
115 
116   public StandardDataStore(long maxData, int maxItems) {
117     ar = new CyclicArray(maxItems);
118     h = new Hashtable();
119     this.maxData = maxData;
120     }
121 
122   // Public Methods
123 
124   public Enumeration keys()
125   {
126     return h.keys();
127   }
128 
129   /**
130    * Searches for a key in the DataStore and if found returns
131    * any data associated with that key.  If none is found,
132    * null is returned.
133    * @param k The key to search for
134    * @return The data associated with the key or null if not found
135    **/
136 
137   public Data searchData(Key k) {
138     Logger.log("DataStore.java", "searchData("+k + ")", Logger.DEBUG);
139     synchronized (this)
140     {
141       DataStoreItem dsi = (DataStoreItem)h.get(k);
142       if(dsi==null || dsi.data==null)
143       {
144         Logger.log("DataStore.java", "Not found.", Logger.DEBUG);
145         return null;
146       }
147       // We have a hit, raise its priority
148       Logger.log("DataStore.java", "Data found.", Logger.DEBUG);
149       Data data = dsi.data;
150       Address addr = dsi.ref;
151       remove(k);
152       put(k, addr, data);
153       return data;
154     }
155   }
156 
157   /**
158     * Searches for a key in the DataStore and if found returns
159     * any reference associated with that key.  If none is found,
160     * null is returned.
161     * @param k The key to search for
162     * @return The reference associated with the key or null
163     *         if not found
164     **/
165 
166   public Address searchRef(Key k) {
167       if (k == null)
168     return null;
169     Logger.log("DataStore.java", "called searchRef("+k + ")", Logger.DEBUG);
170     synchronized (this)
171     {
172       DataStoreItem dsi = (DataStoreItem)h.get(k);
173       if(dsi==null)
174       {
175         Logger.log("DataStore.java", "Not found.", Logger.DEBUG);
176         return null;
177       }
178       Logger.log("DataStore.java", "Ref found.", Logger.DEBUG);
179       return dsi.ref;
180     }
181   }
182 
183   /**
184       * Removes an item from the DataStore given its key
185     * @param k The key of the item to remove
186     **/
187 
188   public void remove(Key k) {
189     synchronized (this) {
190       for (int x = 0; x < ar.length(); x++) {
191         DataStoreItem dsi = (DataStoreItem) ar.get(x);
192         Logger.log("DataStore.java",
193                    "Testing "+dsi + " against "+k, Logger.DEBUGGING);
194         if (dsi != null)
195           if (dsi.key.equals(k)) {
196             ar.remove(x);
197             h.remove(k);
198             return;
199             }
200         }
201       }
202     }
203 
204   /**
205     * Returns the reference associated with the closest key
206     * to k.
207     * @param k The key to search for
208     * @return The closest Key to k
209     **/
210   public Key findClosestKey(Key k) {
211     return findClosestKey(k, null);
212     }
213 
214   /**
215     * Returns the reference associated with the closest key
216     * to k.  The masking key allows the 'next best' key to
217     * be found.  Imagine the entries in the datastore being
218     * sorted in terms of closeness to the key you specify.
219     * With no mask key the reference associated with the
220     * top-most item will be returned.  However, with a mask
221     * key any references associated with keys above the mask
222     * key (including the mask key itself) will be ignored.
223     * This facility allows best-first backtracking.
224     * @param k The key to search for
225     * @param maskKey The masking key (or null for no mask)
226     * @return The closest Key to k (excluding masked keys) or
227     *         null if all keys are masked.
228     **/
229 
230   public Key findClosestKey(Key k, Key maskKey) {
231     int m = 0;
232     synchronized (this) {
233       // Ensure that maskKey exists
234       if ((maskKey != null) && (searchRef(maskKey) == null))
235         maskKey = null;
236       int indx = findNextClosestPos(k, maskKey);
237       if (indx < 0)
238     return null;
239       DataStoreItem dsi = (DataStoreItem) ar.get(indx);
240       if (dsi == null)
241         return null;
242       return dsi.key;
243       }
244     }
245 
246   /**
247     * Adds an item to the DataStore
248     * @param k The key to add
249     * @param r The address to which requests should be directed for
250     *          this key if the data is removed
251     * @param d The data associated with this key
252     **/
253 
254   public void put(Key k, Address r, Data d) {
255     synchronized (this) {
256       DataStoreItem dsi = new DataStoreItem(k, r, d);
257       DataStoreItem old = (DataStoreItem) ar.put(dsi);
258       if (old != null)
259     h.remove(old.key);
260       h.put(k, dsi);
261       cleanUpData();
262       }
263     }
264 
265   // Protected Methods
266 
267   /**
268    * Will return the position in ar of the closest key to k that is not
269    * as close as nextk
270    * @param k Key to search for
271    * @param nextk Must not be as close as this key, if non-null
272    * @return Position in ar of closest key, -1 if there is no key in ar
273    *         such that nextk is closer to k then that key
274    **/
275   protected int findNextClosestPos(Key k, Key nextk) {
276     synchronized (this) {
277       int cl = -1;
278       DataStoreItem bs = null;
279       for (int x = 0; x < ar.length(); x++) {
280         DataStoreItem ds = (DataStoreItem) ar.get(x);
281         if ((ds != null) &&
282             ((bs == null) || (k.compare(ds.key, bs.key)))) {
283           // ds is closer than bs
284           if ((nextk==null) || (k.compare(nextk, ds.key))) {
285             // nextk is closer than ds
286             // note that k.compare returns false on a tie
287             cl = x;
288             bs = ds;
289           }
290         }
291       }
292       return cl;
293     }
294   }
295 
296   /**
297     * Removes excess data (ie. if there is more data than is
298     * permitted by the maxData field).
299     **/
300   protected void cleanUpData() {
301     long total = 0;
302     for (int x = 0; x < ar.length(); x++) {
303       Object o = ar.get(x);
304       if (o != null) {
305         DataStoreItem dsi = (DataStoreItem) o;
306         if (dsi.data != null) {
307           if (total + dsi.data.length() > maxData)
308             dsi.data = null;
309           else
310             total += dsi.data.length();
311           }
312         }
313       }
314     }
315 
316   // Mainly for debugging
317   public String toString()
318   {
319     return h.toString();
320   }
321 }
322 
323 class DataStoreItem implements Serializable {
324   public Key key;
325   public Address ref;
326   public Data data;
327 
328   public DataStoreItem(Key k, Address a, Data d) {
329     key = k;
330     ref = a;
331     data = d;
332     }
333 
334   public String toString() {
335     return "Key: "+key + " Ref: "+ref + " Data:"+data;
336     }
337   }
338 
339 /*
340  *$Log: StandardDataStore.java,v $
341  *Revision 1.10  2000/04/08 20:48:17  hobbex
342  *Write DataStore to .freenet/store_<port>
343  *
344  *Revision 1.9  2000/04/08 19:19:52  hal
345  *synch when dumping datastore to disk so it can be modified in the middle.
346  *
347  *Revision 1.8  2000/04/08 15:22:19  hobbex
348  *Cleaned up my ugly code from yesterday
349  *
350  *Revision 1.7  2000/04/08 07:12:15  hal
351  *Move items to top of priority stack when searchData gets a hit.  Not
352  *very efficient.
353  *
354  *Revision 1.6  2000/04/07 23:19:33  hobbex
355  *Remove entry from hash when it is overwritten in the array
356  *
357  *Revision 1.5  2000/04/07 20:34:09  hobbex
358  *Fixed building and running with Kaffe (scripts/kbuild.sh). Added canceling of timer callback and sending of requestfailed on loosing MessageMemory (not too well tested). And fixed a bug in the datastore + some exception catching in requestfailed.
359  *
360  *Revision 1.4  2000/04/07 06:03:42  hal
361  *Clean up StandardDataStore:
362  *Make searchRef use the hashtable like searchData, no searching necessary
363  *Clean up findClosestKey to only search once not multiple times.
364  *Fix findClosestKey, it was not looking at the most recently inserted item.
365  *
366  *Revision 1.3  2000/04/03 21:04:55  hal
367  *Fix findClosestPos() in StandardDataStore.
368  *
369  *Revision 1.2  2000/04/02 21:13:25  blanu
370  *Moved class loading into a separate class (Freenet.support.Loader)
371  *
372  *Revision 1.1  2000/03/29 18:49:14  hobbex
373  *Subclassed Node from Core, added Freenet.node package
374  *
375  *Revision 1.18  2000/03/25 17:42:40  sanity
376  *Minor tidying of debug messages.
377  *
378  *Revision 1.17  2000/03/22 18:19:36  blanu
379  *Added Hashtable for keys for faster lookup.
380  *
381  *Revision 1.16  2000/03/17 10:06:02  blanu
382  *Changed Freenet.support.Timer to Freenet.support.Ticker to avoid JDK1.3 name conflict.
383  *
384  *Revision 1.15  2000/02/23 20:52:42  blanu
385  *Fixed timeout in client.
386  *
387  *Revision 1.14  2000/02/14 21:08:14  blanu
388  *The datastore is now written to disk every checkpointInterval seconds as
389  *per the configuration file, with a default of every 5 minutes.
390  *
391  *Revision 1.13  2000/02/14 00:20:31  blanu
392  *Periodic writing of DataStore information to .freenet/store. It doesn't
393  *work yet. I think it might be something wrong with Ticker.
394  *
395  *Revision 1.12  2000/02/13 12:11:57  sanity
396  *Fixed numerous syntax errors.
397  *
398  *Revision 1.11  2000/02/09 23:56:39  hobbex
399  *Preliminary tunneling of DataReplies and DataInserts (for now)
400  *
401  *Revision 1.10  2000/02/08 16:22:06  sanity
402  *Removed printing of exception when datastore file is not found, replaced
403  *with logger message.
404  *
405  *Revision 1.9  2000/02/02 21:03:06  blanu
406  *Changed the fromfile method so that it should work without a store file.
407  *
408  *Revision 1.8  2000/02/02 11:26:40  sanity
409  *Merged changes.
410  *
411  *Revision 1.7  2000/02/02 05:13:28  blanu
412  *Datastore can now be read to / written from a file. Params can be fetched as various types.
413  *
414  *Revision 1.6  2000/01/03 10:20:48  hobbex
415  *Removed deleting of MM on Loop and Failed Request
416  *
417  *Revision 1.5  2000/01/03 00:09:03  michaels
418  *findClosestPos didn't respect a set ignore flag on first dsi in array (cl==0)
419  *now it does.
420  *
421  *Revision 1.4  2000/01/02 14:10:15  michaels
422  *findClosestKey doesnt't return a dsi anymore if its ignore-flag is set to true
423  *
424  *Revision 1.3  2000/01/02 13:05:06  michaels
425  *searchRef is used for checking that a maskKey exists (not searchData)
426  *
427  */