/**
* Copyright 2011-2012 Akiban Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.persistit;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
/**
* At a DP site experiencing very low insert rates the JournalManager was
* failing to delete obsolete journal files. This was noticed just prior to the
* disk becoming full.
*
* Current journal file is xx36, the obsolete journal file not being removed is
* xx27 Many of the journal files are short, indicating repeated cycles of
* shutdown/restart.
*
* The root cause is that a transaction which began in xx27 aborted, but its
* transaction status was (correctly) written to the journal's TM (transaction
* map) record after the next recovery. What is incorrect is that after the
* subsequent recovery, the same transaction was also copied into _its_
* liveTransactionMap where it was subsequently carried through many additional
* start/stop cycles.
*
* Two issues to fix:
*
* (1) an aborted transaction in the LiveTransactionMap should not hold back the
* journal cleanup process.
*
* (2) the aborted transaction should not have been retained in the
* liveTransactionMap after the second startup.
*/
public class Bug918909Test extends PersistitUnitTestCase {
private final int RESTART_ITERATIONS = 5;
private final int SMALL_RECORD_COUNT = 10;
private final int LARGE_RECORD_COUNT = 1000;
private final int TRANSACTION_COUNT = 10;
@Test
public void testSmallAbortedEmptyTransaction() throws Exception {
doTest(1, SMALL_RECORD_COUNT, 1);
}
@Test
public void testMultipleSmallAbortedEmptyTransactions() throws Exception {
doTest(1, SMALL_RECORD_COUNT, TRANSACTION_COUNT);
}
@Test
public void testSmallAbortedInsertTransaction() throws Exception {
doTest(SMALL_RECORD_COUNT / 2, SMALL_RECORD_COUNT, 1);
}
@Test
public void testSmallAbortedStoreDeleteTransaction() throws Exception {
doTest(SMALL_RECORD_COUNT, SMALL_RECORD_COUNT, 1);
}
@Test
public void testLargeAbortedEmptyTransaction() throws Exception {
doTest(1, LARGE_RECORD_COUNT, 1);
}
@Test
public void testLargeAbortedInsertTransaction() throws Exception {
doTest(LARGE_RECORD_COUNT / 2, LARGE_RECORD_COUNT, 1);
}
@Test
public void testLargeAbortedStoreDeleteTransaction() throws Exception {
doTest(LARGE_RECORD_COUNT, LARGE_RECORD_COUNT, 1);
}
@Test
public void testMultipleLargeAbortedStoreDeleteTransactions() throws Exception {
doTest(LARGE_RECORD_COUNT, LARGE_RECORD_COUNT, TRANSACTION_COUNT);
}
private void doTest(final int when, final int records, final int transactions) throws Exception {
for (int i = 1; i < transactions; i++) {
{
final Exchange ex = _persistit.getExchange("persistit", "Bug918909Test", true);
final Transaction txn = ex.getTransaction();
txn.begin();
for (int j = 1; j <= records; j++) {
ex.getValue().put(RED_FOX);
if (j == when) {
_persistit.flush();
_persistit.checkpoint();
}
ex.clear().append(j).store();
}
if (when == records) {
ex.removeAll();
}
txn.rollback();
txn.end();
}
}
_persistit.crash();
for (int i = 0; i < RESTART_ITERATIONS; i++) {
_persistit = new Persistit(_config);
final Exchange ex = _persistit.getExchange("persistit", "Bug918909Test", true);
final Transaction txn = ex.getTransaction();
txn.begin();
for (int j = 1; j <= records; j++) {
ex.clear().append(j).fetch();
assertFalse(ex.getValue().isDefined());
assertFalse(ex.isValueDefined());
}
assertFalse(ex.to(Key.BEFORE).next());
assertFalse(ex.to(Key.AFTER).previous());
txn.commit();
txn.end();
_persistit.close();
}
_persistit = new Persistit(_config);
_persistit.checkpoint();
_persistit.copyBackPages();
assertTrue(_persistit.getJournalManager().getBaseAddress() > RESTART_ITERATIONS
* _persistit.getJournalManager().getBlockSize());
}
}