Author: toad
Date: 2007-03-09 02:55:01 +0000 (Fri, 09 Mar 2007)
New Revision: 12050

Modified:
   trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java
Log:
More datastore fixes.
- Online shrink: Don't do more than one online shrink at once! And don't wait 
for them when changing the maximum store size either.
- Offline shrink: Don't go through maybeSlowShrink checks. Chop off any surplus 
which is entirely empty (e.g. duplicated data).

Modified: trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java
===================================================================
--- trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java 2007-03-09 
02:28:26 UTC (rev 12049)
+++ trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java 2007-03-09 
02:55:01 UTC (rev 12050)
@@ -539,6 +539,8 @@
                                storeFile.createNewFile();
                        chkStore = new RandomAccessFile(storeFile,"rw");

+                       boolean dontCheckOnShrink = false;
+                       
                        long chkBlocksInDatabase = countCHKBlocksFromDatabase();
                        chkBlocksInStore = chkBlocksInDatabase;
                        long chkBlocksFromFile = countCHKBlocksFromFile();
@@ -557,6 +559,7 @@
                                        throw new DatabaseException("Keys in 
database: "+chkBlocksInStore+" but keys in file: "+chkBlocksFromFile);
                                } else if(!noCheck) {
                                        long len = 
checkForHoles(chkBlocksFromFile, false);
+                                       dontCheckOnShrink = true;
                                        if(len < chkBlocksFromFile) {
                                                System.err.println("Truncating 
to "+len+" as no non-holes after that point");
                                                chkStore.setLength(len * 
(dataBlockSize + headerBlockSize));
@@ -570,7 +573,7 @@
                        System.out.println("Keys in store: db 
"+chkBlocksInDatabase+" file "+chkBlocksFromFile+" / max "+maxChkBlocks);

                        if(!noCheck) {
-                               maybeShrink(true, true);
+                               maybeShrink(dontCheckOnShrink, true);
                                chkBlocksFromFile = countCHKBlocksFromFile();
                                chkBlocksInStore = Math.max(chkBlocksInStore, 
chkBlocksFromFile);
                        }
@@ -631,7 +634,12 @@
                return bound;
        }

+       private Object shrinkLock = new Object();
+       private boolean shrinking = false;
+       
        private void maybeShrink(boolean dontCheck, boolean offline) throws 
DatabaseException, IOException {
+               try {
+                       synchronized(shrinkLock) { if(shrinking) return; 
shrinking = true; };
                if(chkBlocksInStore <= maxChkBlocks) return;
                if(offline)
                        maybeSlowShrink(dontCheck, offline);
@@ -643,6 +651,9 @@
                                Logger.error(this, "Online shrink only 
supported for small deltas because online shrink does not preserve LRU order. 
Suggest you restart the node.");
                        }
                }
+               } finally {
+                       synchronized(shrinkLock) { shrinking = false; };
+               }
        }

        private void maybeSlowShrink(boolean dontCheck, boolean inStartUp) 
throws DatabaseException, IOException {
@@ -660,12 +671,15 @@

        System.err.println("Shrinking from "+chkBlocksInStore+" to 
"+maxChkBlocks+" (from db "+countCHKBlocksFromDatabase()+" from file 
"+countCHKBlocksFromFile()+ ')');

-       checkForHoles(maxChkBlocks, true);
+       if(!dontCheck)
+               checkForHoles(maxChkBlocks, true);

        WrapperManager.signalStarting(5*60*1000 + (int)chkBlocksInStore * 100); 
// 10 per second

        long realSize = countCHKBlocksFromFile();

+       long highestBlock = 0;
+       
        try {
                        c = chkDB_accessTime.openCursor(null,null);

@@ -686,6 +700,7 @@
                        while(true) {
                        StoreBlock storeBlock = (StoreBlock) 
storeBlockTupleBinding.entryToObject(blockDBE);
                                long block = storeBlock.offset;
+                               if(block > highestBlock) highestBlock = block;
                                if(storeBlock.offset > Integer.MAX_VALUE) {
                                        // 2^31 * blockSize; ~ 70TB for CHKs, 
2TB for the others
                                        System.err.println("Store too big, 
doing quick shrink"); // memory usage would be insane
@@ -863,6 +878,7 @@
                if(t != null)
                        t.abort();
        }
+       System.out.println("Completing shrink"); // FIXME remove

        // If there are any slots left over, they must be free.
        freeBlocks.clear();
@@ -874,25 +890,38 @@
                }
        }

-       maybeQuickShrink(false, true);
+       System.out.println("Finishing shrink"); // FIXME remove

+       innerQuickShrink(realSize, Math.min(newSize, highestBlock), true, 
dontCheck);
+       
        System.err.println("Shrunk store, now have "+chkBlocksInStore+" of 
"+maxChkBlocks);
        }

+       /**
+        * Shrink the store, on the fly/quickly.
+        * @param dontCheck If true, keep going until the store has shrunk 
enough.
+        * @param dontCheckForHoles
+        * @throws DatabaseException
+        * @throws IOException
+        */
        private void maybeQuickShrink(boolean dontCheck, boolean 
dontCheckForHoles) throws DatabaseException, IOException {
+               // long's are not atomic.
+               long maxBlocks;
+               long curBlocks;
+               synchronized(this) {
+                       maxBlocks = maxChkBlocks;
+                       curBlocks = chkBlocksInStore;
+                       if(maxBlocks >= curBlocks) {
+                               System.out.println("Not shrinking store: 
"+curBlocks+" < "+maxBlocks);
+                               return;
+                       }
+               }
+               innerQuickShrink(curBlocks, maxBlocks, dontCheck, 
dontCheckForHoles);
+       }
+
+       private void innerQuickShrink(long curBlocks, long maxBlocks, boolean 
dontCheck, boolean dontCheckForHoles) throws DatabaseException, IOException {
                Transaction t = null;
                try {
-                       // long's are not atomic.
-                       long maxBlocks;
-                       long curBlocks;
-                       synchronized(this) {
-                               maxBlocks = maxChkBlocks;
-                               curBlocks = chkBlocksInStore;
-                               if(maxBlocks >= curBlocks) {
-                                       System.out.println("Not shrinking 
store: "+curBlocks+" < "+maxBlocks);
-                                       return;
-                               }
-                       }
                        System.err.println("Shrinking store: "+curBlocks+" -> 
"+maxBlocks+" (from db "+countCHKBlocksFromDatabase()+" from file 
"+countCHKBlocksFromFile()+ ')');
                        Logger.error(this, "Shrinking store: "+curBlocks+" -> 
"+maxBlocks+" (from db "+countCHKBlocksFromDatabase()+" from file 
"+countCHKBlocksFromFile()+ ')');
                
WrapperManager.signalStarting((int)Math.min(0,(curBlocks-maxBlocks)*100)+5*60*1000);
 // 10 per second plus 5 minutes
@@ -2101,8 +2130,21 @@
                synchronized(this) {
                        maxChkBlocks = maxStoreKeys;
                }
-               if(shrinkNow)
-                       maybeShrink(false, false);
+               if(shrinkNow) {
+                       Thread t = new Thread(new Runnable() {
+                               public void run() {
+                                       try {
+                                               maybeShrink(false, false);
+                                       } catch (DatabaseException e) {
+                                               Logger.error(this, "Cannot 
shrink: "+e, e);
+                                       } catch (IOException e) {
+                                               Logger.error(this, "Cannot 
shrink: "+e, e);
+                                       }
+                               }
+                       });
+                       t.setDaemon(true);
+                       t.start();
+               }
        }

     public long getMaxKeys() {


Reply via email to