Author: toad
Date: 2006-08-05 15:45:37 +0000 (Sat, 05 Aug 2006)
New Revision: 9904

Modified:
   trunk/freenet/src/freenet/node/Node.java
   trunk/freenet/src/freenet/node/RequestSender.java
   trunk/freenet/src/freenet/node/Version.java
   trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java
   trunk/freenet/src/freenet/store/FreenetStore.java
Log:
928:
Don't store keys in the store unless both a) we are the closest node so far, 
and b) it is an insert.
Store is limited to 80% of total, cache to 20% of total, but do not immediately 
shrink cache:
The cache will not grow beyond its limit; every time we insert a key to the 
store, we reduce the cache's limit, without actually shrinking the cache.
On startup, shrink the cache so that the store and the cache together do not 
exceed the overall limit.
=> The combination of the store and the cache may exceed the size limit 
temporarily if the cache was already over 20% of the overall limit, but will 
always be truncated on restart.
Comments.

Modified: trunk/freenet/src/freenet/node/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java    2006-08-05 14:58:53 UTC (rev 
9903)
+++ trunk/freenet/src/freenet/node/Node.java    2006-08-05 15:45:37 UTC (rev 
9904)
@@ -518,22 +518,30 @@
        static final int sizePerKey = CHKBlock.DATA_LENGTH + 
CHKBlock.TOTAL_HEADERS_LENGTH +
                DSAPublicKey.PADDED_SIZE + SSKBlock.DATA_LENGTH + 
SSKBlock.TOTAL_HEADERS_LENGTH;

-       /** The maximum number of keys stored in each of the datastores. */
+       /** The maximum number of keys stored in each of the datastores, cache 
and store combined. */
+       private long maxTotalKeys;
+       private long maxCacheKeys;
        private long maxStoreKeys;

-       /** These 3 are private because must be protected by synchronized(this) 
*/
-       /** The CHK datastore */
+       /* These are private because must be protected by synchronized(this) */
+       /** The CHK datastore. Long term storage; data should only be inserted 
here if
+        * this node is the closest location on the chain so far, and it is on 
an 
+        * insert (because inserts will always reach the most specialized node; 
if we
+        * allow requests to store here, then we get pollution by inserts for 
keys not
+        * close to our specialization). These conclusions derived from Oskar's 
simulations. */
        private final FreenetStore chkDatastore;
-       /** The SSK datastore */
+       /** The SSK datastore. See description for chkDatastore. */
        private final FreenetStore sskDatastore;
-       /** The store of DSAPublicKeys (by hash) */
+       /** The store of DSAPublicKeys (by hash). See description for 
chkDatastore. */
        private final FreenetStore pubKeyDatastore;
-       /** These 3 are private because must be protected by synchronized(this) 
*/
-       /** The CHK datastore */
+       /** The CHK datacache. Short term cache which stores everything that 
passes
+        * through this node. */
        private final FreenetStore chkDatacache;
-       /** The SSK datastore */
+       /** The SSK datacache. Short term cache which stores everything that 
passes
+        * through this node. */
        private final FreenetStore sskDatacache;
-       /** The store of DSAPublicKeys (by hash) */
+       /** The public key datacache (by hash). Short term cache which stores 
+        * everything that passes through this node. */
        private final FreenetStore pubKeyDatacache;
        /** RequestSender's currently running, by KeyHTLPair */
        private final HashMap requestSenders;
