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

Subscribers

People subscribed via source and target branches