Merge lp:~pbeaman/akiban-persistit/fix_1018526_temp_trees_in_journal into lp:akiban-persistit

Proposed by Peter Beaman
Status: Merged
Approved by: Peter Beaman
Approved revision: 335
Merged at revision: 330
Proposed branch: lp:~pbeaman/akiban-persistit/fix_1018526_temp_trees_in_journal
Merge into: lp:akiban-persistit
Diff against target: 447 lines (+201/-29)
12 files modified
src/main/java/com/persistit/Buffer.java (+3/-1)
src/main/java/com/persistit/Exchange.java (+3/-1)
src/main/java/com/persistit/IntegrityCheck.java (+5/-4)
src/main/java/com/persistit/JournalManager.java (+13/-1)
src/main/java/com/persistit/Persistit.java (+2/-4)
src/main/java/com/persistit/RecoveryManager.java (+18/-6)
src/main/java/com/persistit/Transaction.java (+10/-7)
src/main/java/com/persistit/Tree.java (+11/-0)
src/main/java/com/persistit/Volume.java (+26/-1)
src/main/java/com/persistit/VolumeStructure.java (+6/-1)
src/test/java/com/persistit/Bug1018526Test.java (+104/-0)
src/test/java/com/persistit/Bug932097Test.java (+0/-3)
To merge this branch: bzr merge lp:~pbeaman/akiban-persistit/fix_1018526_temp_trees_in_journal
Reviewer Review Type Date Requested Status
Nathan Williams Needs Fixing
Peter Beaman Needs Resubmitting
Akiban Build User Needs Fixing
Review via email: mp+112454@code.launchpad.net

Description of the change

Fix bug1018526 in which every tree created in a temporary volume has an Identify Tree (IT) record in the journal.

Removes proactive call to JournalManager#handleForTree in VolumeStructure#getTree and instead lets tree handles be created lazily.

Adds a test to verify that no records are written to the journal within a transaction if only temporary volumes are modified.

To post a comment you must log in.
Revision history for this message
Peter Beaman (pbeaman) wrote :

After reconsideration I'm going to add code to remove temporary trees from the _handleToTreeMap on recovery. This will clean up any mess at customer sites related to this bug when we install this update and restart the server.

review: Needs Fixing
Revision history for this message
Nathan Williams (nwilliams) wrote :

What is the intended lifetime of the tree handle now? It looks like it will get created on remove key, remove tree, store key, and accumulator delta inside of a transaction. It looks like _ignoreTransactions hould always mirror isTemporary but it is up to the caller. Maybe an assert inside of JournalManager#handleForTree() would be nice.

A couple of the checks for handle != 0 are also slightly confusing. We shouldn't have MVVs in a temporary tree (txns being ignored) so if we are pruning, we should always have a handle. Similarly, how could we get an index hole if they can't be shared across threads and aren't recovered?

The new test with the "upper bound" to avoid a checkpoint race. We already have a couple intermittent test failures, it would be nice to structure this so it is always deterministic.

review: Needs Information
Revision history for this message
Peter Beaman (pbeaman) wrote :

Added code to detect IT records that refer to temporary volumes during recovery. Such trees are not restored into the handleToTreeMap and treeToHandleMap collections, so that when the journal next rolls over, the recorded tree map will contain only permanent trees and volumes. This logic will fix up existing systems.

Once we have had this version in the field on all sites we can then remove the cleanup code.

Note that from the information in the journal, the detection of a temporary volume is somewhat ad hoc. It is known by the conjunction of two things:

id value is 12345 (for no very good reason temporary volumes have all been marked with that ID number)
name ends with "_temporary_volume"

We feel it is unlikely there are any non-temporary volumes that have these two conditions at this time. However, eventually the detection code should be removed since it is less than perfectly precise.

review: Needs Resubmitting
Revision history for this message
Peter Beaman (pbeaman) wrote :

Responses to Nathan:

What is the intended lifetime of the tree handle now? It looks like it will get created on remove key, remove tree, store key, and accumulator delta inside of a transaction. -- Correct

