public void testJournalCompaction() throws Exception
{
File tempDirectory = TempFileUtil.makeTemporaryDirectory(getClass().getName() + "." + getName());
PersistentJournal perJournal = PersistentJournal.makeJournal(tempDirectory);
MemoryJournal j1, j2, j3;
File tempFile1 = new File(tempDirectory, "journal1.bin");
File tempFile2 = new File(tempDirectory, "journal2.bin");
final int nHeaderLength = 2;
final int nZeroObjectsLength = 7;
assertEquals(nZeroObjectsLength, tempFile1.length());
assertEquals(nHeaderLength, tempFile2.length());
perJournal.setCompactionThreshold(nZeroObjectsLength);
//Just one journal handle: should compact quickly!
j1 = perJournal.getJournal(makeXid(1)); //NO COMPACT
assertEquals(1, perJournal.getActiveTransactions());
assertEquals(tempFile1, perJournal.getActiveJournal());
j1.addRecord(new JournalRecordTesting(makeXid(1), FileJournalRecordCopyInsert.OPCODE));
j1.addRecord(new JournalRecordTesting(makeXid(1), JournalRecordPrepared.OPCODE));
j1.addRecord(new JournalRecordTesting(makeXid(1), JournalRecordCompleted.OPCODE));
assertEquals(nZeroObjectsLength, tempFile1.length());
j1.flush();
assertTrue(tempFile1.length() > nZeroObjectsLength);
j1.completed(); //COMPACT
assertEquals(0, perJournal.getActiveTransactions());
assertEquals(tempFile2, perJournal.getActiveJournal());
assertEquals(nZeroObjectsLength, tempFile2.length());
assertEquals(nHeaderLength, tempFile1.length());
j1 = null;
//Test handles overlapping in time:
//---j1---COMPACT!
// ---j2---COMPACT!
// ---j3--->COMPACT!
j1 = perJournal.getJournal(makeXid(2)); //NO COMPACT
assertEquals(1, perJournal.getActiveTransactions());
assertEquals(tempFile2, perJournal.getActiveJournal());
j1.addRecord(new JournalRecordTesting(makeXid(2), FileJournalRecordCopyInsert.OPCODE));
j1.flush();
assertEquals(tempFile2, perJournal.getActiveJournal());
assertTrue(tempFile2.length() > nZeroObjectsLength);
assertEquals(nHeaderLength, tempFile1.length());
j2 = perJournal.getJournal(makeXid(3)); //COMPACT
assertEquals(tempFile1, perJournal.getActiveJournal());
assertTrue(tempFile1.length() > nZeroObjectsLength); //first record still active!
assertEquals(nHeaderLength, tempFile2.length());
j2.addRecord(new JournalRecordTesting(makeXid(3), FileJournalRecordDelete.OPCODE));
j2.flush();
j1.completed(); //COMPACT
assertEquals(tempFile2, perJournal.getActiveJournal());
assertEquals(nHeaderLength, tempFile1.length());
assertTrue(tempFile2.length() > nZeroObjectsLength); //second record still active!
j1 = null;
j3 = perJournal.getJournal(makeXid(4)); //COMPACT
assertEquals(tempFile1, perJournal.getActiveJournal());
assertEquals(nHeaderLength, tempFile2.length());
assertTrue(tempFile1.length() > nZeroObjectsLength); //second record still active!
j2.completed(); //COMPACT
assertEquals(tempFile2, perJournal.getActiveJournal());
assertEquals(nHeaderLength, tempFile1.length());
assertEquals(nZeroObjectsLength, tempFile2.length()); //third record still active, but is null!
j2 = null;
j3.completed(); //NO COMPACT
assertEquals(tempFile2, perJournal.getActiveJournal());
assertEquals(nHeaderLength, tempFile1.length());
assertEquals(nZeroObjectsLength, tempFile2.length());
j3 = null;
//Test no compaction until crash recovered
//---j1--- CRASH
// RESTART ---j2---
// forget(j1) COMPACT
j1 = perJournal.getJournal(makeXid(5)); //NO COMPACT
assertEquals(tempFile2, perJournal.getActiveJournal());
assertEquals(nHeaderLength, tempFile1.length());
assertEquals(nZeroObjectsLength, tempFile2.length());
j1.addRecord(new JournalRecordTesting(makeXid(5), FileJournalRecordCopyInsert.OPCODE));
j1.addRecord(new JournalRecordTesting(makeXid(5), JournalRecordPrepared.OPCODE));
j1.flush();
assertTrue(tempFile2.length() > nZeroObjectsLength);
//CRASH
PersistentJournal.closeAll();
j1 = null;
perJournal = null;
perJournal = PersistentJournal.makeJournal(tempDirectory);
perJournal.setCompactionThreshold(nZeroObjectsLength);
assertEquals(tempFile1, perJournal.getActiveJournal());
assertEquals(nHeaderLength, tempFile2.length());
assertTrue(tempFile1.length() > nZeroObjectsLength);
j2 = perJournal.getJournal(makeXid(6)); //COMPACT
assertEquals(tempFile2, perJournal.getActiveJournal());
assertEquals(nHeaderLength, tempFile1.length());
assertTrue(tempFile2.length() > nZeroObjectsLength);
j2.addRecord(new JournalRecordTesting(makeXid(6), FileJournalRecordCopyUpdate.OPCODE));
j2.addRecord(new JournalRecordTesting(makeXid(6), JournalRecordPrepared.OPCODE));
j2.addRecord(new JournalRecordTesting(makeXid(6), JournalRecordCompleted.OPCODE));
j2.flush();
assertEquals(tempFile2, perJournal.getActiveJournal());
j2.completed(); //COMPACT
assertEquals(tempFile1, perJournal.getActiveJournal());
assertEquals(nHeaderLength, tempFile2.length());
assertTrue(tempFile1.length() > nZeroObjectsLength);
j2 = null;
j1 = perJournal.recoverJournal(makeXid(5));
assertNotNull(j1);
List opsList = j1.getRecords();
assertEquals(2, opsList.size());
assertEquals(new JournalRecordTesting(makeXid(5), FileJournalRecordCopyInsert.OPCODE), opsList.get(0));
assertEquals(new JournalRecordTesting(makeXid(5), JournalRecordPrepared.OPCODE), opsList.get(1));
//FORGET
assertEquals(tempFile1, perJournal.getActiveJournal());
j1.addRecord(new JournalRecordTesting(makeXid(5), JournalRecordCompleted.OPCODE));
j1.flush();
assertEquals(tempFile1, perJournal.getActiveJournal());
j1.forget(makeXid(5)); //COMPACT
assertEquals(tempFile2, perJournal.getActiveJournal());
assertEquals(nHeaderLength, tempFile1.length());
assertEquals(nZeroObjectsLength, tempFile2.length());
j1 = null;