@@ -1441,23 +1449,29 @@
                                new LongCallback() {

                                        public long get() {
-                                               return maxStoreKeys * 
sizePerKey;
+                                               return maxTotalKeys * 
sizePerKey;
                                        }

                                        public void set(long storeSize) throws 
InvalidConfigValueException {
                                                if((storeSize < 0) || 
(storeSize < (32 * 1024 * 1024)))
                                                        throw new 
InvalidConfigValueException("Invalid store size");
                                                long newMaxStoreKeys = 
storeSize / sizePerKey;
-                                               if(newMaxStoreKeys == 
maxStoreKeys) return;
+                                               if(newMaxStoreKeys == 
maxTotalKeys) return;
                                                // Update each datastore
-                                               maxStoreKeys = newMaxStoreKeys;
+                                               maxTotalKeys = newMaxStoreKeys;
+                                               long maxStoreKeys = 
(maxTotalKeys * 4) / 5;
+                                               long maxCacheKeys = 
maxTotalKeys - maxStoreKeys;
                                                try {
-                                                       
chkDatastore.setMaxKeys(maxStoreKeys);
-                                                       
sskDatastore.setMaxKeys(maxStoreKeys);
-                                                       
pubKeyDatastore.setMaxKeys(maxStoreKeys);
-                                                       
chkDatacache.setMaxKeys(maxStoreKeys);
-                                                       
sskDatacache.setMaxKeys(maxStoreKeys);
-                                                       
pubKeyDatacache.setMaxKeys(maxStoreKeys);
+                                                       long sz;
+                                                       
chkDatastore.setMaxKeys(maxStoreKeys, false);
+                                                       sz = 
Math.max(maxCacheKeys, maxTotalKeys - chkDatastore.keyCount());
+                                                       
chkDatacache.setMaxKeys(sz, false);
+                                                       
pubKeyDatastore.setMaxKeys(maxStoreKeys, false);
+                                                       sz = 
Math.max(maxCacheKeys, maxTotalKeys - pubKeyDatastore.keyCount());
+                                                       
pubKeyDatacache.setMaxKeys(sz, false);
+                                                       
sskDatastore.setMaxKeys(maxStoreKeys, false);
+                                                       sz = 
Math.max(maxCacheKeys, maxTotalKeys - sskDatastore.keyCount());
+                                                       
sskDatacache.setMaxKeys(sz, false);
                                                } catch (IOException e) {
                                                        // FIXME we need to be 
able to tell the user.
                                                        Logger.error(this, 
"Caught "+e+" resizing the datastore", e);
@@ -1477,7 +1491,7 @@
                        throw new NodeInitException(EXIT_INVALID_STORE_SIZE, 
"Invalid store size");
                }

-               maxStoreKeys = storeSize / sizePerKey;
+               maxTotalKeys = storeSize / sizePerKey;

                nodeConfig.register("storeDir", ".", sortOrder++, true, "Store 
directory", "Name of directory to put store files in", 
                                new StringCallback() {
@@ -1527,11 +1541,15 @@
                        if(!sskStoreFile.renameTo(sskCacheFile))
                                throw new NodeInitException(EXIT_STORE_OTHER, 
"Could not migrate to two level cache: Could not rename "+sskStoreFile+" to 
"+sskCacheFile);
                }
+
+               maxStoreKeys = (maxTotalKeys * 4) / 5;
+               maxCacheKeys = maxTotalKeys - maxStoreKeys;

                try {
+                       BerkeleyDBFreenetStore tmp;
+                       long sz;
                        Logger.normal(this, "Initializing CHK Datastore");
                        System.out.println("Initializing CHK Datastore 
("+maxStoreKeys+" keys)");
-                       BerkeleyDBFreenetStore tmp;
                        try {
                                if((lastVersion > 0) && (lastVersion < 852)) {
                                        throw new 
DatabaseException("Reconstructing store because started from old version");
@@ -1546,20 +1564,23 @@
                        }
                        chkDatastore = tmp;
                        Logger.normal(this, "Initializing CHK Datacache");
-                       System.out.println("Initializing CHK Datacache 
("+maxStoreKeys+" keys)");
+                       sz = Math.max(maxCacheKeys, maxTotalKeys - 
tmp.keyCount());
+                       System.out.println("Initializing CHK Datacache 
("+sz+":"+maxCacheKeys+" keys)");
                        try {
                                if((lastVersion > 0) && (lastVersion < 852)) {
                                        throw new 
DatabaseException("Reconstructing store because started from old version");
                                }
-                               tmp = new BerkeleyDBFreenetStore(chkCachePath, 
maxStoreKeys, 32768, CHKBlock.TOTAL_HEADERS_LENGTH, true);
+                               tmp = new BerkeleyDBFreenetStore(chkCachePath, 
sz, 32768, CHKBlock.TOTAL_HEADERS_LENGTH, true);
                        } catch (DatabaseException e) {
                                System.err.println("Could not open store: "+e);
                                e.printStackTrace();
                                System.err.println("Attempting to 
reconstruct...");
                                WrapperManager.signalStarting(5*60*60*1000);
-                               tmp = new BerkeleyDBFreenetStore(chkCachePath, 
maxStoreKeys, 32768, CHKBlock.TOTAL_HEADERS_LENGTH, 
BerkeleyDBFreenetStore.TYPE_CHK);
+                               tmp = new BerkeleyDBFreenetStore(chkCachePath, 
sz, 32768, CHKBlock.TOTAL_HEADERS_LENGTH, BerkeleyDBFreenetStore.TYPE_CHK);
                        }
                        chkDatacache = tmp;
+                       chkDatacache.setMaxKeys(maxCacheKeys, false);
+                       // Shrink pubkey store immediately; it's tiny anyway.
                        Logger.normal(this, "Initializing pubKey Datastore");
                        System.out.println("Initializing pubKey Datastore");
                        try {
@@ -1576,18 +1597,18 @@
                        }
                        this.pubKeyDatastore = tmp;
                        Logger.normal(this, "Initializing pubKey Datacache");
-                       System.out.println("Initializing pubKey Datacache");
+                       System.out.println("Initializing pubKey Datacache 
("+maxCacheKeys+" keys)");
                        try {
                                if((lastVersion > 0) && (lastVersion < 852)) {
                                        throw new 
DatabaseException("Reconstructing store because started from old version");
                                }
-                               tmp = new BerkeleyDBFreenetStore(pkCachePath, 
maxStoreKeys, DSAPublicKey.PADDED_SIZE, 0, true);
+                               tmp = new BerkeleyDBFreenetStore(pkCachePath, 
maxCacheKeys, DSAPublicKey.PADDED_SIZE, 0, true);
                        } catch (DatabaseException e) {
                                System.err.println("Could not open store: "+e);
                                e.printStackTrace();
                                System.err.println("Attempting to 
reconstruct...");
                                WrapperManager.signalStarting(5*60*60*1000);
-                               tmp = new BerkeleyDBFreenetStore(pkCachePath, 
maxStoreKeys, DSAPublicKey.PADDED_SIZE, 0, BerkeleyDBFreenetStore.TYPE_PUBKEY);
+                               tmp = new BerkeleyDBFreenetStore(pkCachePath, 
maxCacheKeys, DSAPublicKey.PADDED_SIZE, 0, BerkeleyDBFreenetStore.TYPE_PUBKEY);
                        }
                        this.pubKeyDatacache = tmp;
                        // FIXME can't auto-fix SSK stores.
@@ -1595,8 +1616,10 @@
                        System.out.println("Initializing SSK Datastore");
                        sskDatastore = new BerkeleyDBFreenetStore(sskStorePath, 
maxStoreKeys, 1024, SSKBlock.TOTAL_HEADERS_LENGTH, false);
                        Logger.normal(this, "Initializing SSK Datacache");
-                       System.out.println("Initializing SSK Datacache");
-                       sskDatacache = new BerkeleyDBFreenetStore(sskCachePath, 
maxStoreKeys, 1024, SSKBlock.TOTAL_HEADERS_LENGTH, false);
+                       sz = Math.max(maxCacheKeys, maxTotalKeys - 
sskDatastore.keyCount());
+                       System.out.println("Initializing SSK Datacache 
("+sz+":"+maxCacheKeys+" keys)");
+                       sskDatacache = new BerkeleyDBFreenetStore(sskCachePath, 
sz, 1024, SSKBlock.TOTAL_HEADERS_LENGTH, false);
+                       sskDatacache.setMaxKeys(maxCacheKeys, false);
                } catch (FileNotFoundException e1) {
                        String msg = "Could not open datastore: "+e1;
                        Logger.error(this, msg, e1);
@@ -2814,22 +2837,46 @@

        /**
         * Store a datum.
-        * @param deep If true, insert to the store as well as the cache.
+        * @param deep If true, insert to the store as well as the cache. Do 
not set
+        * this to true unless the store results from an insert, and this node 
is the
+        * closest node to the target; see the description of chkDatastore.
         */
        public void store(CHKBlock block, boolean deep) {
                try {
-                       if(deep)
+                       if(deep) {
                                chkDatastore.put(block);
+                               long sz = Math.max(maxCacheKeys, maxTotalKeys - 
chkDatastore.keyCount());
+                               try {
+                                       chkDatacache.setMaxKeys(sz, false);
+                               } catch (DatabaseException e) {
+                                       // Impossible
+                                       Logger.error(this, "Caught "+e, e);
+                               }
+                       }
                        chkDatacache.put(block);
                } catch (IOException e) {
                        Logger.error(this, "Cannot store data: "+e, e);
                }
        }

+       /**
+        * Store a datum.
+        * @param deep If true, insert to the store as well as the cache. Do 
not set
+        * this to true unless the store results from an insert, and this node 
is the
+        * closest node to the target; see the description of chkDatastore.
+        */
        public void store(SSKBlock block, boolean deep) throws 
KeyCollisionException {
                try {
-                       if(deep)
+                       if(deep) {
                                sskDatastore.put(block, false);
+                               long sz = Math.max(maxCacheKeys, maxTotalKeys - 
sskDatastore.keyCount());
+                               try {
+                                       chkDatacache.setMaxKeys(sz, false);
+                               } catch (DatabaseException e) {
+                                       // Impossible
+                                       Logger.error(this, "Caught "+e, e);
+                               }
+                       }
                        sskDatacache.put(block, false);
                        cacheKey(((NodeSSK)block.getKey()).getPubKeyHash(), 
((NodeSSK)block.getKey()).getPubKey(), deep);
                } catch (IOException e) {

Modified: trunk/freenet/src/freenet/node/RequestSender.java
===================================================================
--- trunk/freenet/src/freenet/node/RequestSender.java   2006-08-05 14:58:53 UTC 
(rev 9903)
+++ trunk/freenet/src/freenet/node/RequestSender.java   2006-08-05 15:45:37 UTC 
(rev 9904)
@@ -436,7 +436,11 @@
        private void verifyAndCommit(byte[] data) throws KeyVerifyException {
        if(key instanceof NodeCHK) {
                CHKBlock block = new CHKBlock(data, headers, (NodeCHK)key);
-               node.store(block, resetNearestLoc);
+               // Cache only in the cache, not the store. The reason for this 
is that
+               // requests don't go to the full distance, and therefore 
pollute the 
+               // store; simulations it is best to only include data from 
requests
+               // which go all the way i.e. inserts.
+               node.store(block, false);
                        if(node.random.nextInt(RANDOM_REINSERT_INTERVAL) == 0)
                                node.queueRandomReinsert(block);
        } else if (key instanceof NodeSSK) {

Modified: trunk/freenet/src/freenet/node/Version.java
===================================================================
--- trunk/freenet/src/freenet/node/Version.java 2006-08-05 14:58:53 UTC (rev 
9903)
+++ trunk/freenet/src/freenet/node/Version.java 2006-08-05 15:45:37 UTC (rev 
9904)
@@ -18,7 +18,7 @@
        public static final String protocolVersion = "1.0";

        /** The build number of the current revision */
-       private static final int buildNumber = 927;
+       private static final int buildNumber = 928;

        /** Oldest build of Fred we will talk to */
        private static final int oldLastGoodBuild = 874;

Modified: trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java
===================================================================
--- trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java 2006-08-05 
14:58:53 UTC (rev 9903)
+++ trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java 2006-08-05 
15:45:37 UTC (rev 9904)
@@ -1509,11 +1509,12 @@
        }
     }

-       public void setMaxKeys(long maxStoreKeys) throws DatabaseException, 
IOException {
+       public void setMaxKeys(long maxStoreKeys, boolean shrinkNow) throws 
DatabaseException, IOException {
                synchronized(this) {
                        maxChkBlocks = maxStoreKeys;
                }
-               maybeShrink(false, false);
+               if(shrinkNow)
+                       maybeShrink(false, false);
        }

        public long hits() {

Modified: trunk/freenet/src/freenet/store/FreenetStore.java
===================================================================
--- trunk/freenet/src/freenet/store/FreenetStore.java   2006-08-05 14:58:53 UTC 
(rev 9903)
+++ trunk/freenet/src/freenet/store/FreenetStore.java   2006-08-05 15:45:37 UTC 
(rev 9904)
@@ -54,10 +54,11 @@
     /**
      * Change the store size.
      * @param maxStoreKeys The maximum number of keys to be cached.
+     * @param shrinkNow If false, don't shrink the store immediately.
      * @throws IOException 
      * @throws DatabaseException 
      */
-       public void setMaxKeys(long maxStoreKeys) throws DatabaseException, 
IOException;
+       public void setMaxKeys(long maxStoreKeys, boolean shrinkNow) throws 
DatabaseException, IOException;

        public long hits();



Reply via email to