From: <tho...@us...> - 2011-03-14 18:17:38
|
Revision: 4298 http://bigdata.svn.sourceforge.net/bigdata/?rev=4298&view=rev Author: thompsonbry Date: 2011-03-14 18:17:32 +0000 (Mon, 14 Mar 2011) Log Message: ----------- Added an option (com.bigdata.journal.Options.INGORE_BAD_ROOT_BLOCK) in the QUADS_QUERY_BRANCH which may be used to permit a Journal with ONE (1) bad root block to be opened using the other root block. The ALTERNATE_ROOT_BLOCK option is only permitted when both root blocks are valid, but there is a reason to revert to the previous root block anyway. The IGNORE_BAD_ROOT_BLOCK option handles the case where one of the two root blocks is invalid. Note that the Journal now logs its root blocks, so it is possible (with code) to choose a historical root block to be restored. Modified Paths: -------------- branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/journal/FileMetadata.java branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/journal/Options.java branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/journal/RootBlockUtility.java branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java Modified: branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/journal/FileMetadata.java =================================================================== --- branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/journal/FileMetadata.java 2011-03-14 17:49:49 UTC (rev 4297) +++ branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/journal/FileMetadata.java 2011-03-14 18:17:32 UTC (rev 4298) @@ -831,54 +831,58 @@ } - /** - * This constructor handles cases where the file exists and is non-empty. - * - * @param file - * The name of the file to be opened. - * @param useDirectBuffers - * true if a buffer should be allocated using - * {@link ByteBuffer#allocateDirect(int)} rather than - * {@link ByteBuffer#allocate(int)}. This has no effect for the - * {@link BufferMode#Disk} and {@link BufferMode#Mapped} modes. - * @param readOnly - * When true, the file is opened in a read-only mode and it is an - * error if the file does not exist. - * @param forceWrites - * When true, the file is opened in "rwd" mode and individual IOs - * are forced to disk. This option SHOULD be false since we only - * need to write through to disk on commit, not on each IO. - * @param writeCacheEnabled - * When <code>true</code>, the {@link DiskOnlyStrategy} will - * allocate a direct {@link ByteBuffer} from the - * {@link DirectBufferPool} to service as a write cache. - * @param writeCacheBufferCount - * The #of buffers to allocate for the {@link WriteCacheService}. - * @param validateChecksum - * When <code>true</code>, the checksum stored in the root blocks - * of an existing file will be validated when the file is opened. - * See {@link Options#VALIDATE_CHECKSUM}. - * @param alternateRootBlock - * When <code>true</code> the prior root block will be used. This - * option may be used when a commit record is valid but the data - * associated with the commit point is invalid. There are two - * root blocks. Normally the one which has been most recently - * written will be loaded on restart. When this option is - * specified, the older of the two root blocks will be loaded - * instead. <strong>If you use this option and then do a commit - * then the more recent of the root blocks will be lost and any - * data associated with that commit point will be lost as - * well!</strong> - * - * @throws RuntimeException - * if there is a problem preparing the file for use by the - * journal. - */ + /** + * This constructor handles cases where the file exists and is non-empty. + * + * @param file + * The name of the file to be opened. + * @param useDirectBuffers + * true if a buffer should be allocated using + * {@link ByteBuffer#allocateDirect(int)} rather than + * {@link ByteBuffer#allocate(int)}. This has no effect for the + * {@link BufferMode#Disk} and {@link BufferMode#Mapped} modes. + * @param readOnly + * When true, the file is opened in a read-only mode and it is an + * error if the file does not exist. + * @param forceWrites + * When true, the file is opened in "rwd" mode and individual IOs + * are forced to disk. This option SHOULD be false since we only + * need to write through to disk on commit, not on each IO. + * @param writeCacheEnabled + * When <code>true</code>, the {@link DiskOnlyStrategy} will + * allocate a direct {@link ByteBuffer} from the + * {@link DirectBufferPool} to service as a write cache. + * @param writeCacheBufferCount + * The #of buffers to allocate for the {@link WriteCacheService}. + * @param validateChecksum + * When <code>true</code>, the checksum stored in the root blocks + * of an existing file will be validated when the file is opened. + * See {@link Options#VALIDATE_CHECKSUM}. + * @param alternateRootBlock + * When <code>true</code> the prior root block will be used. This + * option may be used when a commit record is valid but the data + * associated with the commit point is invalid. There are two + * root blocks. Normally the one which has been most recently + * written will be loaded on restart. When this option is + * specified, the older of the two root blocks will be loaded + * instead. <strong>If you use this option and then do a commit + * then the more recent of the root blocks will be lost and any + * data associated with that commit point will be lost as + * well!</strong> + * @param ignoreBadRootBlock + * When <code>true</code>, the application will be allowed to + * proceed with one damaged root block. The undamaged root block + * will be automatically chosen. + * + * @throws RuntimeException + * if there is a problem preparing the file for use by the + * journal. + */ FileMetadata(final File file, final boolean useDirectBuffers, final boolean readOnly, final ForceEnum forceWrites, final boolean writeCacheEnabled, final int writeCacheBufferCount, final boolean validateChecksum, final boolean alternateRootBlock, - final Properties properties) + final boolean ignoreBadRootBlock, final Properties properties) throws RuntimeException { if (file == null) @@ -976,7 +980,7 @@ * constants (slotSize, segmentId). */ final RootBlockUtility tmp = new RootBlockUtility(opener, file, - validateChecksum, alternateRootBlock); + validateChecksum, alternateRootBlock, ignoreBadRootBlock); this.rootBlock0 = tmp.rootBlock0; this.rootBlock1 = tmp.rootBlock1; this.rootBlock = tmp.rootBlock; @@ -1422,9 +1426,12 @@ properties, Options.VALIDATE_CHECKSUM, Options.DEFAULT_VALIDATE_CHECKSUM)); - final boolean alternateRootBlock = Boolean.parseBoolean(getProperty( - properties, Options.ALTERNATE_ROOT_BLOCK, "false")); + final boolean alternateRootBlock = Boolean.parseBoolean(getProperty( + properties, Options.ALTERNATE_ROOT_BLOCK, "false")); + final boolean ignoreBadRootBlock = Boolean.parseBoolean(getProperty( + properties, Options.IGNORE_BAD_ROOT_BLOCK, "false")); + if (alternateRootBlock && !readOnly) { log.warn("*** Using the alternate root block: " @@ -1440,7 +1447,8 @@ return new FileMetadata(file, useDirectBuffers, readOnly, forceWrites, writeCacheEnabled, writeCacheBufferCount, - validateChecksum, alternateRootBlock, properties); + validateChecksum, alternateRootBlock, ignoreBadRootBlock, + properties); } else { Modified: branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/journal/Options.java =================================================================== --- branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/journal/Options.java 2011-03-14 17:49:49 UTC (rev 4297) +++ branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/journal/Options.java 2011-03-14 18:17:32 UTC (rev 4298) @@ -322,12 +322,12 @@ * the more current root block is used to (re-)open the store. However, if * this option is specified, the <em>previous</em> root block will be used * to open the store. This will allow you to access the previous commit - * point. <strong>If you subsequently perform a commit then the most root - * block will be overwritten and any data associated with the last commit - * point will be unreachable.</strong> This option may be considered in the - * cases where the application is otherwise unable to proceed. It is - * strongly recommended that you also specify {@link #READ_ONLY} so that you - * do not <em>accidentally</em> trigger a commit and thereby make the data + * point. <strong>If you subsequently perform a commit then the other root + * block will be overwritten and any data associated with its commit point + * will be unreachable.</strong> This option may be considered in the cases + * where the application is otherwise unable to proceed. It is strongly + * recommended that you also specify {@link #READ_ONLY} so that you do not + * <em>accidentally</em> trigger a commit and thereby make the data * associated with the other root block unreachable. You may of course * deliberately allow a commit as an attempt to restore the database to * service accepting that you have rolled back the database by one commit @@ -336,6 +336,21 @@ String ALTERNATE_ROOT_BLOCK = AbstractJournal.class.getName()+".alternateRootBlock"; /** + * <strong>WARNING - The use of this option is dangerous.</strong> This + * option MAY be used to permit the database to be opened if one of the root + * blocks is bad. This will allow you to access the remaining root block and + * the associated commit point. <strong>If you subsequently perform a commit + * then the damaged root block will be overwritten.</strong> This option may + * be considered in the cases where the application is otherwise unable to + * proceed. It is strongly recommended that you also specify + * {@link #READ_ONLY} so that you do not <em>accidentally</em> trigger a + * commit. You may of course deliberately allow a commit as an attempt to + * restore the database to service accepting that you may have rolled back + * the database by one commit point in doing so. + */ + String IGNORE_BAD_ROOT_BLOCK = AbstractJournal.class.getName()+".ignoreBadRootBlock"; + + /** * An optional boolean property (default is {@value #DEFAULT_CREATE}). When * <code>true</code> and the named file is not found, a new journal will be * created. If the file exists but is empty, then a new journal will be Modified: branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/journal/RootBlockUtility.java =================================================================== --- branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/journal/RootBlockUtility.java 2011-03-14 17:49:49 UTC (rev 4297) +++ branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/journal/RootBlockUtility.java 2011-03-14 18:17:32 UTC (rev 4298) @@ -67,10 +67,24 @@ */ public final IRootBlockView rootBlock; + /** + * + * @param opener + * @param file + * @param validateChecksum + * @param alternateRootBlock + * @param ignoreBadRootBlock + * + * @throws IOException + * + * @see com.bigdata.journal.Options#ALTERNATE_ROOT_BLOCK + * @see com.bigdata.journal.Options#IGNORE_BAD_ROOT_BLOCK + */ public RootBlockUtility(final IReopenChannel<FileChannel> opener, final File file, final boolean validateChecksum, - final boolean alternateRootBlock) throws IOException { - + final boolean alternateRootBlock, final boolean ignoreBadRootBlock) + throws IOException { + final ChecksumUtility checker = validateChecksum ? ChecksumUtility.threadChk .get() : null; @@ -87,31 +101,43 @@ try { rootBlock0 = new RootBlockView(true, tmp0, checker); } catch (RootBlockException ex) { - log.warn("Bad root block zero: " + ex); + log.error("Bad root block zero: " + ex); } try { rootBlock1 = new RootBlockView(false, tmp1, checker); } catch (RootBlockException ex) { - log.warn("Bad root block one: " + ex); + log.error("Bad root block one: " + ex); } if (rootBlock0 == null && rootBlock1 == null) { throw new RuntimeException( "Both root blocks are bad - journal is not usable: " + file); } + // save references. this.rootBlock0 = rootBlock0; this.rootBlock1 = rootBlock1; - + + if (!ignoreBadRootBlock + && (rootBlock0 == null || rootBlock1 == null)) { + /* + * Do not permit the application to continue with a damaged + * root block. + */ + throw new RuntimeException( + "Bad root block(s): rootBlock0 is " + + (rootBlock0 == null ? "bad" : "ok") + + ", rootBlock1=" + + (rootBlock1 == null ? "bad" : "ok")); + } if(alternateRootBlock) { /* * A request was made to use the alternative root block. */ if (rootBlock0 == null || rootBlock1 == null) { /* - * Note: The [alternateRootBlock] flag only makes sense - * when you have two to choose from and you want to - * choose the other one. In this case, your only choice - * is to use the undamaged root block. + * Note: The [alternateRootBlock] flag only makes sense when you + * have two root blocks to choose from and you want to choose + * the other one. */ throw new RuntimeException( "Can not use alternative root block since one root block is damaged."); @@ -219,12 +245,17 @@ }; + // validate the root blocks using their checksums. final boolean validateChecksum = true; - + + // option is ignored since we are not not opening the Journal. final boolean alternateRootBlock = false; + + // Open even if one root block is bad. + final boolean ignoreBadRootBlock = true; final RootBlockUtility u = new RootBlockUtility(opener, file, - validateChecksum, alternateRootBlock); + validateChecksum, alternateRootBlock, ignoreBadRootBlock); System.out.println("rootBlock0: " + u.rootBlock0); Modified: branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java =================================================================== --- branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2011-03-14 17:49:49 UTC (rev 4297) +++ branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2011-03-14 18:17:32 UTC (rev 4298) @@ -2068,7 +2068,8 @@ try { final RootBlockUtility tmp = new RootBlockUtility(m_reopener, m_fd, - true/* validateChecksum */, false/* alternateRootBlock */); + true/* validateChecksum */, false/* alternateRootBlock */, + false/* ignoreBadRootBlock */); final IRootBlockView rootBlock = tmp.rootBlock; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |