Merge lp:~pbeaman/akiban-persistit/fix-1041003-IllegalStateException into lp:akiban-persistit

Proposed by Peter Beaman
Status: Merged
Approved by: Nathan Williams
Approved revision: 370
Merged at revision: 370
Proposed branch: lp:~pbeaman/akiban-persistit/fix-1041003-IllegalStateException
Merge into: lp:akiban-persistit
Diff against target: 155 lines (+131/-2)
2 files modified
src/main/java/com/persistit/JournalManager.java (+2/-2)
src/test/java/com/persistit/Bug1041003Test.java (+129/-0)
To merge this branch: bzr merge lp:~pbeaman/akiban-persistit/fix-1041003-IllegalStateException
Reviewer Review Type Date Requested Status
Nathan Williams Approve
Review via email: mp+126557@code.launchpad.net

Description of the change

Relatively trivial fix for bug 1041003 - IllegalStateException in Transaction#prepare.

Fix is to avoid flipping the Transaction byte buffer until it is safe to do so. The larger part of this is a unit test that demonstrated the problem prior to the fix.

To post a comment you must log in.
Revision history for this message
Nathan Williams (nwilliams) wrote :

Looks good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/main/java/com/persistit/JournalManager.java'
2--- src/main/java/com/persistit/JournalManager.java 2012-09-12 22:02:22 +0000
3+++ src/main/java/com/persistit/JournalManager.java 2012-09-26 21:34:36 +0000
4@@ -1175,8 +1175,7 @@
5 */
6 synchronized long writeTransactionToJournal(final ByteBuffer buffer, final long startTimestamp,
7 final long commitTimestamp, final long backchainAddress) throws PersistitException {
8- buffer.flip();
9- final int recordSize = TX.OVERHEAD + buffer.remaining();
10+ final int recordSize = TX.OVERHEAD + buffer.position();
11 prepareWriteBuffer(recordSize);
12 final long address = _currentAddress;
13 TX.putLength(_writeBuffer, recordSize);
14@@ -1187,6 +1186,7 @@
15 _persistit.getIOMeter().chargeWriteTXtoJournal(recordSize, _currentAddress);
16 advance(TX.OVERHEAD);
17 try {
18+ buffer.flip();
19 _writeBuffer.put(buffer);
20 } finally {
21 buffer.clear();
22
23=== added file 'src/test/java/com/persistit/Bug1041003Test.java'
24--- src/test/java/com/persistit/Bug1041003Test.java 1970-01-01 00:00:00 +0000
25+++ src/test/java/com/persistit/Bug1041003Test.java 2012-09-26 21:34:36 +0000
26@@ -0,0 +1,129 @@
27+/**
28+ * Copyright © 2011-2012 Akiban Technologies, Inc. All rights reserved.
29+ *
30+ * This program and the accompanying materials are made available
31+ * under the terms of the Eclipse Public License v1.0 which
32+ * accompanies this distribution, and is available at
33+ * http://www.eclipse.org/legal/epl-v10.html
34+ *
35+ * This program may also be available under different license terms.
36+ * For more information, see www.akiban.com or contact licensing@akiban.com.
37+ *
38+ * Contributors:
39+ * Akiban Technologies, Inc.
40+ */
41+
42+package com.persistit;
43+
44+import static org.junit.Assert.assertEquals;
45+import static org.junit.Assert.assertTrue;
46+import static org.junit.Assert.fail;
47+
48+import java.io.File;
49+import java.io.IOException;
50+import java.io.RandomAccessFile;
51+import java.nio.ByteBuffer;
52+import java.nio.channels.FileChannel;
53+import java.util.Properties;
54+import java.util.Timer;
55+import java.util.TimerTask;
56+
57+import org.junit.Test;
58+
59+import com.persistit.JournalRecord.JE;
60+import com.persistit.Transaction.CommitPolicy;
61+import com.persistit.exception.CorruptJournalException;
62+import com.persistit.exception.CorruptVolumeException;
63+import com.persistit.exception.PersistitException;
64+import com.persistit.exception.PersistitIOException;
65+import com.persistit.unit.UnitTestProperties;
66+
67+public class Bug1041003Test extends PersistitUnitTestCase {
68+
69+ final static int BLOCKSIZE = 10000000;
70+
71+ /*
72+ * This class needs to be in com.persistit rather than com.persistit.unit
73+ * because it uses some package- private methods in Persistit.
74+ */
75+
76+ private final String _volumeName = "persistit";
77+
78+ @Override
79+ protected Properties getProperties(final boolean cleanup) {
80+ final Properties p = UnitTestProperties.getProperties(cleanup);
81+ p.setProperty("journalsize", Integer.toString(BLOCKSIZE));
82+ return p;
83+ }
84+
85+ private ErrorInjectingFileChannel errorInjectingChannel(final FileChannel channel) {
86+ final ErrorInjectingFileChannel eimfc = new ErrorInjectingFileChannel();
87+ ((MediatedFileChannel) channel).injectChannelForTests(eimfc);
88+ return eimfc;
89+ }
90+
91+ /**
92+ * Simulate IOException on attempt to append to the journal. This simulates
93+ * bug #878346. Sets an injected IOException on journal file .000000000001
94+ * then stores a bunch of data until a failure occurs. Clears the injected
95+ * error, runs one more transaction and then checks the resulting database
96+ * state for correctness.
97+ *
98+ * @throws Exception
99+ */
100+ @Test
101+ public void leaveTransactionBufferFlipped() throws Exception {
102+ /*
103+ * Need first journal file almost full so that an attempt to write a transaction
104+ * will force a rollover.
105+ */
106+ final Exchange exchange = _persistit.getExchange(_volumeName, "Bug1041003Test", true);
107+ _persistit.flush();
108+ final JournalManager jman = _persistit.getJournalManager();
109+ ByteBuffer bb = ByteBuffer.allocate(BLOCKSIZE);
110+ long size = BLOCKSIZE - JE.OVERHEAD - jman.getCurrentAddress() - 1;
111+ bb.position((int)(size - JournalRecord.TX.OVERHEAD));
112+ jman.writeTransactionToJournal(bb, 1, 2, 0);
113+ final Transaction txn = _persistit.getTransaction();
114+ final ErrorInjectingFileChannel eifc = errorInjectingChannel(_persistit.getJournalManager().getFileChannel(
115+ BLOCKSIZE));
116+ /*
117+ * Will cause any attempt to write into the second journal file to fail.
118+ */
119+ eifc.injectTestIOException(new IOException("injected"), "w");
120+ try {
121+ txn.begin();
122+ try {
123+ exchange.getValue().put(RED_FOX);
124+ exchange.to(1).store();
125+ txn.commit(CommitPolicy.HARD);
126+ } finally {
127+ txn.end();
128+ }
129+ } catch (final PersistitIOException e) {
130+ if (e.getMessage().contains("injected")) {
131+ System.out.println("Expected: " + e);
132+ } else {
133+ throw e;
134+ }
135+ }
136+ /*
137+ * Now remove the disk full condition. Transaction should now succeed.
138+ */
139+ eifc.injectTestIOException(null, "w");
140+ txn.begin();
141+ try {
142+ exchange.getValue().put(RED_FOX + RED_FOX);
143+ /*
144+ * Bug 1041003 causes the following line to throw an IllegalStateException.
145+ */
146+ exchange.to(1).store();
147+ txn.commit(CommitPolicy.HARD);
148+ } catch (IllegalStateException e) {
149+ fail("Bug 1041003 strikes: " + e);
150+ } finally {
151+ txn.end();
152+ }
153+ }
154+
155+}

Subscribers

People subscribed via source and target branches