1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2010 Oracle. All rights reserved.
*
* $Id: FileEdgeCaseTest.java,v 1.6.2.2 2010/01/04 15:30:44 cwl Exp $
*/
package com.sleepycat.je.log;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import junit.framework.TestCase;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.DbInternal;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.dbi.EnvironmentImpl;
import com.sleepycat.je.recovery.NoRootException;
import com.sleepycat.je.util.TestUtils;
public class FileEdgeCaseTest extends TestCase {
private File envHome;
private Environment env;
private String firstFile;
public FileEdgeCaseTest() {
envHome = new File(System.getProperty(TestUtils.DEST_DIR));
}
public void setUp()
throws IOException {
TestUtils.removeLogFiles("Setup", envHome, false);
}
public void tearDown()
throws Exception {
/*
* Close down environments in case the unit test failed so that the log
* files can be removed.
*/
try {
if (env != null) {
env.close();
env = null;
}
} catch (DatabaseException e) {
e.printStackTrace();
// ok, the test closed it
}
TestUtils.removeLogFiles("TearDown", envHome, false);
}
/**
* SR #15133
* Create a JE environment with a single log file and a checksum
* exception in the second entry in the log file.
*
* When an application attempts to open this JE environment, JE truncates
* the log file at the point before the bad checksum, because it assumes
* that bad entries at the end of the log are the result of incompletely
* flushed writes from the last environment use. However, the truncated
* log doesn't have a valid environment root, so JE complains and asks the
* application to move aside the existing log file (via the exception
* message). The resulting environment has a single log file, with
* a single valid entry, which is the file header.
*
* Any subsequent attempts to open the environment should also fail at the
* same point. In the error case reported by this SR, we didn't handle this
* single log file/single file header case right, and subsequent opens
* first truncated before the file header, leaving a 0 length log, and
* then proceeded to write error trace messages into the log. This
* resulted in a log file with no file header, (but with trace messages)
* and any following opens got unpredictable errors like
* ClassCastExceptions and BufferUnderflows.
*
* The correct situation is to continue to get the same exception.
*/
public void testPostChecksumError()
throws IOException, DatabaseException {
EnvironmentConfig config = new EnvironmentConfig();
config.setAllowCreate(true);
env = new Environment(envHome, config);
EnvironmentImpl envImpl = DbInternal.envGetEnvironmentImpl(env);
FileManager fm = envImpl.getFileManager();
firstFile = fm.getFullFileName(0, FileManager.JE_SUFFIX);
env.close();
env = null;
/* Intentionally corrupt the second entry. */
corruptSecondEntry();
/*
* Next attempt to open the environment should fail with a
* NoRootException
*/
try {
env = new Environment(envHome, config);
} catch (NoRootException expected) {
}
/*
* Next attempt to open the environment should fail with a
* NoRootException
*/
try {
env = new Environment(envHome, config);
} catch (NoRootException expected) {
}
}
/**
* Write junk into the second log entry, after the file header.
*/
private void corruptSecondEntry()
throws IOException {
RandomAccessFile file =
new RandomAccessFile(firstFile,
FileManager.FileMode.
READWRITE_MODE.getModeValue());
try {
byte[] junk = new byte[20];
file.seek(FileManager.firstLogEntryOffset());
file.write(junk);
} catch (Exception e) {
e.printStackTrace();
} finally {
file.close();
}
}
}
|