Author: toad
Date: 2007-05-18 17:05:28 +0000 (Fri, 18 May 2007)
New Revision: 13261

Modified:
   trunk/freenet/src/freenet/node/Node.java
   trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java
Log:
Attempt to reconstruct via DbDump -r / DbLoad. Oddly enough this doesn't work 
at the moment. There are more urgent matters to attend to, I'll get back to it 
later.
Anyway create a file called "reconstruct" in the database dir to test.

Modified: trunk/freenet/src/freenet/node/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java    2007-05-18 16:38:58 UTC (rev 
13260)
+++ trunk/freenet/src/freenet/node/Node.java    2007-05-18 17:05:28 UTC (rev 
13261)
@@ -38,6 +38,7 @@
 import com.sleepycat.je.EnvironmentConfig;
 import com.sleepycat.je.EnvironmentMutableConfig;
 import com.sleepycat.je.StatsConfig;
+import com.sleepycat.je.util.DbDump;

 import freenet.client.FetchContext;
 import freenet.config.EnumerableOptionCallback;
@@ -1152,16 +1153,27 @@
                File dbDir = new File(storeDir, "database-"+portNumber);
                dbDir.mkdirs();

+               File reconstructFile = new File(dbDir, "reconstruct");
+               
                Environment env = null;
                EnvironmentMutableConfig mutableConfig;
+               
+               boolean tryDbLoad = false;
+               
+               String suffix = "-" + portNumber;
+               
                // This can take some time
                System.out.println("Starting database...");
                try {
+                       if(reconstructFile.exists()) {
+                               reconstructFile.delete();
+                               throw new DatabaseException();
+                       }
                        env = new Environment(dbDir, envConfig);
                        mutableConfig = env.getConfig();
                } catch (DatabaseException e) {
-                       // The database is broken
-                       // We will have to recover from scratch
+
+                       // Close the database
                        if(env != null) {
                                try {
                                        env.close();
@@ -1170,13 +1182,71 @@
                                        t.printStackTrace();
                                }
                        }
+                       
+                       // First try DbDump
+                       
+                       boolean failed = false;
+                       
+                       System.err.println("Attempting DbDump-level 
recovery...");
+                       
+                       boolean[] isStores = new boolean[] { true, false, true, 
false, true, false };
+                       short[] types = new short[] { 
+                                       BerkeleyDBFreenetStore.TYPE_CHK,
+                                       BerkeleyDBFreenetStore.TYPE_CHK,
+                                       BerkeleyDBFreenetStore.TYPE_PUBKEY,
+                                       BerkeleyDBFreenetStore.TYPE_PUBKEY,
+                                       BerkeleyDBFreenetStore.TYPE_SSK,
+                                       BerkeleyDBFreenetStore.TYPE_SSK
+                       };
+                       int[] lengths = new int[] {
+                                       CHKBlock.TOTAL_HEADERS_LENGTH + 
CHKBlock.DATA_LENGTH,
+                                       CHKBlock.TOTAL_HEADERS_LENGTH + 
CHKBlock.DATA_LENGTH,
+                                       DSAPublicKey.PADDED_SIZE,
+                                       DSAPublicKey.PADDED_SIZE,
+                                       SSKBlock.TOTAL_HEADERS_LENGTH + 
SSKBlock.DATA_LENGTH,
+                                       SSKBlock.TOTAL_HEADERS_LENGTH + 
SSKBlock.DATA_LENGTH
+                       };
+                       
+                       for(int i=0;i<types.length;i++) {
+                               boolean isStore = isStores[i];
+                               short type = types[i];
+                               String dbName = 
BerkeleyDBFreenetStore.getName(isStore, type);
+                               File dbFile = 
BerkeleyDBFreenetStore.getFile(isStore, type, storeDir, suffix);
+                               long keyCount = dbFile.length() / lengths[i];
+                               // This is *slow* :(
+                               int millis = (int)Math.min(24*60*60*1000 /* 
horrible hack, because of the wrapper's braindead timeout additions */, 
+                                               5*60*1000 + (Math.max(keyCount, 
1) * 10000));
+                               WrapperManager.signalStarting(millis);
+                               try {
+                                       File target = new File(storeDir, 
dbName+".dump");
+                                       System.err.println("Dumping "+dbName+" 
to "+target+" ("+keyCount+" keys from file, allowing "+millis+"ms)");
+                                       DbDump.main(new String[] { "-r", "-h", 
dbDir.toString(), 
+                                                       "-s", dbName, "-f", 
target.toString() });
+                               } catch (DatabaseException e2) {
+                                       System.err.println("DbDump recovery 
failed for "+dbName+" : "+e2);
+                                       e2.printStackTrace();
+                               } catch (IOException e2) {
+                                       System.err.println("DbDump recovery 
failed for "+dbName+" : "+e2);
+                                       e2.printStackTrace();
+                               }
+                               tryDbLoad = true;
+                       }
+                       
+                       // Delete the database logs
+                       
+                       System.err.println("Deleting old database log 
files...");
+                       
                        File[] files = dbDir.listFiles();
                        for(int i=0;i<files.length;i++) {
                                String name = files[i].getName().toLowerCase();
                                if(name.endsWith(".jdb") || 
name.equals("je.lck"))
-                                       files[i].delete();
+                                       if(!files[i].delete())
+                                               System.err.println("Failed to 
delete old database log file "+files[i]);
                        }
-                       dbDir.delete();
+                       
+                       System.err.println("Recovering...");
+                       // The database is broken
+                       // We will have to recover from scratch
                        try {
                                env = new Environment(dbDir, envConfig);
                                mutableConfig = env.getConfig();
@@ -1253,34 +1323,32 @@
                        throw new NodeInitException(EXIT_STORE_OTHER, 
e.getMessage());                  
                }

-               String suffix = "-" + portNumber;
-               
                try {
                        Logger.normal(this, "Initializing CHK Datastore");
                        System.out.println("Initializing CHK Datastore 
("+maxStoreKeys+" keys)");
                        chkDatastore = 
BerkeleyDBFreenetStore.construct(lastVersion, storeDir, true, suffix, 
maxStoreKeys, 
-                                       CHKBlock.DATA_LENGTH, 
CHKBlock.TOTAL_HEADERS_LENGTH, true, BerkeleyDBFreenetStore.TYPE_CHK, 
storeEnvironment, random, storeShutdownHook);
+                                       CHKBlock.DATA_LENGTH, 
CHKBlock.TOTAL_HEADERS_LENGTH, true, BerkeleyDBFreenetStore.TYPE_CHK, 
storeEnvironment, random, storeShutdownHook, tryDbLoad, reconstructFile);
                        Logger.normal(this, "Initializing CHK Datacache");
                        System.out.println("Initializing CHK Datacache 
("+maxCacheKeys+ ':' +maxCacheKeys+" keys)");
                        chkDatacache = 
BerkeleyDBFreenetStore.construct(lastVersion, storeDir, false, suffix, 
maxCacheKeys, 
-                                       CHKBlock.DATA_LENGTH, 
CHKBlock.TOTAL_HEADERS_LENGTH, true, BerkeleyDBFreenetStore.TYPE_CHK, 
storeEnvironment, random, storeShutdownHook);
+                                       CHKBlock.DATA_LENGTH, 
CHKBlock.TOTAL_HEADERS_LENGTH, true, BerkeleyDBFreenetStore.TYPE_CHK, 
storeEnvironment, random, storeShutdownHook, tryDbLoad, reconstructFile);
                        Logger.normal(this, "Initializing pubKey Datastore");
                        System.out.println("Initializing pubKey Datastore");
                        pubKeyDatastore = 
BerkeleyDBFreenetStore.construct(lastVersion, storeDir, true, suffix, 
maxStoreKeys, 
-                                       DSAPublicKey.PADDED_SIZE, 0, true, 
BerkeleyDBFreenetStore.TYPE_PUBKEY, storeEnvironment, random, 
storeShutdownHook);
+                                       DSAPublicKey.PADDED_SIZE, 0, true, 
BerkeleyDBFreenetStore.TYPE_PUBKEY, storeEnvironment, random, 
storeShutdownHook, tryDbLoad, reconstructFile);
                        Logger.normal(this, "Initializing pubKey Datacache");
                        System.out.println("Initializing pubKey Datacache 
("+maxCacheKeys+" keys)");
                        pubKeyDatacache = 
BerkeleyDBFreenetStore.construct(lastVersion, storeDir, false, suffix, 
maxCacheKeys, 
-                                       DSAPublicKey.PADDED_SIZE, 0, true, 
BerkeleyDBFreenetStore.TYPE_PUBKEY, storeEnvironment, random, 
storeShutdownHook);
+                                       DSAPublicKey.PADDED_SIZE, 0, true, 
BerkeleyDBFreenetStore.TYPE_PUBKEY, storeEnvironment, random, 
storeShutdownHook, tryDbLoad, reconstructFile);
                        // FIXME can't auto-fix SSK stores.
                        Logger.normal(this, "Initializing SSK Datastore");
                        System.out.println("Initializing SSK Datastore");
                        sskDatastore = 
BerkeleyDBFreenetStore.construct(lastVersion, storeDir, true, suffix, 
maxStoreKeys, 
-                                       SSKBlock.DATA_LENGTH, 
SSKBlock.TOTAL_HEADERS_LENGTH, false, BerkeleyDBFreenetStore.TYPE_SSK, 
storeEnvironment, random, storeShutdownHook);
+                                       SSKBlock.DATA_LENGTH, 
SSKBlock.TOTAL_HEADERS_LENGTH, false, BerkeleyDBFreenetStore.TYPE_SSK, 
storeEnvironment, random, storeShutdownHook, tryDbLoad, reconstructFile);
                        Logger.normal(this, "Initializing SSK Datacache");
                        System.out.println("Initializing SSK Datacache 
("+maxCacheKeys+" keys)");
                        sskDatacache = 
BerkeleyDBFreenetStore.construct(lastVersion, storeDir, false, suffix, 
maxStoreKeys, 
-                                       SSKBlock.DATA_LENGTH, 
SSKBlock.TOTAL_HEADERS_LENGTH, false, BerkeleyDBFreenetStore.TYPE_SSK, 
storeEnvironment, random, storeShutdownHook);
+                                       SSKBlock.DATA_LENGTH, 
SSKBlock.TOTAL_HEADERS_LENGTH, false, BerkeleyDBFreenetStore.TYPE_SSK, 
storeEnvironment, random, storeShutdownHook, tryDbLoad, reconstructFile);
                } catch (FileNotFoundException e1) {
                        String msg = "Could not open datastore: "+e1;
                        Logger.error(this, msg, e1);

Modified: trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java
===================================================================
--- trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java 2007-05-18 
16:38:58 UTC (rev 13260)
+++ trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java 2007-05-18 
17:05:28 UTC (rev 13261)
@@ -1,9 +1,12 @@
 package freenet.store;

+import java.io.BufferedReader;
 import java.io.EOFException;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.io.InputStreamReader;
 import java.io.RandomAccessFile;
 import java.util.Arrays;
 import java.util.Vector;
@@ -28,6 +31,7 @@
 import com.sleepycat.je.SecondaryDatabase;
 import com.sleepycat.je.SecondaryKeyCreator;
 import com.sleepycat.je.Transaction;
+import com.sleepycat.je.util.DbLoad;

 import freenet.crypt.CryptFormatException;
 import freenet.crypt.DSAPublicKey;
@@ -59,6 +63,8 @@

        private static boolean logMINOR;

+       // If we get a DbChecksumException, create this file.
+       final File reconstructFile;
        final int dataBlockSize;
        final int headerBlockSize;

@@ -85,8 +91,20 @@
        private boolean reallyClosed;
        private final static byte[] dummy = new byte[0];

+       public static String getName(boolean isStore, short type) {
+               String newDBPrefix = newTypeName(type)+ '-' +(isStore ? "store" 
: "cache")+ '-';
+               return newDBPrefix + "CHK";
+       }
+       
+       public static File getFile(boolean isStore, short type, File 
baseStoreDir, String suffix) {
+               String newStoreFileName = newTypeName(type) + suffix + '.' + 
(isStore ? "store" : "cache");
+               return new File(baseStoreDir, newStoreFileName);
+       }
+       
        public static BerkeleyDBFreenetStore construct(int lastVersion, File 
baseStoreDir, boolean isStore,
-                       String suffix, long maxStoreKeys, int blockSize, int 
headerSize, boolean throwOnTooFewKeys, short type, Environment 
storeEnvironment, RandomSource random, SemiOrderedShutdownHook 
storeShutdownHook) throws DatabaseException, IOException {
+                       String suffix, long maxStoreKeys, int blockSize, int 
headerSize, boolean throwOnTooFewKeys, 
+                       short type, Environment storeEnvironment, RandomSource 
random, 
+                       SemiOrderedShutdownHook storeShutdownHook, boolean 
tryDbLoad, File reconstructFile) throws DatabaseException, IOException {

                /**
                * Migration strategy:
@@ -129,8 +147,8 @@
                        // Try to load new database, reconstruct it if 
necessary.
                        // Don't need to create a new Environment, since we can 
use the old one.

-                       tmp = openStore(storeEnvironment, newDBPrefix, 
newStoreFile, newFixSecondaryFile, maxStoreKeys,
-                                       blockSize, headerSize, 
throwOnTooFewKeys, false, lastVersion, type, false, storeShutdownHook);
+                       tmp = openStore(storeEnvironment, baseStoreDir, 
newDBPrefix, newStoreFile, newFixSecondaryFile, maxStoreKeys,
+                                       blockSize, headerSize, 
throwOnTooFewKeys, false, lastVersion, type, false, storeShutdownHook, 
tryDbLoad, reconstructFile);

                } else if(oldDir.exists() && oldStoreFile.exists()) {

@@ -180,8 +198,9 @@

                                // Open the new store
                                // Don't reconstruct yet
-                               tmp = openStore(storeEnvironment, newDBPrefix, 
storeFile, newFixSecondaryFile, maxStoreKeys,
-                                                       blockSize, headerSize, 
false, true, lastVersion, type, true, storeShutdownHook);
+                               tmp = openStore(storeEnvironment, baseStoreDir, 
newDBPrefix, storeFile, newFixSecondaryFile, 
+                                               maxStoreKeys, blockSize, 
headerSize, false, true, lastVersion, type, true, 
+                                               storeShutdownHook, tryDbLoad, 
reconstructFile);

                                // Migrate all tuples from old database to new 
database.
                                migrateTuples(oldEnv, oldChkDB, tmp);
@@ -198,7 +217,9 @@

                                        // Reconstruct

-                                       tmp = new 
BerkeleyDBFreenetStore(storeEnvironment, newDBPrefix, newStoreFile, 
newFixSecondaryFile, maxStoreKeys, blockSize, headerSize, type, true, 
storeShutdownHook);
+                                       tmp = new 
BerkeleyDBFreenetStore(storeEnvironment, newDBPrefix, newStoreFile, 
+                                                       newFixSecondaryFile, 
maxStoreKeys, blockSize, headerSize, type, true, 
+                                                       storeShutdownHook, 
reconstructFile);
                                }

                                tmp.checkForHoles(tmp.countCHKBlocksFromFile(), 
false);
@@ -210,8 +231,9 @@
                                // No old database to worry about.
                                // Reconstruct the new database from the store 
file which is now in the right place.

-                               tmp = openStore(storeEnvironment, newDBPrefix, 
storeFile, newFixSecondaryFile, maxStoreKeys,
-                                               blockSize, headerSize, 
throwOnTooFewKeys, false, lastVersion, type, false, storeShutdownHook);
+                               tmp = openStore(storeEnvironment, baseStoreDir, 
newDBPrefix, storeFile, newFixSecondaryFile, 
+                                               maxStoreKeys, blockSize, 
headerSize, throwOnTooFewKeys, false, lastVersion, type, 
+                                               false, storeShutdownHook, 
tryDbLoad, reconstructFile);

                        }

@@ -220,8 +242,9 @@
                        // No new store file, no new database.
                        // Start from scratch, with new store.

-                       tmp = openStore(storeEnvironment, newDBPrefix, 
newStoreFile, newFixSecondaryFile, maxStoreKeys,
-                                       blockSize, headerSize, 
throwOnTooFewKeys, false, lastVersion, type, false, storeShutdownHook);
+                       tmp = openStore(storeEnvironment, baseStoreDir, 
newDBPrefix, newStoreFile, newFixSecondaryFile, 
+                                       maxStoreKeys, blockSize, headerSize, 
throwOnTooFewKeys, false, lastVersion, type, 
+                                       false, storeShutdownHook, tryDbLoad, 
reconstructFile);

                }

@@ -328,13 +351,38 @@

        }

-       private static BerkeleyDBFreenetStore openStore(Environment 
storeEnvironment, String newDBPrefix, File newStoreFile,
+       private static BerkeleyDBFreenetStore openStore(Environment 
storeEnvironment, File baseDir, String newDBPrefix, File newStoreFile,
                        File newFixSecondaryFile, long maxStoreKeys, int 
blockSize, int headerSize, boolean throwOnTooFewKeys,
-                       boolean noCheck, int lastVersion, short type, boolean 
wipe, SemiOrderedShutdownHook storeShutdownHook) throws DatabaseException, 
IOException {
+                       boolean noCheck, int lastVersion, short type, boolean 
wipe, SemiOrderedShutdownHook storeShutdownHook, 
+                       boolean tryDbLoad, File reconstructFile) throws 
DatabaseException, IOException {

+               if(tryDbLoad) {
+                       String dbName = newDBPrefix+"CHK";
+                       File dumpFilename = new File(baseDir, dbName+".dump");
+                       System.err.println("Trying to restore from 
"+dumpFilename);
+                       try {
+                               FileInputStream fis = new 
FileInputStream(dumpFilename);
+                               // DbDump used the default charset, so will 
this.
+                               BufferedReader br = new BufferedReader(new 
InputStreamReader(fis));
+                               DbLoad loader = new DbLoad();
+                               loader.setEnv(storeEnvironment);
+                               loader.setDbName(dbName);
+                               loader.setInputReader(br);
+                               loader.setNoOverwrite(false);
+                               loader.setTextFileMode(false);
+                               loader.load();
+                               fis.close();
+                               newFixSecondaryFile.createNewFile(); // force 
reconstruct of secondary indexes
+                       } catch (IOException e) {
+                               System.err.println("Failed to reload database 
"+dbName+": "+e);
+                               e.printStackTrace();
+                       }
+               }
+               
                try {
                        return new BerkeleyDBFreenetStore(storeEnvironment, 
newDBPrefix, newStoreFile, newFixSecondaryFile,
-                                       maxStoreKeys, blockSize, headerSize, 
throwOnTooFewKeys, noCheck, wipe, storeShutdownHook);
+                                       maxStoreKeys, blockSize, headerSize, 
throwOnTooFewKeys, noCheck, wipe, storeShutdownHook, 
+                                       reconstructFile);
                } catch (DatabaseException e) {

                        System.err.println("Could not open store: "+e);
@@ -350,7 +398,8 @@

                        // Reconstruct

-                       return new BerkeleyDBFreenetStore(storeEnvironment, 
newDBPrefix, newStoreFile, newFixSecondaryFile, maxStoreKeys, blockSize, 
headerSize, type, noCheck, storeShutdownHook);
+                       return new BerkeleyDBFreenetStore(storeEnvironment, 
newDBPrefix, newStoreFile, newFixSecondaryFile, 
+                                       maxStoreKeys, blockSize, headerSize, 
type, noCheck, storeShutdownHook, reconstructFile);
                }
        }

@@ -423,12 +472,13 @@
        * Initializes database
        * @param noCheck If true, don't check for holes etc.
        * @param wipe If true, wipe the database first.
+        * @param reconstructFile 
        * @param the directory where the store is located
        * @throws IOException
        * @throws DatabaseException
        * @throws FileNotFoundException if the dir does not exist and could not 
be created
        */
-       public BerkeleyDBFreenetStore(Environment env, String prefix, File 
storeFile, File fixSecondaryFile, long maxChkBlocks, int blockSize, int 
headerSize, boolean throwOnTooFewKeys, boolean noCheck, boolean wipe, 
SemiOrderedShutdownHook storeShutdownHook) throws IOException, 
DatabaseException {
+       public BerkeleyDBFreenetStore(Environment env, String prefix, File 
storeFile, File fixSecondaryFile, long maxChkBlocks, int blockSize, int 
headerSize, boolean throwOnTooFewKeys, boolean noCheck, boolean wipe, 
SemiOrderedShutdownHook storeShutdownHook, File reconstructFile) throws 
IOException, DatabaseException {
                logMINOR = Logger.shouldLog(Logger.MINOR, this);
                this.dataBlockSize = blockSize;
                this.headerBlockSize = headerSize;
@@ -436,6 +486,7 @@
                name = prefix;

                this.maxChkBlocks=maxChkBlocks;
+               this.reconstructFile = reconstructFile;

                environment = env;

@@ -549,11 +600,12 @@
                        new BlockNumberKeyCreator(storeBlockTupleBinding);
                blockNoDbConfig.setKeyCreator(bnkc);
                SecondaryDatabase blockNums = null;
+               String blockDBName = prefix+"CHK_blockNum";
                try {
                try {
                        System.err.println("Opening block db index");
                        blockNums = environment.openSecondaryDatabase
-                               (null, prefix+"CHK_blockNum", chkDB, 
blockNoDbConfig);
+                               (null, blockDBName, chkDB, blockNoDbConfig);
                        // The below is too slow to be useful, because 
SecondaryDatabase.count() isn't optimised.
 //                     long blockNumsCount = blockNums.count();
 //                     long chkDBCount = chkDB.count();
@@ -568,20 +620,24 @@
                        // Either we find out what the maximum value is and we 
do a static method somewhere ensuring
                        // it won't overflow ... or we debug the wrapper.
                        // NB: it might be a wrapper-version-missmatch problem 
(nextgens)
-                       if(blockNums != null) blockNums.close();
+                       if(blockNums != null) {
+                               Logger.normal(this, "Closing database 
"+blockDBName);
+                               blockNums.close();
+                       }
                        try {
-                               environment.removeDatabase(null, 
prefix+"CHK_blockNum");
+                               environment.removeDatabase(null, blockDBName);
                        } catch (DatabaseNotFoundException e1) {
                                // Ignore
+                               System.err.println("Database "+blockDBName+" 
does not exist deleting it");
                        }
-                       System.err.println("Reconstructing block numbers 
index...");
-                       Logger.error(this, "Reconstructing block numbers 
index...");
+                       System.err.println("Reconstructing block numbers 
index... ("+e+")");
+                       Logger.error(this, "Reconstructing block numbers 
index...", e);
                        System.err.println("Creating new block DB index");
-                       blockNoDbConfig.setSortedDuplicates(false);
+                       blockNoDbConfig.setSortedDuplicates(true);
                        blockNoDbConfig.setAllowCreate(true);
                        blockNoDbConfig.setAllowPopulate(true);
                        blockNums = environment.openSecondaryDatabase
-                               (null, prefix+"CHK_blockNum", chkDB, 
blockNoDbConfig);
+                               (null, blockDBName, chkDB, blockNoDbConfig);
                }
                } catch (DatabaseException e1) {
                        // Log this now because close() will probably throw too
@@ -1131,18 +1187,20 @@

        /**
        * Recreate the index from the data file. Call this when the index has 
been corrupted.
+        * @param reconstructFile 
        * @param the directory where the store is located
        * @throws DatabaseException If the store cannot be opened because of a 
database problem.
        * @throws IOException If the store cannot be opened because of a 
filesystem problem.
        * @throws FileNotFoundException if the dir does not exist and could not 
be created
        */
-       public BerkeleyDBFreenetStore(Environment env, String prefix, File 
storeFile, File fixSecondaryFile, long maxChkBlocks, int blockSize, int 
headerSize, short type, boolean noCheck, SemiOrderedShutdownHook 
storeShutdownHook) throws DatabaseException, IOException {
+       public BerkeleyDBFreenetStore(Environment env, String prefix, File 
storeFile, File fixSecondaryFile, long maxChkBlocks, int blockSize, int 
headerSize, short type, boolean noCheck, SemiOrderedShutdownHook 
storeShutdownHook, File reconstructFile) throws DatabaseException, IOException {
                logMINOR = Logger.shouldLog(Logger.MINOR, this);
                this.dataBlockSize = blockSize;
                this.headerBlockSize = headerSize;
                this.freeBlocks = new SortedLongSet();
                this.maxChkBlocks=maxChkBlocks;
                this.environment = env;
+               this.reconstructFile = reconstructFile;
                name = prefix;

                wipeOldDatabases(prefix);


Reply via email to