/**
* 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.fail;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Properties;
import org.junit.Test;
import com.persistit.JournalRecord.JE;
import com.persistit.Transaction.CommitPolicy;
import com.persistit.exception.PersistitIOException;
import com.persistit.unit.UnitTestProperties;
public class Bug1041003Test extends PersistitUnitTestCase {
final static int BLOCKSIZE = 10000000;
/*
* This class needs to be in com.persistit rather than com.persistit.unit
* because it uses some package- private methods in Persistit.
*/
private final String _volumeName = "persistit";
@Override
protected Properties getProperties(final boolean cleanup) {
final Properties p = UnitTestProperties.getProperties(cleanup);
p.setProperty("journalsize", Integer.toString(BLOCKSIZE));
return p;
}
private ErrorInjectingFileChannel errorInjectingChannel(final FileChannel channel) {
final ErrorInjectingFileChannel eimfc = new ErrorInjectingFileChannel();
((MediatedFileChannel) channel).injectChannelForTests(eimfc);
return eimfc;
}
/**
* Simulate IOException on attempt to append to the journal. This simulates
* bug #878346. Sets an injected IOException on journal file .000000000001
* then stores a bunch of data until a failure occurs. Clears the injected
* error, runs one more transaction and then checks the resulting database
* state for correctness.
*
* @throws Exception
*/
@Test
public void leaveTransactionBufferFlipped() throws Exception {
/*
* Need first journal file almost full so that an attempt to write a
* transaction will force a rollover.
*/
final Exchange exchange = _persistit.getExchange(_volumeName, "Bug1041003Test", true);
_persistit.flush();
final JournalManager jman = _persistit.getJournalManager();
final ByteBuffer bb = ByteBuffer.allocate(BLOCKSIZE);
final long size = BLOCKSIZE - JE.OVERHEAD - jman.getCurrentAddress() - 1;
bb.position((int) (size - JournalRecord.TX.OVERHEAD));
jman.writeTransactionToJournal(bb, 1, 2, 0);
final Transaction txn = _persistit.getTransaction();
final ErrorInjectingFileChannel eifc = errorInjectingChannel(_persistit.getJournalManager().getFileChannel(
BLOCKSIZE));
/*
* Will cause any attempt to write into the second journal file to fail.
*/
eifc.injectTestIOException(new IOException("injected"), "w");
try {
txn.begin();
try {
exchange.getValue().put(RED_FOX);
exchange.to(1).store();
txn.commit(CommitPolicy.HARD);
} finally {
txn.end();
}
} catch (final PersistitIOException e) {
if (e.getMessage().contains("injected")) {
System.out.println("Expected: " + e);
} else {
throw e;
}
}
/*
* Now remove the disk full condition. Transaction should now succeed.
*/
eifc.injectTestIOException(null, "w");
txn.begin();
try {
exchange.getValue().put(RED_FOX + RED_FOX);
/*
* Bug 1041003 causes the following line to throw an
* IllegalStateException.
*/
exchange.to(1).store();
txn.commit(CommitPolicy.HARD);
} catch (final IllegalStateException e) {
fail("Bug 1041003 strikes: " + e);
} finally {
txn.end();
}
}
}