001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: SR10597Test.java,v 1.7.2.3 2008/01/07 15:14:25 cwl Exp $
007: */
008:
009: package com.sleepycat.je.cleaner;
010:
011: import java.io.File;
012: import java.io.IOException;
013:
014: import junit.framework.TestCase;
015:
016: import com.sleepycat.je.CheckpointConfig;
017: import com.sleepycat.je.Cursor;
018: import com.sleepycat.je.Database;
019: import com.sleepycat.je.DatabaseConfig;
020: import com.sleepycat.je.DatabaseEntry;
021: import com.sleepycat.je.DatabaseException;
022: import com.sleepycat.je.DbInternal;
023: import com.sleepycat.je.Environment;
024: import com.sleepycat.je.EnvironmentConfig;
025: import com.sleepycat.je.OperationStatus;
026: import com.sleepycat.je.config.EnvironmentParams;
027: import com.sleepycat.je.log.FileManager;
028: import com.sleepycat.je.util.TestUtils;
029:
030: public class SR10597Test extends TestCase {
031:
032: private static final String DB_NAME = "foo";
033:
034: private static final CheckpointConfig forceConfig = new CheckpointConfig();
035: static {
036: forceConfig.setForce(true);
037: }
038:
039: private File envHome;
040: private Environment env;
041: private Database db;
042:
043: public SR10597Test() {
044: envHome = new File(System.getProperty(TestUtils.DEST_DIR));
045: }
046:
047: public void setUp() throws IOException, DatabaseException {
048:
049: TestUtils.removeLogFiles("Setup", envHome, false);
050: TestUtils.removeFiles("Setup", envHome, FileManager.DEL_SUFFIX);
051: }
052:
053: public void tearDown() throws IOException, DatabaseException {
054:
055: try {
056: if (env != null) {
057: env.close();
058: }
059: } catch (Throwable e) {
060: System.out.println("tearDown: " + e);
061: }
062:
063: try {
064: TestUtils.removeLogFiles("tearDown", envHome, true);
065: TestUtils.removeFiles("tearDown", envHome,
066: FileManager.DEL_SUFFIX);
067: } catch (Throwable e) {
068: System.out.println("tearDown: " + e);
069: }
070:
071: db = null;
072: env = null;
073: envHome = null;
074: }
075:
076: /**
077: * Opens the environment and database.
078: */
079: private void openEnv() throws DatabaseException {
080:
081: EnvironmentConfig config = TestUtils.initEnvConfig();
082: DbInternal.disableParameterValidation(config);
083: config.setAllowCreate(true);
084: /* Do not run the daemons. */
085: config.setConfigParam(EnvironmentParams.ENV_RUN_CLEANER
086: .getName(), "false");
087: config.setConfigParam(EnvironmentParams.ENV_RUN_EVICTOR
088: .getName(), "false");
089: config.setConfigParam(EnvironmentParams.ENV_RUN_CHECKPOINTER
090: .getName(), "false");
091: config.setConfigParam(EnvironmentParams.ENV_RUN_INCOMPRESSOR
092: .getName(), "false");
093: /* Use a small log file size to make cleaning more frequent. */
094: config.setConfigParam(EnvironmentParams.LOG_FILE_MAX.getName(),
095: Integer.toString(1024));
096: env = new Environment(envHome, config);
097:
098: openDb();
099: }
100:
101: /**
102: * Opens that database.
103: */
104: private void openDb() throws DatabaseException {
105:
106: DatabaseConfig dbConfig = new DatabaseConfig();
107: dbConfig.setAllowCreate(true);
108: dbConfig.setSortedDuplicates(true);
109: db = env.openDatabase(null, DB_NAME, dbConfig);
110: }
111:
112: /**
113: * Closes the environment and database.
114: */
115: private void closeEnv() throws DatabaseException {
116:
117: if (db != null) {
118: db.close();
119: db = null;
120: }
121: if (env != null) {
122: env.close();
123: env = null;
124: }
125: }
126:
127: /**
128: */
129: public void testSR10597() throws DatabaseException {
130:
131: openEnv();
132:
133: /* Put some duplicates, enough to fill a log file. */
134: final int COUNT = 10;
135: DatabaseEntry key = new DatabaseEntry(TestUtils.getTestArray(0));
136: DatabaseEntry data = new DatabaseEntry();
137: for (int i = 0; i < COUNT; i += 1) {
138: data.setData(TestUtils.getTestArray(i));
139: db.put(null, key, data);
140: }
141: Cursor cursor = db.openCursor(null, null);
142: assertEquals(OperationStatus.SUCCESS, cursor.getSearchKey(key,
143: data, null));
144: assertEquals(COUNT, cursor.count());
145: cursor.close();
146:
147: /* Delete everything, then compress to delete the DIN. */
148: db.delete(null, key);
149: env.compress();
150: data.setData(TestUtils.getTestArray(0));
151:
152: /* Add a single record, which will not create a DIN. */
153: db.put(null, key, data);
154:
155: /* Checkpoint and clean. */
156: env.checkpoint(forceConfig);
157: int cleaned = env.cleanLog();
158: assertTrue("cleaned=" + cleaned, cleaned > 0);
159:
160: /*
161: * Before the fix to 10597, when cleaning the log we would be looking
162: * for an LN with containsDuplicates=true. We assumed that when we
163: * found the BIN entry, it must point to a DIN. But because we
164: * deleted and compressed above, the entry is actually an LN. This
165: * caused a ClassCastException at the bottom of
166: * Tree.getParentBINForChildLN.
167: */
168: closeEnv();
169: }
170: }
|