It looks like _ignoreTransactions hould always mirror isTemporary but it is up to the caller. - Not quite: currently the directory tree exchange operates with _ignoreTransactions on non-temporary volumes.

Maybe an assert inside of JournalManager#handleForTree() would be nice. - Added

A couple of the checks for handle != 0 are also slightly confusing. We shouldn't have MVVs in a temporary tree (txns being ignored) so if we are pruning, we should always have a handle. - Correct. Changed to asserts.

Similarly, how could we get an index hole if they can't be shared across threads and aren't recovered? - There's an obscure, gnarly re-balance case in raw_removeKeyRangeInternal that can leave an index hole. A fix for another bug may remove it, but for now since we think it can happen, the condition in walkRight should be retained.

The new test with the "upper bound" to avoid a checkpoint race. We already have a couple intermittent test failures, it would be nice to structure this so it is always deterministic. - Yes. I suggest we should do that comprehensively in a different branch.

Revision history for this message
Nathan Williams (nwilliams) wrote :

Thanks for the changes, looks good.

review: Approve
Revision history for this message
Akiban Build User (build-akiban) wrote :

There were 2 failures during build/test:

* job persistit-build failed at build number 374: http://172.16.20.104:8080/job/persistit-build/374/

* view must-pass failed: persistit-build is yellow

review: Needs Fixing
334. By Peter Beaman

Always allocate tree handles for permanent trees

Revision history for this message
Peter Beaman (pbeaman) wrote :

Modified the protocol yet again. Tree handles are now assigned on non-temporary trees as soon as the tree object is created. This permits the Exchange#fetchFromValueInternal to enqueue pages with MVVs before any transaction modifies the tree. (Otherwise the conditional on handle != 0 is required in that code path.) Since this behavior is more similar to what we currently have in trunk, it seemed preferable to restore it.

review: Needs Resubmitting
Revision history for this message
Nathan Williams (nwilliams) wrote :

A static final end for the two magic values (12345 and _temporary_volume) would be nice. Coming across that in the future could be confusing otherwise.

Now that tree handles are always loaded proactively, it might be nice to make JournalManage#handleForTree() private/package, grab the current handle in usages in Transaction, and assert in the various JournalManager#write* methods that the incoming handling is non-0.

I don't mean to harp, but since we are trying to fix a bug about the handle lifetime it seems preferable to check all of our assumptions related to it.

review: Needs Fixing
335. By Peter Beaman

Changes per Nathan's review

Revision history for this message
Peter Beaman (pbeaman) wrote :

Modified as requested.

review: Needs Resubmitting
Revision history for this message
Nathan Williams (nwilliams) wrote :

I don't mean to nitpick, but the other source of the constants is in Persistit#createTemporaryVolume(). It is minor, but I know *I* will forget about this soon and it would be easy for one to change and not the other.

Feel free to self-approve after that tiny change.

review: Needs Fixing
336. By Peter Beaman

Use constants when creating temp volume

Revision history for this message
Peter Beaman (pbeaman) wrote :

