0001: /*-
0002: * See the file LICENSE for redistribution information.
0003: *
0004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
0005: *
0006: * $Id: UtilizationTest.java,v 1.22.2.3 2008/01/07 15:14:25 cwl Exp $
0007: */
0008:
0009: package com.sleepycat.je.cleaner;
0010:
0011: import java.io.File;
0012: import java.io.IOException;
0013: import java.nio.ByteBuffer;
0014: import java.util.Enumeration;
0015:
0016: import junit.framework.Test;
0017: import junit.framework.TestCase;
0018: import junit.framework.TestSuite;
0019:
0020: import com.sleepycat.bind.tuple.IntegerBinding;
0021: import com.sleepycat.je.CheckpointConfig;
0022: import com.sleepycat.je.Cursor;
0023: import com.sleepycat.je.Database;
0024: import com.sleepycat.je.DatabaseConfig;
0025: import com.sleepycat.je.DatabaseEntry;
0026: import com.sleepycat.je.DatabaseException;
0027: import com.sleepycat.je.DbInternal;
0028: import com.sleepycat.je.Environment;
0029: import com.sleepycat.je.EnvironmentConfig;
0030: import com.sleepycat.je.OperationStatus;
0031: import com.sleepycat.je.Transaction;
0032: import com.sleepycat.je.config.EnvironmentParams;
0033: import com.sleepycat.je.log.FileManager;
0034: import com.sleepycat.je.log.LogEntryHeader;
0035: import com.sleepycat.je.log.LogManager;
0036: import com.sleepycat.je.log.LogSource;
0037: import com.sleepycat.je.util.TestUtils;
0038: import com.sleepycat.je.utilint.DbLsn;
0039:
0040: public class UtilizationTest extends TestCase {
0041:
0042: private static final String DB_NAME = "foo";
0043:
0044: private static final String OP_NONE = "op-none";
0045: private static final String OP_CHECKPOINT = "op-checkpoint";
0046: private static final String OP_RECOVER = "op-recover";
0047: //private static final String[] OPERATIONS = { OP_NONE, };
0048: //*
0049: private static final String[] OPERATIONS = { OP_NONE,
0050: OP_CHECKPOINT, OP_RECOVER, OP_RECOVER };
0051: //*/
0052:
0053: /*
0054: * Set fetchObsoleteSize=true only for the second OP_RECOVER test.
0055: * We check that OP_RECOVER works with without fetching, but with fetching
0056: * we check that all LN sizes are counted.
0057: */
0058: private static final boolean[] FETCH_OBSOLETE_SIZE = { false,
0059: false, false, true };
0060:
0061: private static final CheckpointConfig forceConfig = new CheckpointConfig();
0062: static {
0063: forceConfig.setForce(true);
0064: }
0065:
0066: private File envHome;
0067: private Environment env;
0068: private Database db;
0069: private boolean dups = false;
0070: private DatabaseEntry keyEntry = new DatabaseEntry();
0071: private DatabaseEntry dataEntry = new DatabaseEntry();
0072: private String operation;
0073: private long lastFileSeen;
0074: private boolean fetchObsoleteSize;
0075:
0076: public static Test suite() {
0077: TestSuite allTests = new TestSuite();
0078: for (int i = 0; i < OPERATIONS.length; i += 1) {
0079: TestSuite suite = new TestSuite(UtilizationTest.class);
0080: Enumeration e = suite.tests();
0081: while (e.hasMoreElements()) {
0082: UtilizationTest test = (UtilizationTest) e
0083: .nextElement();
0084: test.init(OPERATIONS[i], FETCH_OBSOLETE_SIZE[i]);
0085: allTests.addTest(test);
0086: }
0087: }
0088: return allTests;
0089: }
0090:
0091: public UtilizationTest() {
0092: envHome = new File(System.getProperty(TestUtils.DEST_DIR));
0093: }
0094:
0095: private void init(String operation, boolean fetchObsoleteSize) {
0096: this .operation = operation;
0097: this .fetchObsoleteSize = fetchObsoleteSize;
0098: }
0099:
0100: public void setUp() throws IOException, DatabaseException {
0101:
0102: TestUtils.removeLogFiles("Setup", envHome, false);
0103: TestUtils.removeFiles("Setup", envHome, FileManager.DEL_SUFFIX);
0104: }
0105:
0106: public void tearDown() throws IOException, DatabaseException {
0107:
0108: /* Set test name for reporting; cannot be done in the ctor or setUp. */
0109: setName(operation + (fetchObsoleteSize ? "-fetch" : "") + ':'
0110: + getName());
0111:
0112: try {
0113: if (env != null) {
0114: env.close();
0115: }
0116: } catch (Throwable e) {
0117: System.out.println("tearDown: " + e);
0118: }
0119:
0120: try {
0121: //*
0122: TestUtils.removeLogFiles("tearDown", envHome, true);
0123: TestUtils.removeFiles("tearDown", envHome,
0124: FileManager.DEL_SUFFIX);
0125: //*/
0126: } catch (Throwable e) {
0127: System.out.println("tearDown: " + e);
0128: }
0129:
0130: db = null;
0131: env = null;
0132: envHome = null;
0133: keyEntry = null;
0134: dataEntry = null;
0135: }
0136:
0137: /**
0138: * Opens the environment and database.
0139: */
0140: private void openEnv() throws DatabaseException {
0141:
0142: EnvironmentConfig config = TestUtils.initEnvConfig();
0143: DbInternal.disableParameterValidation(config);
0144: config.setTransactional(true);
0145: config.setTxnNoSync(true);
0146: config.setAllowCreate(true);
0147: /* Do not run the daemons. */
0148: config.setConfigParam(EnvironmentParams.ENV_RUN_CLEANER
0149: .getName(), "false");
0150: config.setConfigParam(EnvironmentParams.ENV_RUN_EVICTOR
0151: .getName(), "false");
0152: config.setConfigParam(EnvironmentParams.ENV_RUN_CHECKPOINTER
0153: .getName(), "false");
0154: config.setConfigParam(EnvironmentParams.ENV_RUN_INCOMPRESSOR
0155: .getName(), "false");
0156: /* Use a tiny log file size to write one LN per file. */
0157: config.setConfigParam(EnvironmentParams.LOG_FILE_MAX.getName(),
0158: Integer.toString(64));
0159: /* Don't use NIO direct buffers or we run out of memory. */
0160: config.setConfigParam(EnvironmentParams.LOG_DIRECT_NIO
0161: .getName(), "false");
0162:
0163: /* Obsolete LN size counting is optional per test. */
0164: if (fetchObsoleteSize) {
0165: config.setConfigParam(
0166: EnvironmentParams.CLEANER_FETCH_OBSOLETE_SIZE
0167: .getName(), "true");
0168: }
0169:
0170: env = new Environment(envHome, config);
0171:
0172: /* Speed up test that uses lots of very small files. */
0173: DbInternal.envGetEnvironmentImpl(env).getFileManager()
0174: .setSyncAtFileEnd(false);
0175:
0176: openDb();
0177: }
0178:
0179: /**
0180: * Opens the database.
0181: */
0182: private void openDb() throws DatabaseException {
0183:
0184: DatabaseConfig dbConfig = new DatabaseConfig();
0185: dbConfig.setTransactional(true);
0186: dbConfig.setAllowCreate(true);
0187: dbConfig.setSortedDuplicates(dups);
0188: db = env.openDatabase(null, DB_NAME, dbConfig);
0189: }
0190:
0191: /**
0192: * Closes the environment and database.
0193: */
0194: private void closeEnv(boolean doCheckpoint)
0195: throws DatabaseException {
0196:
0197: /* Verify utilization using UtilizationFileReader. */
0198: CleanerTestUtils.verifyUtilization(DbInternal
0199: .envGetEnvironmentImpl(env), true, // expectAccurateObsoleteLNCount
0200: expectAccurateObsoleteLNSize());
0201:
0202: if (db != null) {
0203: db.close();
0204: db = null;
0205: }
0206: if (env != null) {
0207: DbInternal.envGetEnvironmentImpl(env).close(doCheckpoint);
0208: env = null;
0209: }
0210: }
0211:
0212: public void testReuseSlotAfterDelete() throws DatabaseException {
0213:
0214: openEnv();
0215:
0216: /* Insert and delete without compress to create a knownDeleted slot. */
0217: Transaction txn = env.beginTransaction(null, null);
0218: long file0 = doPut(0, txn);
0219: long file1 = doDelete(0, txn);
0220: txn.commit();
0221:
0222: /* Insert key 0 to reuse the knownDeleted slot. */
0223: txn = env.beginTransaction(null, null);
0224: long file2 = doPut(0, txn);
0225: /* Delete and insert to reuse deleted slot in same txn. */
0226: long file3 = doDelete(0, txn);
0227: long file4 = doPut(0, txn);
0228: txn.commit();
0229: performRecoveryOperation();
0230:
0231: expectObsolete(file0, true);
0232: expectObsolete(file1, true);
0233: expectObsolete(file2, true);
0234: expectObsolete(file3, true);
0235: expectObsolete(file4, false);
0236:
0237: closeEnv(true);
0238: }
0239:
0240: public void testReuseKnownDeletedSlot() throws DatabaseException {
0241:
0242: openEnv();
0243:
0244: /* Insert key 0 and abort to create a knownDeleted slot. */
0245: Transaction txn = env.beginTransaction(null, null);
0246: long file0 = doPut(0, txn);
0247: txn.abort();
0248:
0249: /* Insert key 0 to reuse the knownDeleted slot. */
0250: txn = env.beginTransaction(null, null);
0251: long file1 = doPut(0, txn);
0252: txn.commit();
0253: performRecoveryOperation();
0254:
0255: /* Verify that file0 is still obsolete. */
0256: expectObsolete(file0, true);
0257: expectObsolete(file1, false);
0258:
0259: closeEnv(true);
0260: }
0261:
0262: public void testReuseKnownDeletedSlotAbort()
0263: throws DatabaseException {
0264:
0265: openEnv();
0266:
0267: /* Insert key 0 and abort to create a knownDeleted slot. */
0268: Transaction txn = env.beginTransaction(null, null);
0269: long file0 = doPut(0, txn);
0270: txn.abort();
0271:
0272: /* Insert key 0 to reuse the knownDeleted slot, and abort. */
0273: txn = env.beginTransaction(null, null);
0274: long file1 = doPut(0, txn);
0275: txn.abort();
0276: performRecoveryOperation();
0277:
0278: /* Verify that file0 is still obsolete. */
0279: expectObsolete(file0, true);
0280: expectObsolete(file1, true);
0281:
0282: closeEnv(true);
0283: }
0284:
0285: public void testReuseKnownDeletedSlotDup() throws DatabaseException {
0286:
0287: dups = true;
0288: openEnv();
0289:
0290: /* Insert two key 0 dups and checkpoint. */
0291: Transaction txn = env.beginTransaction(null, null);
0292: long file0 = doPut(0, 0, txn); // 1st LN
0293: long file2 = doPut(0, 1, txn); // 2nd LN
0294: long file1 = file2 - 1; // DupCountLN
0295: txn.commit();
0296: env.checkpoint(forceConfig);
0297:
0298: /* Insert {0, 2} and abort to create a knownDeleted slot. */
0299: txn = env.beginTransaction(null, null);
0300: long file3 = doPut(0, 2, txn); // 3rd LN
0301: long file4 = file3 + 1; // DupCountLN
0302: txn.abort();
0303:
0304: /* Insert {0, 2} to reuse the knownDeleted slot. */
0305: txn = env.beginTransaction(null, null);
0306: long file5 = doPut(0, 2, txn); // 4th LN
0307: long file6 = file5 + 1; // DupCountLN
0308: txn.commit();
0309: performRecoveryOperation();
0310:
0311: /* Verify that file3 is still obsolete. */
0312: expectObsolete(file0, false);
0313: expectObsolete(file1, true);
0314: expectObsolete(file2, false);
0315: expectObsolete(file3, true);
0316: expectObsolete(file4, true);
0317: expectObsolete(file5, false);
0318: expectObsolete(file6, false);
0319:
0320: closeEnv(true);
0321: }
0322:
0323: public void testReuseKnownDeletedSlotDupAbort()
0324: throws DatabaseException {
0325:
0326: dups = true;
0327: openEnv();
0328:
0329: /* Insert two key 0 dups and checkpoint. */
0330: Transaction txn = env.beginTransaction(null, null);
0331: long file0 = doPut(0, 0, txn); // 1st LN
0332: long file2 = doPut(0, 1, txn); // 2nd LN
0333: long file1 = file2 - 1; // DupCountLN
0334: txn.commit();
0335: env.checkpoint(forceConfig);
0336:
0337: /* Insert {0, 2} and abort to create a knownDeleted slot. */
0338: txn = env.beginTransaction(null, null);
0339: long file3 = doPut(0, 2, txn); // 3rd LN
0340: long file4 = file3 + 1; // DupCountLN
0341: txn.abort();
0342:
0343: /* Insert {0, 2} to reuse the knownDeleted slot, then abort. */
0344: txn = env.beginTransaction(null, null);
0345: long file5 = doPut(0, 2, txn); // 4th LN
0346: long file6 = file5 + 1; // DupCountLN
0347: txn.abort();
0348: performRecoveryOperation();
0349:
0350: /* Verify that file3 is still obsolete. */
0351: expectObsolete(file0, false);
0352: expectObsolete(file1, false);
0353: expectObsolete(file2, false);
0354: expectObsolete(file3, true);
0355: expectObsolete(file4, true);
0356: expectObsolete(file5, true);
0357: expectObsolete(file6, true);
0358:
0359: closeEnv(true);
0360: }
0361:
0362: public void testInsert() throws DatabaseException {
0363:
0364: openEnv();
0365:
0366: /* Insert key 0. */
0367: long file0 = doPut(0, true);
0368: performRecoveryOperation();
0369:
0370: /* Expect that LN is not obsolete. */
0371: FileSummary summary = getSummary(file0);
0372: assertEquals(1, summary.totalLNCount);
0373: assertEquals(0, summary.obsoleteLNCount);
0374:
0375: closeEnv(true);
0376: }
0377:
0378: public void testInsertAbort() throws DatabaseException {
0379:
0380: openEnv();
0381:
0382: /* Insert key 0. */
0383: long file0 = doPut(0, false);
0384: performRecoveryOperation();
0385:
0386: /* Expect that LN is obsolete. */
0387: FileSummary summary = getSummary(file0);
0388: assertEquals(1, summary.totalLNCount);
0389: assertEquals(1, summary.obsoleteLNCount);
0390:
0391: closeEnv(true);
0392: }
0393:
0394: public void testInsertDup() throws DatabaseException {
0395:
0396: dups = true;
0397: openEnv();
0398:
0399: /* Insert key 0 and a dup. */
0400: Transaction txn = env.beginTransaction(null, null);
0401: long file0 = doPut(0, 0, txn);
0402: long file3 = doPut(0, 1, txn);
0403: txn.commit();
0404: performRecoveryOperation();
0405:
0406: /*
0407: * The dup tree is created on 2nd insert. In between the two
0408: * DupCountLNs are two INs.
0409: */
0410: long file1 = file0 + 1; // DupCountLN (provisional)
0411: long file2 = file1 + 3; // DupCountLN (non-provisional)
0412: assertEquals(file3, file2 + 1); // new LN
0413:
0414: expectObsolete(file0, false); // 1st LN
0415: expectObsolete(file1, true); // 1st DupCountLN
0416: expectObsolete(file2, false); // 2nd DupCountLN
0417: expectObsolete(file3, false); // 2nd LN
0418:
0419: closeEnv(true);
0420: }
0421:
0422: public void testInsertDupAbort() throws DatabaseException {
0423:
0424: dups = true;
0425: openEnv();
0426:
0427: /* Insert key 0 and a dup. */
0428: Transaction txn = env.beginTransaction(null, null);
0429: long file0 = doPut(0, 0, txn);
0430: long file3 = doPut(0, 1, txn);
0431: txn.abort();
0432: performRecoveryOperation();
0433:
0434: /*
0435: * The dup tree is created on 2nd insert. In between the two
0436: * DupCountLNs are two INs.
0437: */
0438: long file1 = file0 + 1; // DupCountLN (provisional)
0439: long file2 = file1 + 3; // DupCountLN (non-provisional)
0440: assertEquals(file3, file2 + 1); // new LN
0441:
0442: expectObsolete(file0, true); // 1st LN
0443: expectObsolete(file1, false); // 1st DupCountLN
0444: expectObsolete(file2, true); // 2nd DupCountLN
0445: expectObsolete(file3, true); // 2nd LN
0446:
0447: closeEnv(true);
0448: }
0449:
0450: public void testUpdate() throws DatabaseException {
0451:
0452: openEnv();
0453:
0454: /* Insert key 0 and checkpoint. */
0455: long file0 = doPut(0, true);
0456: env.checkpoint(forceConfig);
0457:
0458: /* Update key 0. */
0459: long file1 = doPut(0, true);
0460: performRecoveryOperation();
0461:
0462: expectObsolete(file0, true);
0463: expectObsolete(file1, false);
0464:
0465: closeEnv(true);
0466: }
0467:
0468: public void testUpdateAbort() throws DatabaseException {
0469:
0470: openEnv();
0471:
0472: /* Insert key 0 and checkpoint. */
0473: long file0 = doPut(0, true);
0474: env.checkpoint(forceConfig);
0475:
0476: /* Update key 0 and abort. */
0477: long file1 = doPut(0, false);
0478: performRecoveryOperation();
0479:
0480: expectObsolete(file0, false);
0481: expectObsolete(file1, true);
0482:
0483: closeEnv(true);
0484: }
0485:
0486: public void testUpdateDup() throws DatabaseException {
0487:
0488: dups = true;
0489: openEnv();
0490:
0491: /* Insert two key 0 dups and checkpoint. */
0492: Transaction txn = env.beginTransaction(null, null);
0493: long file0 = doPut(0, 0, txn); // 1st LN
0494: long file2 = doPut(0, 1, txn); // 2nd LN
0495: long file1 = file2 - 1; // DupCountLN
0496: txn.commit();
0497: env.checkpoint(forceConfig);
0498:
0499: /* Update {0, 0}. */
0500: txn = env.beginTransaction(null, null);
0501: long file3 = doUpdate(0, 0, txn); // 3rd LN
0502: txn.commit();
0503: performRecoveryOperation();
0504:
0505: expectObsolete(file0, true);
0506: expectObsolete(file1, false);
0507: expectObsolete(file2, false);
0508: expectObsolete(file3, false);
0509:
0510: closeEnv(true);
0511: }
0512:
0513: public void testUpdateDupAbort() throws DatabaseException {
0514:
0515: dups = true;
0516: openEnv();
0517:
0518: /* Insert two key 0 dups and checkpoint. */
0519: Transaction txn = env.beginTransaction(null, null);
0520: long file0 = doPut(0, 0, txn); // 1st LN
0521: long file2 = doPut(0, 1, txn); // 2nd LN
0522: long file1 = file2 - 1; // DupCountLN
0523: txn.commit();
0524: env.checkpoint(forceConfig);
0525:
0526: /* Update {0, 0}. */
0527: txn = env.beginTransaction(null, null);
0528: long file3 = doUpdate(0, 0, txn); // 3rd LN
0529: txn.abort();
0530: performRecoveryOperation();
0531:
0532: expectObsolete(file0, false);
0533: expectObsolete(file1, false);
0534: expectObsolete(file2, false);
0535: expectObsolete(file3, true);
0536:
0537: closeEnv(true);
0538: }
0539:
0540: public void testDelete() throws DatabaseException {
0541:
0542: openEnv();
0543:
0544: /* Insert key 0 and checkpoint. */
0545: long file0 = doPut(0, true);
0546: env.checkpoint(forceConfig);
0547:
0548: /* Delete key 0. */
0549: long file1 = doDelete(0, true);
0550: performRecoveryOperation();
0551:
0552: expectObsolete(file0, true);
0553: expectObsolete(file1, true);
0554:
0555: closeEnv(true);
0556: }
0557:
0558: public void testDeleteAbort() throws DatabaseException {
0559:
0560: openEnv();
0561:
0562: /* Insert key 0 and checkpoint. */
0563: long file0 = doPut(0, true);
0564: env.checkpoint(forceConfig);
0565:
0566: /* Delete key 0 and abort. */
0567: long file1 = doDelete(0, false);
0568: performRecoveryOperation();
0569:
0570: expectObsolete(file0, false);
0571: expectObsolete(file1, true);
0572:
0573: closeEnv(true);
0574: }
0575:
0576: public void testDeleteDup() throws DatabaseException {
0577:
0578: dups = true;
0579: openEnv();
0580:
0581: /* Insert two key 0 dups and checkpoint. */
0582: Transaction txn = env.beginTransaction(null, null);
0583: long file0 = doPut(0, 0, txn); // 1st LN
0584: long file2 = doPut(0, 1, txn); // 2nd LN
0585: long file1 = file2 - 1; // DupCountLN
0586: txn.commit();
0587: env.checkpoint(forceConfig);
0588:
0589: /* Delete {0, 0} and abort. */
0590: txn = env.beginTransaction(null, null);
0591: long file3 = doDelete(0, 0, txn); // 3rd LN
0592: long file4 = file3 + 1; // DupCountLN
0593: txn.commit();
0594: performRecoveryOperation();
0595:
0596: expectObsolete(file0, true);
0597: expectObsolete(file1, true);
0598: expectObsolete(file2, false);
0599: expectObsolete(file3, true);
0600: expectObsolete(file4, false);
0601:
0602: closeEnv(true);
0603: }
0604:
0605: public void testDeleteDupAbort() throws DatabaseException {
0606:
0607: dups = true;
0608: openEnv();
0609:
0610: /* Insert two key 0 dups and checkpoint. */
0611: Transaction txn = env.beginTransaction(null, null);
0612: long file0 = doPut(0, 0, txn); // 1st LN
0613: long file2 = doPut(0, 1, txn); // 2nd LN
0614: long file1 = file2 - 1; // DupCountLN
0615: txn.commit();
0616: env.checkpoint(forceConfig);
0617:
0618: /* Delete {0, 0} and abort. */
0619: txn = env.beginTransaction(null, null);
0620: long file3 = doDelete(0, 0, txn); // 3rd LN
0621: long file4 = file3 + 1; // DupCountLN
0622: txn.abort();
0623: performRecoveryOperation();
0624:
0625: expectObsolete(file0, false);
0626: expectObsolete(file1, false);
0627: expectObsolete(file2, false);
0628: expectObsolete(file3, true);
0629: expectObsolete(file4, true);
0630:
0631: closeEnv(true);
0632: }
0633:
0634: public void testInsertUpdate() throws DatabaseException {
0635:
0636: openEnv();
0637:
0638: /* Insert and update key 0. */
0639: Transaction txn = env.beginTransaction(null, null);
0640: long file0 = doPut(0, txn);
0641: long file1 = doPut(0, txn);
0642: txn.commit();
0643: performRecoveryOperation();
0644:
0645: expectObsolete(file0, true);
0646: expectObsolete(file1, false);
0647:
0648: closeEnv(true);
0649: }
0650:
0651: public void testInsertUpdateAbort() throws DatabaseException {
0652:
0653: openEnv();
0654:
0655: /* Insert and update key 0. */
0656: Transaction txn = env.beginTransaction(null, null);
0657: long file0 = doPut(0, txn);
0658: long file1 = doPut(0, txn);
0659: txn.abort();
0660: performRecoveryOperation();
0661:
0662: expectObsolete(file0, true);
0663: expectObsolete(file1, true);
0664:
0665: closeEnv(true);
0666: }
0667:
0668: public void testInsertUpdateDup() throws DatabaseException {
0669:
0670: dups = true;
0671: openEnv();
0672:
0673: /* Insert two key 0 dups and checkpoint. */
0674: Transaction txn = env.beginTransaction(null, null);
0675: long file0 = doPut(0, 0, txn); // 1st LN
0676: long file2 = doPut(0, 1, txn); // 2nd LN
0677: long file1 = file2 - 1; // DupCountLN
0678: txn.commit();
0679: env.checkpoint(forceConfig);
0680:
0681: /* Insert and update {0, 2}. */
0682: txn = env.beginTransaction(null, null);
0683: long file3 = doPut(0, 2, txn); // 3rd LN
0684: long file4 = file3 + 1; // DupCountLN
0685: long file5 = doUpdate(0, 2, txn); // 4rd LN
0686: txn.commit();
0687: performRecoveryOperation();
0688:
0689: expectObsolete(file0, false);
0690: expectObsolete(file1, true);
0691: expectObsolete(file2, false);
0692: expectObsolete(file3, true);
0693: expectObsolete(file4, false);
0694: expectObsolete(file5, false);
0695:
0696: closeEnv(true);
0697: }
0698:
0699: public void testInsertUpdateDupAbort() throws DatabaseException {
0700:
0701: dups = true;
0702: openEnv();
0703:
0704: /* Insert two key 0 dups and checkpoint. */
0705: Transaction txn = env.beginTransaction(null, null);
0706: long file0 = doPut(0, 0, txn); // 1st LN
0707: long file2 = doPut(0, 1, txn); // 2nd LN
0708: long file1 = file2 - 1; // DupCountLN
0709: txn.commit();
0710: env.checkpoint(forceConfig);
0711:
0712: /* Insert and update {0, 2}. */
0713: txn = env.beginTransaction(null, null);
0714: long file3 = doPut(0, 2, txn); // 3rd LN
0715: long file4 = file3 + 1; // DupCountLN
0716: long file5 = doUpdate(0, 2, txn); // 4rd LN
0717: txn.abort();
0718: performRecoveryOperation();
0719:
0720: expectObsolete(file0, false);
0721: expectObsolete(file1, false);
0722: expectObsolete(file2, false);
0723: expectObsolete(file3, true);
0724: expectObsolete(file4, true);
0725: expectObsolete(file5, true);
0726:
0727: closeEnv(true);
0728: }
0729:
0730: public void testInsertDelete() throws DatabaseException {
0731:
0732: openEnv();
0733:
0734: /* Insert and update key 0. */
0735: Transaction txn = env.beginTransaction(null, null);
0736: long file0 = doPut(0, txn);
0737: long file1 = doDelete(0, txn);
0738: txn.commit();
0739: performRecoveryOperation();
0740:
0741: expectObsolete(file0, true);
0742: expectObsolete(file1, true);
0743:
0744: closeEnv(true);
0745: }
0746:
0747: public void testInsertDeleteAbort() throws DatabaseException {
0748:
0749: openEnv();
0750:
0751: /* Insert and update key 0. */
0752: Transaction txn = env.beginTransaction(null, null);
0753: long file0 = doPut(0, txn);
0754: long file1 = doDelete(0, txn);
0755: txn.abort();
0756: performRecoveryOperation();
0757:
0758: expectObsolete(file0, true);
0759: expectObsolete(file1, true);
0760:
0761: closeEnv(true);
0762: }
0763:
0764: public void testInsertDeleteDup() throws DatabaseException {
0765:
0766: dups = true;
0767: openEnv();
0768:
0769: /* Insert two key 0 dups and checkpoint. */
0770: Transaction txn = env.beginTransaction(null, null);
0771: long file0 = doPut(0, 0, txn); // 1st LN
0772: long file2 = doPut(0, 1, txn); // 2nd LN
0773: long file1 = file2 - 1; // DupCountLN
0774: txn.commit();
0775: env.checkpoint(forceConfig);
0776:
0777: /* Insert and delete {0, 2}. */
0778: txn = env.beginTransaction(null, null);
0779: long file3 = doPut(0, 2, txn); // 3rd LN
0780: long file4 = file3 + 1; // DupCountLN
0781: long file5 = doDelete(0, 2, txn); // 4rd LN
0782: long file6 = file5 + 1; // DupCountLN
0783: txn.commit();
0784: performRecoveryOperation();
0785:
0786: expectObsolete(file0, false);
0787: expectObsolete(file1, true);
0788: expectObsolete(file2, false);
0789: expectObsolete(file3, true);
0790: expectObsolete(file4, true);
0791: expectObsolete(file5, true);
0792: expectObsolete(file6, false);
0793:
0794: closeEnv(true);
0795: }
0796:
0797: public void testInsertDeleteDupAbort() throws DatabaseException {
0798:
0799: dups = true;
0800: openEnv();
0801:
0802: /* Insert two key 0 dups and checkpoint. */
0803: Transaction txn = env.beginTransaction(null, null);
0804: long file0 = doPut(0, 0, txn); // 1st LN
0805: long file2 = doPut(0, 1, txn); // 2nd LN
0806: long file1 = file2 - 1; // DupCountLN
0807: txn.commit();
0808: env.checkpoint(forceConfig);
0809:
0810: /* Insert and delete {0, 2} and abort. */
0811: txn = env.beginTransaction(null, null);
0812: long file3 = doPut(0, 2, txn); // 3rd LN
0813: long file4 = file3 + 1; // DupCountLN
0814: long file5 = doDelete(0, 2, txn); // 4rd LN
0815: long file6 = file5 + 1; // DupCountLN
0816: txn.abort();
0817: performRecoveryOperation();
0818:
0819: expectObsolete(file0, false);
0820: expectObsolete(file1, false);
0821: expectObsolete(file2, false);
0822: expectObsolete(file3, true);
0823: expectObsolete(file4, true);
0824: expectObsolete(file5, true);
0825: expectObsolete(file6, true);
0826:
0827: closeEnv(true);
0828: }
0829:
0830: public void testUpdateUpdate() throws DatabaseException {
0831:
0832: openEnv();
0833:
0834: /* Insert key 0 and checkpoint. */
0835: long file0 = doPut(0, true);
0836: env.checkpoint(forceConfig);
0837:
0838: /* Update key 0 twice. */
0839: Transaction txn = env.beginTransaction(null, null);
0840: long file1 = doPut(0, txn);
0841: long file2 = doPut(0, txn);
0842: txn.commit();
0843: performRecoveryOperation();
0844:
0845: expectObsolete(file0, true);
0846: expectObsolete(file1, true);
0847: expectObsolete(file2, false);
0848:
0849: closeEnv(true);
0850: }
0851:
0852: public void testUpdateUpdateAbort() throws DatabaseException {
0853:
0854: openEnv();
0855:
0856: /* Insert key 0 and checkpoint. */
0857: long file0 = doPut(0, true);
0858: env.checkpoint(forceConfig);
0859:
0860: /* Update key 0 twice and abort. */
0861: Transaction txn = env.beginTransaction(null, null);
0862: long file1 = doPut(0, txn);
0863: long file2 = doPut(0, txn);
0864: txn.abort();
0865: performRecoveryOperation();
0866:
0867: expectObsolete(file0, false);
0868: expectObsolete(file1, true);
0869: expectObsolete(file2, true);
0870:
0871: closeEnv(true);
0872: }
0873:
0874: public void testUpdateUpdateDup() throws DatabaseException {
0875:
0876: dups = true;
0877: openEnv();
0878:
0879: /* Insert two key 0 dups and checkpoint. */
0880: Transaction txn = env.beginTransaction(null, null);
0881: long file0 = doPut(0, 0, txn); // 1st LN
0882: long file2 = doPut(0, 1, txn); // 2nd LN
0883: long file1 = file2 - 1; // DupCountLN
0884: txn.commit();
0885: env.checkpoint(forceConfig);
0886:
0887: /* Update {0, 1} twice. */
0888: txn = env.beginTransaction(null, null);
0889: long file3 = doUpdate(0, 1, txn); // 3rd LN
0890: long file4 = doUpdate(0, 1, txn); // 4rd LN
0891: txn.commit();
0892: performRecoveryOperation();
0893:
0894: expectObsolete(file0, false);
0895: expectObsolete(file1, false);
0896: expectObsolete(file2, true);
0897: expectObsolete(file3, true);
0898: expectObsolete(file4, false);
0899:
0900: closeEnv(true);
0901: }
0902:
0903: public void testUpdateUpdateDupAbort() throws DatabaseException {
0904:
0905: dups = true;
0906: openEnv();
0907:
0908: /* Insert two key 0 dups and checkpoint. */
0909: Transaction txn = env.beginTransaction(null, null);
0910: long file0 = doPut(0, 0, txn); // 1st LN
0911: long file2 = doPut(0, 1, txn); // 2nd LN
0912: long file1 = file2 - 1; // DupCountLN
0913: txn.commit();
0914: env.checkpoint(forceConfig);
0915:
0916: /* Update {0, 1} twice and abort. */
0917: txn = env.beginTransaction(null, null);
0918: long file3 = doUpdate(0, 1, txn); // 3rd LN
0919: long file4 = doUpdate(0, 1, txn); // 4rd LN
0920: txn.abort();
0921: performRecoveryOperation();
0922:
0923: expectObsolete(file0, false);
0924: expectObsolete(file1, false);
0925: expectObsolete(file2, false);
0926: expectObsolete(file3, true);
0927: expectObsolete(file4, true);
0928:
0929: closeEnv(true);
0930: }
0931:
0932: public void testUpdateDelete() throws DatabaseException {
0933:
0934: openEnv();
0935:
0936: /* Insert key 0 and checkpoint. */
0937: long file0 = doPut(0, true);
0938: env.checkpoint(forceConfig);
0939:
0940: /* Update and delete key 0. */
0941: Transaction txn = env.beginTransaction(null, null);
0942: long file1 = doPut(0, txn);
0943: long file2 = doDelete(0, txn);
0944: txn.commit();
0945: performRecoveryOperation();
0946:
0947: expectObsolete(file0, true);
0948: expectObsolete(file1, true);
0949: expectObsolete(file2, true);
0950:
0951: closeEnv(true);
0952: }
0953:
0954: public void testUpdateDeleteAbort() throws DatabaseException {
0955:
0956: openEnv();
0957:
0958: /* Insert key 0 and checkpoint. */
0959: long file0 = doPut(0, true);
0960: env.checkpoint(forceConfig);
0961:
0962: /* Update and delete key 0 and abort. */
0963: Transaction txn = env.beginTransaction(null, null);
0964: long file1 = doPut(0, txn);
0965: long file2 = doDelete(0, txn);
0966: txn.abort();
0967: performRecoveryOperation();
0968:
0969: expectObsolete(file0, false);
0970: expectObsolete(file1, true);
0971: expectObsolete(file2, true);
0972:
0973: closeEnv(true);
0974: }
0975:
0976: public void testUpdateDeleteDup() throws DatabaseException {
0977:
0978: dups = true;
0979: openEnv();
0980:
0981: /* Insert two key 0 dups and checkpoint. */
0982: Transaction txn = env.beginTransaction(null, null);
0983: long file0 = doPut(0, 0, txn); // 1st LN
0984: long file2 = doPut(0, 1, txn); // 2nd LN
0985: long file1 = file2 - 1; // DupCountLN
0986: txn.commit();
0987: env.checkpoint(forceConfig);
0988:
0989: /* Update and delete {0, 1}. */
0990: txn = env.beginTransaction(null, null);
0991: long file3 = doUpdate(0, 1, txn); // 3rd LN
0992: long file4 = doDelete(0, 1, txn); // 4rd LN
0993: long file5 = file4 + 1; // DupCountLN
0994: txn.commit();
0995: performRecoveryOperation();
0996:
0997: expectObsolete(file0, false);
0998: expectObsolete(file1, true);
0999: expectObsolete(file2, true);
1000: expectObsolete(file3, true);
1001: expectObsolete(file4, true);
1002: expectObsolete(file5, false);
1003:
1004: closeEnv(true);
1005: }
1006:
1007: public void testUpdateDeleteDupAbort() throws DatabaseException {
1008:
1009: dups = true;
1010: openEnv();
1011:
1012: /* Insert two key 0 dups and checkpoint. */
1013: Transaction txn = env.beginTransaction(null, null);
1014: long file0 = doPut(0, 0, txn); // 1st LN
1015: long file2 = doPut(0, 1, txn); // 2nd LN
1016: long file1 = file2 - 1; // DupCountLN
1017: txn.commit();
1018: env.checkpoint(forceConfig);
1019:
1020: /* Update and delete {0, 1} and abort. */
1021: txn = env.beginTransaction(null, null);
1022: long file3 = doUpdate(0, 1, txn); // 3rd LN
1023: long file4 = doDelete(0, 1, txn); // 4rd LN
1024: long file5 = file4 + 1; // DupCountLN
1025: txn.abort();
1026: performRecoveryOperation();
1027:
1028: expectObsolete(file0, false);
1029: expectObsolete(file1, false);
1030: expectObsolete(file2, false);
1031: expectObsolete(file3, true);
1032: expectObsolete(file4, true);
1033: expectObsolete(file5, true);
1034:
1035: closeEnv(true);
1036: }
1037:
1038: public void testTruncate() throws DatabaseException {
1039:
1040: truncateOrRemove(true, true);
1041: }
1042:
1043: public void testTruncateAbort() throws DatabaseException {
1044:
1045: truncateOrRemove(true, false);
1046: }
1047:
1048: public void testRemove() throws DatabaseException {
1049:
1050: truncateOrRemove(false, true);
1051: }
1052:
1053: public void testRemoveAbort() throws DatabaseException {
1054:
1055: truncateOrRemove(false, false);
1056: }
1057:
1058: /**
1059: * @deprecated use of Database.truncate
1060: */
1061: private void truncateOrRemove(boolean truncate, boolean commit)
1062: throws DatabaseException {
1063:
1064: openEnv();
1065:
1066: /* Insert 3 keys and checkpoint. */
1067: Transaction txn = env.beginTransaction(null, null);
1068: long file0 = doPut(0, txn);
1069: long file1 = doPut(1, txn);
1070: long file2 = doPut(2, txn);
1071: txn.commit();
1072: env.checkpoint(forceConfig);
1073:
1074: /* Truncate. */
1075: txn = env.beginTransaction(null, null);
1076: if (truncate) {
1077: int count = db.truncate(txn, true);
1078: assertEquals(3, count);
1079: } else {
1080: db.close();
1081: db = null;
1082: env.removeDatabase(txn, DB_NAME);
1083: }
1084: if (commit) {
1085: txn.commit();
1086: } else {
1087: txn.abort();
1088: }
1089: performRecoveryOperation();
1090:
1091: expectObsolete(file0, commit);
1092: expectObsolete(file1, commit);
1093: expectObsolete(file2, commit);
1094:
1095: closeEnv(true);
1096: }
1097:
1098: private void expectObsolete(long file, boolean obsolete)
1099: throws DatabaseException {
1100:
1101: FileSummary summary = getSummary(file);
1102: assertEquals("totalLNCount", 1, summary.totalLNCount);
1103: assertEquals("obsoleteLNCount", obsolete ? 1 : 0,
1104: summary.obsoleteLNCount);
1105:
1106: if (obsolete) {
1107: if (expectAccurateObsoleteLNSize()) {
1108: assertTrue(summary.obsoleteLNSize > 0);
1109: assertEquals(1, summary.obsoleteLNSizeCounted);
1110: }
1111: /* If we counted the size, make sure it is the actual LN size. */
1112: if (summary.obsoleteLNSize > 0) {
1113: assertEquals(getLNSize(file), summary.obsoleteLNSize);
1114: }
1115: } else {
1116: assertEquals(0, summary.obsoleteLNSize);
1117: assertEquals(0, summary.obsoleteLNSizeCounted);
1118: }
1119: }
1120:
1121: /**
1122: * If an LN is obsolete, expect the size to be counted unless we ran
1123: * recovery and we did NOT configure fetchObsoleteSize=true. In that
1124: * case, the size may or may not be counted depending on how the redo
1125: * or undo was processed during reocvery.
1126: */
1127: private boolean expectAccurateObsoleteLNSize() {
1128: return fetchObsoleteSize || !OP_RECOVER.equals(operation);
1129: }
1130:
1131: private long doPut(int key, boolean commit)
1132: throws DatabaseException {
1133:
1134: Transaction txn = env.beginTransaction(null, null);
1135: long file = doPut(key, txn);
1136: if (commit) {
1137: txn.commit();
1138: } else {
1139: txn.abort();
1140: }
1141: return file;
1142: }
1143:
1144: private long doPut(int key, Transaction txn)
1145: throws DatabaseException {
1146:
1147: return doPut(key, key, txn);
1148: }
1149:
1150: private long doPut(int key, int data, Transaction txn)
1151: throws DatabaseException {
1152:
1153: Cursor cursor = db.openCursor(txn, null);
1154: IntegerBinding.intToEntry(key, keyEntry);
1155: IntegerBinding.intToEntry(data, dataEntry);
1156: cursor.put(keyEntry, dataEntry);
1157: long file = getFile(cursor);
1158: cursor.close();
1159: return file;
1160: }
1161:
1162: private long doUpdate(int key, int data, Transaction txn)
1163: throws DatabaseException {
1164:
1165: Cursor cursor = db.openCursor(txn, null);
1166: IntegerBinding.intToEntry(key, keyEntry);
1167: IntegerBinding.intToEntry(data, dataEntry);
1168: assertEquals(OperationStatus.SUCCESS, cursor.getSearchBoth(
1169: keyEntry, dataEntry, null));
1170: cursor.putCurrent(dataEntry);
1171: long file = getFile(cursor);
1172: cursor.close();
1173: return file;
1174: }
1175:
1176: private long doDelete(int key, boolean commit)
1177: throws DatabaseException {
1178:
1179: Transaction txn = env.beginTransaction(null, null);
1180: long file = doDelete(key, txn);
1181: if (commit) {
1182: txn.commit();
1183: } else {
1184: txn.abort();
1185: }
1186: return file;
1187: }
1188:
1189: private long doDelete(int key, Transaction txn)
1190: throws DatabaseException {
1191:
1192: Cursor cursor = db.openCursor(txn, null);
1193: IntegerBinding.intToEntry(key, keyEntry);
1194: assertEquals(OperationStatus.SUCCESS, cursor.getSearchKey(
1195: keyEntry, dataEntry, null));
1196: cursor.delete();
1197: long file = getFile(cursor);
1198: cursor.close();
1199: return file;
1200: }
1201:
1202: private long doDelete(int key, int data, Transaction txn)
1203: throws DatabaseException {
1204:
1205: Cursor cursor = db.openCursor(txn, null);
1206: IntegerBinding.intToEntry(key, keyEntry);
1207: IntegerBinding.intToEntry(data, dataEntry);
1208: assertEquals(OperationStatus.SUCCESS, cursor.getSearchBoth(
1209: keyEntry, dataEntry, null));
1210: cursor.delete();
1211: long file = getFile(cursor);
1212: cursor.close();
1213: return file;
1214: }
1215:
1216: /**
1217: * Checkpoint, recover, or do nothing.
1218: */
1219: private void performRecoveryOperation() throws DatabaseException {
1220:
1221: if (OP_NONE.equals(operation)) {
1222: /* Compress to count deleted LNs. */
1223: env.compress();
1224: } else if (OP_CHECKPOINT.equals(operation)) {
1225: /* Compress before checkpointing to count deleted LNs. */
1226: env.compress();
1227: env.checkpoint(forceConfig);
1228: } else if (OP_RECOVER.equals(operation)) {
1229: closeEnv(false);
1230: openEnv();
1231: /* Compress after recovery to count deleted LNs. */
1232: env.compress();
1233: } else {
1234: assert false : operation;
1235: }
1236: }
1237:
1238: /**
1239: * Gets the file of the LSN at the cursor position, using internal methods.
1240: * Also check that the file number is greater than the last file returned,
1241: * to ensure that we're filling a file every time we write.
1242: */
1243: private long getFile(Cursor cursor) throws DatabaseException {
1244:
1245: long file = CleanerTestUtils.getLogFile(this , cursor);
1246: assert file > lastFileSeen;
1247: lastFileSeen = file;
1248: return file;
1249: }
1250:
1251: /**
1252: * Returns the utilization summary for a given log file.
1253: */
1254: private FileSummary getSummary(long file) throws DatabaseException {
1255:
1256: return (FileSummary) DbInternal.envGetEnvironmentImpl(env)
1257: .getUtilizationProfile().getFileSummaryMap(true).get(
1258: new Long(file));
1259: }
1260:
1261: /**
1262: * Peek into the file to get the total size of the first entry past the
1263: * file header, which is known to be the LN log entry.
1264: */
1265: private int getLNSize(long file) throws DatabaseException {
1266:
1267: try {
1268: long offset = FileManager.firstLogEntryOffset();
1269: long lsn = DbLsn.makeLsn(file, offset);
1270: LogManager lm = DbInternal.envGetEnvironmentImpl(env)
1271: .getLogManager();
1272: LogSource src = lm.getLogSource(lsn);
1273: ByteBuffer buf = src.getBytes(offset);
1274: LogEntryHeader header = new LogEntryHeader(null, // envImpl, only needed for
1275: buf, // error reporting
1276: false); // anticipateChecksumError
1277: int size = header.getItemSize();
1278: src.release();
1279: return size + header.getSize();
1280: } catch (IOException e) {
1281: throw new DatabaseException(e);
1282: }
1283: }
1284: }
|