Author: toad
Date: 2006-07-01 14:46:32 +0000 (Sat, 01 Jul 2006)
New Revision: 9414

Modified:
   trunk/freenet/src/freenet/keys/CHKBlock.java
   trunk/freenet/src/freenet/keys/SSKBlock.java
   trunk/freenet/src/freenet/node/Node.java
   trunk/freenet/src/freenet/node/Version.java
   trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java
Log:
846: Attempt to auto-fix broken datastores.

Modified: trunk/freenet/src/freenet/keys/CHKBlock.java
===================================================================
--- trunk/freenet/src/freenet/keys/CHKBlock.java        2006-07-01 13:55:22 UTC 
(rev 9413)
+++ trunk/freenet/src/freenet/keys/CHKBlock.java        2006-07-01 14:46:32 UTC 
(rev 9414)
@@ -47,9 +47,11 @@
         if(headers.length != TOTAL_HEADERS_LENGTH)
                throw new IllegalArgumentException("Wrong length: 
"+headers.length+" should be "+TOTAL_HEADERS_LENGTH);
         hashIdentifier = (short)(((headers[0] & 0xff) << 8) + (headers[1] & 
0xff));
-        this.chk = key;
 //        Logger.debug(CHKBlock.class, "Data length: "+data.length+", header 
length: "+header.length);
-        if(!verify) return;
+        if(key != null && !verify) {
+               this.chk = key;
+               return;
+        }

         // Minimal verification
         // Check the hash
@@ -65,11 +67,16 @@
         md.update(headers);
         md.update(data);
         byte[] hash = md.digest();
-        byte[] check = chk.routingKey;
-        if(!java.util.Arrays.equals(hash, check)) {
-            throw new CHKVerifyException("Hash does not verify");
+        if(key == null) {
+               chk = new NodeCHK(hash);
+        } else {
+               chk = key;
+            byte[] check = chk.routingKey;
+            if(!java.util.Arrays.equals(hash, check)) {
+                throw new CHKVerifyException("Hash does not verify");
+            }
+            // Otherwise it checks out
         }
-        // Otherwise it checks out
     }

        public Key getKey() {

Modified: trunk/freenet/src/freenet/keys/SSKBlock.java
===================================================================
--- trunk/freenet/src/freenet/keys/SSKBlock.java        2006-07-01 13:55:22 UTC 
(rev 9413)
+++ trunk/freenet/src/freenet/keys/SSKBlock.java        2006-07-01 14:46:32 UTC 
(rev 9414)
@@ -85,9 +85,9 @@
                this.data = data;
                this.headers = headers;
                this.nodeKey = nodeKey;
-               this.pubKey = nodeKey.getPubKey();
                if(data.length != DATA_LENGTH)
                        throw new SSKVerifyException("Data length wrong: 
"+data.length+" should be "+DATA_LENGTH);
+               this.pubKey = nodeKey.getPubKey();
                if(pubKey == null)
                        throw new SSKVerifyException("PubKey was null from 
"+nodeKey);
         MessageDigest md;

Modified: trunk/freenet/src/freenet/node/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java    2006-07-01 13:55:22 UTC (rev 
9413)
+++ trunk/freenet/src/freenet/node/Node.java    2006-07-01 14:46:32 UTC (rev 
9414)
@@ -29,6 +29,8 @@

 import org.tanukisoftware.wrapper.WrapperManager;

+import com.sleepycat.je.DatabaseException;
+
 import freenet.client.ArchiveManager;
 import freenet.client.ClientMetadata;
 import freenet.client.FetchException;
@@ -1370,13 +1372,25 @@
                try {
                        Logger.normal(this, "Initializing CHK Datastore");
                        System.out.println("Initializing CHK Datastore");
-                       chkDatastore = new 
BerkeleyDBFreenetStore(storeDir.getPath()+File.separator+"store-"+portNumber, 
maxStoreKeys, 32768, CHKBlock.TOTAL_HEADERS_LENGTH);
+                       BerkeleyDBFreenetStore tmp;
+                       try {
+                               tmp = new 
BerkeleyDBFreenetStore(storeDir.getPath()+File.separator+"store-"+portNumber, 
maxStoreKeys, 32768, CHKBlock.TOTAL_HEADERS_LENGTH);
+                       } catch (DatabaseException e) {
+                               tmp = new 
BerkeleyDBFreenetStore(storeDir.getPath()+File.separator+"store-"+portNumber, 
maxStoreKeys, 32768, CHKBlock.TOTAL_HEADERS_LENGTH, 
BerkeleyDBFreenetStore.TYPE_CHK);
+                       }
+                       chkDatastore = tmp;
+                       Logger.normal(this, "Initializing pubKey Datastore");
+                       System.out.println("Initializing pubKey Datastore");
+                       try {
+                               tmp = new 
BerkeleyDBFreenetStore(storeDir.getPath()+File.separator+"pubkeystore-"+portNumber,
 maxStoreKeys, DSAPublicKey.PADDED_SIZE, 0);
+                       } catch (DatabaseException e) {
+                               tmp = new 
BerkeleyDBFreenetStore(storeDir.getPath()+File.separator+"pubkeystore-"+portNumber,
 maxStoreKeys, DSAPublicKey.PADDED_SIZE, 0, BerkeleyDBFreenetStore.TYPE_PUBKEY);
+                       }
+                       this.pubKeyDatastore = tmp;
+                       // FIXME can't auto-fix SSK stores.
                        Logger.normal(this, "Initializing SSK Datastore");
                        System.out.println("Initializing SSK Datastore");
                        sskDatastore = new 
BerkeleyDBFreenetStore(storeDir.getPath()+File.separator+"sskstore-"+portNumber,
 maxStoreKeys, 1024, SSKBlock.TOTAL_HEADERS_LENGTH);
-                       Logger.normal(this, "Initializing pubKey Datastore");
-                       System.out.println("Initializing pubKey Datastore");
-                       pubKeyDatastore = new 
BerkeleyDBFreenetStore(storeDir.getPath()+File.separator+"pubkeystore-"+portNumber,
 maxStoreKeys, DSAPublicKey.PADDED_SIZE, 0);
                } catch (FileNotFoundException e1) {
                        String msg = "Could not open datastore: "+e1;
                        Logger.error(this, msg, e1);

Modified: trunk/freenet/src/freenet/node/Version.java
===================================================================
--- trunk/freenet/src/freenet/node/Version.java 2006-07-01 13:55:22 UTC (rev 
9413)
+++ trunk/freenet/src/freenet/node/Version.java 2006-07-01 14:46:32 UTC (rev 
9414)
@@ -18,7 +18,7 @@
        public static final String protocolVersion = "1.0";

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

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

Modified: trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java
===================================================================
--- trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java 2006-07-01 
13:55:22 UTC (rev 9413)
+++ trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java 2006-07-01 
14:46:32 UTC (rev 9414)
@@ -1,5 +1,6 @@
 package freenet.store;

+import java.io.EOFException;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -182,8 +183,173 @@
 //              Add shutdownhook
                Runtime.getRuntime().addShutdownHook(new ShutdownHook());
        }
+
+       public static final short TYPE_CHK = 0;
+       public static final short TYPE_PUBKEY = 1;
+       public static final short TYPE_SSK = 2;

        /**
+     * Recreate the index from the data file. Call this when the index has 
been corrupted.
+     * @param the directory where the store is located
+     * @throws FileNotFoundException if the dir does not exist and could not 
be created
+     */
+       public BerkeleyDBFreenetStore(String storeDir, long maxChkBlocks, int 
blockSize, int headerSize, short type) throws Exception {
+               this.dataBlockSize = blockSize;
+               this.headerBlockSize = headerSize;
+               // Percentage of the database that must contain usefull data
+               // decrease to increase performance, increase to save disk space
+               System.setProperty("je.cleaner.minUtilization","98");
+               
+               // Delete empty log files
+               System.setProperty("je.cleaner.expunge","true");
+               
+               // Percentage of the maximum heap size used as a cache
+               System.setProperty("je.maxMemoryPercent","30");
+               
+               this.maxChkBlocks=maxChkBlocks;
+               
+               // Delete old database.
+               
+               File dir = new File(storeDir);
+               if(!dir.exists())
+                       dir.mkdir();
+               File dbDir = new File(dir,"database");
+               if(dbDir.exists()) {
+                       File[] files = dbDir.listFiles();
+                       for(int i=0;i<files.length;i++)
+                               files[i].delete();
+               } else
+                       dbDir.mkdir();
+               
+               // Now create a new one.
+               
+               // Initialize environment
+               EnvironmentConfig envConfig = new EnvironmentConfig();
+               envConfig.setAllowCreate(true);
+               envConfig.setTransactional(true);
+               envConfig.setTxnWriteNoSync(true);
+
+               environment = new Environment(dbDir, envConfig);
+               
+               // Initialize CHK database
+               DatabaseConfig dbConfig = new DatabaseConfig();
+               dbConfig.setAllowCreate(true);
+               dbConfig.setTransactional(true);
+               chkDB = environment.openDatabase(null,"CHK",dbConfig);
+               
+               fixSecondaryFile = new File(storeDir, "recreate_secondary_db");
+               fixSecondaryFile.delete();
+               
+               // Initialize secondary CHK database sorted on accesstime
+               SecondaryConfig secDbConfig = new SecondaryConfig();
+               secDbConfig.setAllowCreate(true);
+               secDbConfig.setSortedDuplicates(true);
+               secDbConfig.setTransactional(true);
+               secDbConfig.setAllowPopulate(true);
+               storeBlockTupleBinding = new StoreBlockTupleBinding();
+               longTupleBinding = TupleBinding.getPrimitiveBinding(Long.class);
+               AccessTimeKeyCreator accessTimeKeyCreator = 
+                       new AccessTimeKeyCreator(storeBlockTupleBinding);
+               secDbConfig.setKeyCreator(accessTimeKeyCreator);
+               chkDB_accessTime = environment.openSecondaryDatabase
+                                                       (null, 
"CHK_accessTime", chkDB, secDbConfig);
+               
+               // Initialize other secondary database sorted on block number
+//             try {
+//                     environment.removeDatabase(null, "CHK_blockNum");
+//             } catch (DatabaseNotFoundException e) { };
+               SecondaryConfig blockNoDbConfig = new SecondaryConfig();
+               blockNoDbConfig.setAllowCreate(true);
+               blockNoDbConfig.setSortedDuplicates(false);
+               blockNoDbConfig.setAllowPopulate(true);
+               blockNoDbConfig.setTransactional(true);
+               
+               BlockNumberKeyCreator bnkc = 
+                       new BlockNumberKeyCreator(storeBlockTupleBinding);
+               blockNoDbConfig.setKeyCreator(bnkc);
+               SecondaryDatabase blockNums;
+               System.err.println("Creating block db index");
+               chkDB_blockNum = environment.openSecondaryDatabase
+                       (null, "CHK_blockNum", chkDB, blockNoDbConfig);
+               
+               // Initialize the store file
+               File storeFile = new File(dir,"store");
+               if(!storeFile.exists())
+                       storeFile.createNewFile();
+               chkStore = new RandomAccessFile(storeFile,"rw");
+               
+               chkBlocksInStore = 0;
+               
+               lastRecentlyUsed = 0;
+               
+               reconstruct(type, storeDir);
+                       
+               chkBlocksInStore = countCHKBlocks();
+               lastRecentlyUsed = getMaxRecentlyUsed();
+               
+//              Add shutdownhook
+               Runtime.getRuntime().addShutdownHook(new ShutdownHook());
+       }
+       
+       private void reconstruct(short type, String storeDir) throws 
DatabaseException {
+               if(type == TYPE_SSK) {
+                       System.err.println("Reconstruction of SSK store not 
supported at present.");
+                       throw new UnsupportedOperationException("Reconstruction 
of SSK store not supported at present.");
+                       // FIXME we would need to pass in a means to fetch the 
pubkeys (an already-working BDBFS maybe).
+                       // This could be via an interface. It might be 
implemented by the node so we can use the in-RAM cache.
+               }
+               System.err.println("Reconstructing store index from store file: 
type="+type);
+               Logger.error(this, "Reconstructing store index from store file: 
type="+type);
+               byte[] header = new byte[headerBlockSize];
+               byte[] data = new byte[dataBlockSize];
+               try {
+                       chkStore.seek(0);
+                       long l = 0;
+                       while(true) {
+                               Transaction t = null;
+                               try {
+                                       chkStore.readFully(header);
+                                       chkStore.readFully(data);
+                                       byte[] routingkey = null;
+                                       if(type == TYPE_CHK) {
+                                               try {
+                                                       CHKBlock chk = new 
CHKBlock(header, data, null);
+                                                       routingkey = 
chk.getKey().getRoutingKey();
+                                               } catch (CHKVerifyException e) {
+                                                       Logger.error(this, 
"Bogus key at slot "+l+" : "+e, e);
+                                               }
+                                       } else if(type == TYPE_PUBKEY) {
+                                               DSAPublicKey key = new 
DSAPublicKey(data);
+                                               routingkey = key.asBytesHash();
+                                       } else {
+                                               l++;
+                                               continue;
+                                       }
+                                       t = 
environment.beginTransaction(null,null);
+                                       long blockNum = chkBlocksInStore++;
+                                       StoreBlock storeBlock = new 
StoreBlock(blockNum);
+                                       DatabaseEntry routingkeyDBE = new 
DatabaseEntry(routingkey);
+                                       DatabaseEntry blockDBE = new 
DatabaseEntry();
+                                       
storeBlockTupleBinding.objectToEntry(storeBlock, blockDBE);
+                                       chkDB.put(t,routingkeyDBE,blockDBE);
+                                       t.commit();
+                                       t = null;
+                               } finally {
+                                       l++;
+                                       if(t != null) t.abort();
+                               }
+                       }
+               } catch (EOFException e) {
+                       migrate(storeDir);
+                       return;
+               } catch (IOException e) {
+                       Logger.error(this, "Caught "+e, e);
+                       throw new Error(e);
+                       // What else can we do? FIXME
+               }
+       }
+
+       /**
         * Migrate from a store which didn't have a unique index on blockNum, 
to one which does.
         * How do we do this? We scan through all entries (slow), we fetch each 
key, delete all data's
         * under it, and then insert the one we are looking at.


Reply via email to