Good suggestion. Delegated createTemporaryVolume to a static method in the Volume class to keep the constants private.

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/Buffer.java'
2--- src/main/java/com/persistit/Buffer.java 2012-06-29 20:54:00 +0000
3+++ src/main/java/com/persistit/Buffer.java 2012-06-30 15:14:20 +0000
4@@ -3712,8 +3712,10 @@
5 if (p == KEY_BLOCK_START) {
6 if (tree != null) {
7 if (!_enqueuedForAntiValuePruning) {
8+ final int treeHandle = tree.getHandle();
9+ assert treeHandle != 0 : "MVV found in a temporary tree " + tree;
10 if (_persistit.getCleanupManager().offer(
11- new CleanupAntiValue(tree.getHandle(), getPageAddress()))) {
12+ new CleanupAntiValue(treeHandle, getPageAddress()))) {
13 _enqueuedForAntiValuePruning = true;
14 }
15 }
16
17=== modified file 'src/main/java/com/persistit/Exchange.java'
18--- src/main/java/com/persistit/Exchange.java 2012-06-29 20:54:00 +0000
19+++ src/main/java/com/persistit/Exchange.java 2012-06-30 15:14:20 +0000
20@@ -2777,7 +2777,9 @@
21 fetchFixupForLongRecords(value, Integer.MAX_VALUE);
22 if (MVV.isArrayMVV(value.getEncodedBytes(), 0, value.getEncodedSize())) {
23 if (bufferForPruning != null) {
24- bufferForPruning.enqueuePruningAction(_tree.getHandle());
25+ final int treeHandle = _tree.getHandle();
26+ assert treeHandle != 0 : "MVV found in a temporary tree " + _tree;
27+ bufferForPruning.enqueuePruningAction(treeHandle);
28 }
29 visible = mvccFetch(value, minimumBytes);
30 fetchFixupForLongRecords(value, minimumBytes);
31
32=== modified file 'src/main/java/com/persistit/IntegrityCheck.java'
33--- src/main/java/com/persistit/IntegrityCheck.java 2012-06-28 20:08:30 +0000
34+++ src/main/java/com/persistit/IntegrityCheck.java 2012-06-30 15:14:20 +0000
35@@ -833,9 +833,9 @@
36 }
37 _currentTree = null;
38 }
39- if (_holes.size() > 0) {
40- postMessage(" Tree " + resourceName(tree) + " has " + plural(_holes.size(), "unindexed page"),
41- LOG_NORMAL);
42+ if (_counters._indexHoleCount > 0) {
43+ postMessage(" Tree " + resourceName(tree) + " has "
44+ + plural((int) _counters._indexHoleCount, "unindexed page"), LOG_NORMAL);
45 if (_fixHoles) {
46 int offered = 0;
47 for (final CleanupIndexHole hole : _holes) {
48@@ -1082,7 +1082,8 @@
49 }
50
51 _counters._indexHoleCount++;
52- if (_holes.size() < MAX_HOLES_TO_FIX) {
53+ final int treeHandle = _currentTree.getHandle();
54+ if (treeHandle != 0 && _holes.size() < MAX_HOLES_TO_FIX) {
55 _holes.add(new CleanupIndexHole(_currentTree.getHandle(), page, level));
56 }
57
58
59=== modified file 'src/main/java/com/persistit/JournalManager.java'
60--- src/main/java/com/persistit/JournalManager.java 2012-06-22 19:07:13 +0000
61+++ src/main/java/com/persistit/JournalManager.java 2012-06-30 15:14:20 +0000
62@@ -213,6 +213,8 @@
63
64 private volatile long _earliestAbortedTimestamp = Long.MAX_VALUE;
65
66+ private boolean _allowHandlesForTempVolumesAndTrees;
67+
68 /**
69 * <p>
70 * Initialize the new journal. This method takes its information from the
71@@ -540,7 +542,10 @@
72 return Math.min(urgency, URGENT);
73 }
74
75- public int handleForVolume(final Volume volume) throws PersistitException {
76+ int handleForVolume(final Volume volume) throws PersistitException {
77+ if (!_allowHandlesForTempVolumesAndTrees && volume.isTemporary()) {
78+ throw new IllegalStateException("Creating handle for temporary volume " + volume);
79+ }
80 if (volume.getHandle() != 0) {
81 return volume.getHandle();
82 }
83@@ -580,6 +585,9 @@
84 }
85
86 int handleForTree(final Tree tree) throws PersistitException {
87+ if (!_allowHandlesForTempVolumesAndTrees && tree.getVolume().isTemporary()) {
88+ throw new IllegalStateException("Creating handle for temporary tree " + tree);
89+ }
90 if (tree.getHandle() != 0) {
91 return tree.getHandle();
92 }
93@@ -2835,6 +2843,10 @@
94 return files;
95 }
96
97+ void unitTestAllowHandlesForTemporaryVolumesAndTrees() {
98+ _allowHandlesForTempVolumesAndTrees = true;
99+ }
100+
101 public PageNode queryPageNode(final int volumeHandle, final long pageAddress) {
102 PageNode pn = _pageMap.get(new PageNode(volumeHandle, pageAddress, -1, -1));
103 if (pn != null) {
104
105=== modified file 'src/main/java/com/persistit/Persistit.java'
106--- src/main/java/com/persistit/Persistit.java 2012-06-22 19:35:13 +0000
107+++ src/main/java/com/persistit/Persistit.java 2012-06-30 15:14:20 +0000
108@@ -1108,7 +1108,7 @@
109 * <p />
110 * The backing store file for a temporary volume is created in the directory
111 * specified by the configuration property <code>tmpvoldir</code>, or if
112- * unspecified, the system temporary directory..
113+ * unspecified, the system temporary directory.
114 *
115 * @param pageSize
116 * The page size for the volume. Must be one of 1024, 2048, 4096,
117@@ -1121,9 +1121,7 @@
118 if (!Volume.isValidPageSize(pageSize)) {
119 throw new IllegalArgumentException("Invalid page size " + pageSize);
120 }
121- Volume volume = new Volume(Thread.currentThread().getName() + "_temporary_volume", 12345);
122- volume.openTemporary(this, pageSize);
123- return volume;
124+ return Volume.createTemporaryVolume(this, pageSize);
125 }
126
127 /**
128
129=== modified file 'src/main/java/com/persistit/RecoveryManager.java'
130--- src/main/java/com/persistit/RecoveryManager.java 2012-06-14 20:15:48 +0000
131+++ src/main/java/com/persistit/RecoveryManager.java 2012-06-30 15:14:20 +0000
132@@ -595,8 +595,13 @@
133
134 void collectRecoveredVolumeMaps(final Map<Integer, Volume> handleToVolumeMap,
135 final Map<Volume, Integer> volumeToHandleMap) {
136- volumeToHandleMap.putAll(_volumeToHandleMap);
137- handleToVolumeMap.putAll(_handleToVolumeMap);
138+ for (final Map.Entry<Integer, Volume> entry : _handleToVolumeMap.entrySet()) {
139+ final Volume volume = entry.getValue();
140+ if (!volume.isTemporary()) {
141+ volumeToHandleMap.put(volume, entry.getKey());
142+ handleToVolumeMap.put(entry.getKey(), volume);
143+ }
144+ }
145 }
146
147 void collectRecoveredTreeMaps(final Map<Integer, TreeDescriptor> handleToTreeMap,
148@@ -994,10 +999,17 @@
149 final Integer handle = Integer.valueOf(IT.getHandle(_readBuffer));
150 final String treeName = IT.getTreeName(_readBuffer);
151 final Integer volumeHandle = Integer.valueOf(IT.getVolumeHandle(_readBuffer));
152- final TreeDescriptor td = new TreeDescriptor(volumeHandle, treeName);
153- _handleToTreeMap.put(handle, td);
154- _treeToHandleMap.put(td, handle);
155- _persistit.getLogBase().recoveryRecord.log("IT", addressToString(address, timestamp), treeName, timestamp);
156+ final Volume volume = _handleToVolumeMap.get(volumeHandle);
157+ if (volume == null) {
158+ throw new CorruptJournalException("IT JournalRecord refers to unidentified volume handle " + volumeHandle
159+ + " at position " + addressToString(address, timestamp));
160+ }
161+ if (!volume.isTemporary()) {
162+ final TreeDescriptor td = new TreeDescriptor(volumeHandle, treeName);
163+ _handleToTreeMap.put(handle, td);
164+ _treeToHandleMap.put(td, handle);
165+ _persistit.getLogBase().recoveryRecord.log("IT", addressToString(address, timestamp), treeName, timestamp);
166+ }
167 }
168
169 /**
170
171=== modified file 'src/main/java/com/persistit/Transaction.java'
172--- src/main/java/com/persistit/Transaction.java 2012-05-25 18:50:59 +0000
173+++ src/main/java/com/persistit/Transaction.java 2012-06-30 15:14:20 +0000
174@@ -1097,8 +1097,7 @@
175 void store(Exchange exchange, Key key, Value value) throws PersistitException {
176 if (_nestedDepth > 0) {
177 checkPendingRollback();
178- final int treeHandle = _persistit.getJournalManager().handleForTree(exchange.getTree());
179- writeStoreRecordToJournal(treeHandle, key, value);
180+ writeStoreRecordToJournal(treeHandle(exchange.getTree()), key, value);
181 }
182 }
183
184@@ -1113,8 +1112,7 @@
185 void remove(Exchange exchange, Key key1, Key key2) throws PersistitException {
186 if (_nestedDepth > 0) {
187 checkPendingRollback();
188- final int treeHandle = _persistit.getJournalManager().handleForTree(exchange.getTree());
189- writeDeleteRecordToJournal(treeHandle, key1, key2);
190+ writeDeleteRecordToJournal(treeHandle(exchange.getTree()), key1, key2);
191 }
192 }
193
194@@ -1127,8 +1125,7 @@
195 void removeTree(Exchange exchange) throws PersistitException {
196 if (_nestedDepth > 0) {
197 checkPendingRollback();
198- final int treeHandle = _persistit.getJournalManager().handleForTree(exchange.getTree());
199- writeDeleteTreeToJournal(treeHandle);
200+ writeDeleteTreeToJournal(treeHandle(exchange.getTree()));
201 }
202 }
203
204@@ -1203,7 +1200,7 @@
205 }
206
207 synchronized void writeDeltaToJournal(final Delta delta) throws PersistitException {
208- final int treeHandle = _persistit.getJournalManager().handleForTree(delta.getAccumulator().getTree());
209+ final int treeHandle = treeHandle(delta.getAccumulator().getTree());
210 if (delta.getValue() == 1) {
211 prepare(D0.OVERHEAD);
212 JournalRecord.putLength(_buffer, D0.OVERHEAD);
213@@ -1292,6 +1289,12 @@
214 + MAXIMUM_STEP);
215 }
216 }
217+
218+ private int treeHandle(final Tree tree) {
219+ final int treeHandle = tree.getHandle();
220+ assert treeHandle != 0 : "Undefined tree handle in " + tree;
221+ return treeHandle;
222+ }
223
224 /**
225 * For unit tests only
226
227=== modified file 'src/main/java/com/persistit/Tree.java'
228--- src/main/java/com/persistit/Tree.java 2012-05-25 18:50:59 +0000
229+++ src/main/java/com/persistit/Tree.java 2012-06-30 15:14:20 +0000
230@@ -279,6 +279,17 @@
231 }
232
233 /**
234+ * Assign are set the tree handle. The tree must may not be a member of a
235+ * temporary volume.
236+ *
237+ * @throws PersistitException
238+ */
239+ void loadHandle() throws PersistitException {
240+ assert !_volume.isTemporary() : "Handle allocation for temporary tree " + this;
241+ _persistit.getJournalManager().handleForTree(this);
242+ }
243+
244+ /**
245 * Return an <code>Accumulator</code> for this Tree. The caller provides the
246 * type (SUM, MAX, MIN or SEQ) of accumulator, and an index value between 0
247 * and 63, inclusive. If the <code>Tree</code> does not yet have an
248
249=== modified file 'src/main/java/com/persistit/Volume.java'
250--- src/main/java/com/persistit/Volume.java 2012-06-15 14:26:11 +0000
251+++ src/main/java/com/persistit/Volume.java 2012-06-30 15:14:20 +0000
252@@ -62,6 +62,16 @@
253 private volatile VolumeStatistics _statistics;
254 private volatile VolumeStructure _structure;
255
256+ /*
257+ * These two constants are used to identify temporary volumes that may have
258+ * been identified in existing journal files due to bug 1018526. They are
259+ * used in code to detect and remove these records. Once all existing
260+ * Persistit volumes sites have been cleaned up, we can remove these
261+ * constants and the logic that depends on them.
262+ */
263+ private final static long TEMP_VOLUME_ID_FOR_FIXUP_DETECTION = 12345;
264+ private final static String TEMP_VOLUME_NAME_SUFFIX_FOR_FIXUP_DETECTION = "_temporary_volume";
265+
266 public static boolean isValidPageSize(final int pageSize) {
267 for (int b = 1024; b <= 16384; b *= 2) {
268 if (b == pageSize) {
269@@ -71,6 +81,13 @@
270 return false;
271 }
272
273+ static Volume createTemporaryVolume(final Persistit persistit, final int pageSize) throws PersistitException {
274+ Volume volume = new Volume(Thread.currentThread().getName() + TEMP_VOLUME_NAME_SUFFIX_FOR_FIXUP_DETECTION,
275+ TEMP_VOLUME_ID_FOR_FIXUP_DETECTION);
276+ volume.openTemporary(persistit, pageSize);
277+ return volume;
278+ }
279+
280 /**
281 * Construct a hollow Volume - used by JournalManager
282 *
283@@ -289,7 +306,15 @@
284 return getStructure().getDirectoryTree();
285 }
286
287- boolean isTemporary() { // TODO
288+ boolean isTemporary() {
289+ if (_storage == null) {
290+ /*
291+ * TODO - Temporary code to detect temporary volumes on existing
292+ * systems to resolve side-effects of bug 1018526.
293+ */
294+ return _id == TEMP_VOLUME_ID_FOR_FIXUP_DETECTION
295+ && _name.endsWith(TEMP_VOLUME_NAME_SUFFIX_FOR_FIXUP_DETECTION);
296+ }
297 return getStorage().isTemp();
298 }
299
300
301=== modified file 'src/main/java/com/persistit/VolumeStructure.java'
302--- src/main/java/com/persistit/VolumeStructure.java 2012-06-22 19:07:13 +0000
303+++ src/main/java/com/persistit/VolumeStructure.java 2012-06-30 15:14:20 +0000
304@@ -79,6 +79,9 @@
305 _directoryTree.setRootPageAddress(rootPageAddr);
306 updateDirectoryTree(_directoryTree);
307 }
308+ if (!_volume.isTemporary()) {
309+ _directoryTree.loadHandle();
310+ }
311 _directoryTree.setValid();
312 }
313
314@@ -188,7 +191,9 @@
315 } else {
316 return null;
317 }
318- _persistit.getJournalManager().handleForTree(tree);
319+ if (!_volume.isTemporary()) {
320+ tree.loadHandle();
321+ }
322 _treeNameHashMap.put(name, new WeakReference<Tree>(tree));
323 return tree;
324 }
325
326=== added file 'src/test/java/com/persistit/Bug1018526Test.java'
327--- src/test/java/com/persistit/Bug1018526Test.java 1970-01-01 00:00:00 +0000
328+++ src/test/java/com/persistit/Bug1018526Test.java 2012-06-30 15:14:20 +0000
329@@ -0,0 +1,104 @@
330+/**
331+ * Copyright © 2011-2012 Akiban Technologies, Inc. All rights reserved.
332+ *
333+ * This program is free software: you can redistribute it and/or modify
334+ * it under the terms of the GNU Affero General Public License as
335+ * published by the Free Software Foundation, version 3 (only) of the
336+ * License.
337+ *
338+ * This program is distributed in the hope that it will be useful,
339+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
340+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
341+ * GNU Affero General Public License for more details.
342+ *
343+ * You should have received a copy of the GNU Affero General Public License
344+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
345+ *
346+ * This program may also be available under different license terms. For more
347+ * information, see www.akiban.com or contact licensing@akiban.com.
348+ */
349+
350+package com.persistit;
351+
352+import static org.junit.Assert.*;
353+import static org.junit.Assert.assertEquals;
354+import static org.junit.Assert.assertTrue;
355+import static org.junit.Assert.fail;
356+
357+import java.util.HashSet;
358+import java.util.Map;
359+import java.util.Set;
360+
361+import org.junit.Test;
362+
363+import com.persistit.JournalManager.TreeDescriptor;
364+import com.persistit.unit.PersistitUnitTestCase;
365+
366+public class Bug1018526Test extends PersistitUnitTestCase {
367+
368+ @Test
369+ public void tempVolumesAndTreesDoNotGetHandles() throws Exception {
370+ final Volume volume = _persistit.createTemporaryVolume();
371+ final Exchange exchange = _persistit.getExchange(volume, "a_temp_tree", true);
372+ assertEquals("Handle should be 0", 0, volume.getHandle());
373+ assertEquals("Handle should be 0", 0, exchange.getTree().getHandle());
374+ }
375+
376+ @Test
377+ public void txnOnTempVolumeDoesNotWriteToJournal() throws Exception {
378+ final Transaction txn = _persistit.getTransaction();
379+ final JournalManager jman = _persistit.getJournalManager();
380+ int failed = 0;
381+ for (int i = 0; i < 10; i++) {
382+ final long startingAddress = jman.getCurrentAddress();
383+ txn.begin();
384+ try {
385+ final Volume volume = _persistit.createTemporaryVolume();
386+ final Exchange exchange = _persistit.getExchange(volume, "a_temp_tree", true);
387+ exchange.clear().append("abc");
388+ exchange.getValue().put(RED_FOX);
389+ exchange.store();
390+ txn.commit();
391+ if (jman.getCurrentAddress() != startingAddress) {
392+ failed++;
393+ }
394+ } finally {
395+ txn.end();
396+ }
397+ }
398+ /*
399+ * Don't require 0 because a checkpoint could write to the journal in a race
400+ */
401+ assertTrue("Transaction on temporary volume should not have written to journal", failed < 3);
402+ }
403+
404+ @Test
405+ public void temporaryVolumesAndTreesNotReloaded() throws Exception {
406+ final Set<Integer> permTreeHandleSet = new HashSet<Integer>();
407+ final Volume permVolume = _persistit.getVolume("persistit");
408+ _persistit.getJournalManager().unitTestAllowHandlesForTemporaryVolumesAndTrees();
409+ for (int i = 0; i < 20; i++) {
410+ final Volume tempVolume = _persistit.createTemporaryVolume();
411+ for (int j = 0; j < 10; j++) {
412+ final Tree tempTree = tempVolume.getTree("temp_tree_" + i + "_" + j, true);
413+ _persistit.getJournalManager().handleForTree(tempTree);
414+ final Tree permTree= permVolume.getTree("perm_tree_" + i + "_" + j, true);
415+ _persistit.getJournalManager().handleForTree(permTree);
416+ if (!permTreeHandleSet.add(permTree.getHandle())) {
417+ fail("Duplicate tree handle " + permTree.getHandle() + " for " + permTree);
418+ }
419+ }
420+ }
421+ final Configuration cfg = _persistit.getConfiguration();
422+ _persistit.close();
423+ _persistit = new Persistit();
424+ _persistit.initialize(cfg);
425+ Map<Integer, TreeDescriptor> map = _persistit.getJournalManager().queryTreeMap();
426+ for (Integer handle : permTreeHandleSet) {
427+ TreeDescriptor td = map.remove(handle);
428+ assertNotNull("Permanent Tree should be un the tree map", td);
429+ }
430+ // expect 1: the directory tree
431+ assertEquals("Recovered tree map should contain only permanent trees", 1, map.size());
432+ }
433+}
434
435=== modified file 'src/test/java/com/persistit/Bug932097Test.java'
436--- src/test/java/com/persistit/Bug932097Test.java 2012-05-25 18:50:59 +0000
437+++ src/test/java/com/persistit/Bug932097Test.java 2012-06-30 15:14:20 +0000
438@@ -24,9 +24,6 @@
439
440 import org.junit.Test;
441
442-import com.persistit.Exchange;
443-import com.persistit.Persistit;
444-import com.persistit.Transaction;
445 import com.persistit.unit.PersistitUnitTestCase;
446
447 public class Bug932097Test extends PersistitUnitTestCase {

Subscribers

People subscribed via source and target branches