Merge lp:~pbeaman/akiban-persistit/fix-1126868-lock-table-pruning into lp:akiban-persistit

Proposed by Peter Beaman
Status: Merged
Approved by: Peter Beaman
Approved revision: 435
Merged at revision: 424
Proposed branch: lp:~pbeaman/akiban-persistit/fix-1126868-lock-table-pruning
Merge into: lp:akiban-persistit
Diff against target: 1090 lines (+312/-112)
24 files modified
src/main/java/com/persistit/Buffer.java (+19/-12)
src/main/java/com/persistit/BufferPool.java (+2/-2)
src/main/java/com/persistit/CleanupManager.java (+14/-7)
src/main/java/com/persistit/Exchange.java (+14/-8)
src/main/java/com/persistit/IntegrityCheck.java (+1/-1)
src/main/java/com/persistit/Management.java (+8/-3)
src/main/java/com/persistit/ManagementImpl.java (+2/-0)
src/main/java/com/persistit/Persistit.java (+21/-11)
src/main/java/com/persistit/Transaction.java (+39/-0)
src/main/java/com/persistit/TransactionIndex.java (+12/-0)
src/main/java/com/persistit/Tree.java (+2/-2)
src/main/java/com/persistit/Volume.java (+20/-9)
src/main/java/com/persistit/VolumeStorageL2.java (+89/-0)
src/main/java/com/persistit/VolumeStorageT2.java (+15/-14)
src/main/java/com/persistit/VolumeStructure.java (+6/-4)
src/main/java/com/persistit/ui/AdminUISummaryPanel.java (+2/-2)
src/main/java/com/persistit/ui/AdminUITreePanel.java (+1/-1)
src/main/java/com/persistit/ui/VTComboBoxModel.java (+1/-1)
src/main/resources/com/persistit/ui/AdminUI.properties (+2/-2)
src/test/java/com/persistit/Bug1041293Test.java (+3/-2)
src/test/java/com/persistit/CleanupManagerTest.java (+3/-1)
src/test/java/com/persistit/ExchangeLockTest.java (+29/-24)
src/test/java/com/persistit/MVCCPruneBufferTest.java (+5/-5)
src/test/java/com/persistit/TestShim.java (+2/-1)
To merge this branch: bzr merge lp:~pbeaman/akiban-persistit/fix-1126868-lock-table-pruning
Reviewer Review Type Date Requested Status
Akiban Build User Needs Fixing
Nathan Williams Approve
Review via email: mp+152063@code.launchpad.net

Description of the change

Fixes bug1126868. The bug is that in a typical data loading scenario, or in any process where update transactions are performing a large volume of locks, the lock volume can be overwhelmed with new entries in such a way that obsolete entries are never pruned. When that happens the lock volume grows rapidly, and in one server test exceeds the 2GB sanity limit for temporary volumes.

A new test in ExchangeLockTest demonstrates the phenomenon by simply creating a large number of locks (10,000) in each of 500 transactions. Prior to the fix this test causes runaway growth of the lock volume.

This proposal fixes this phenomenon by adding a new pruning mode in which all locks are synchronously pruned upon when a transaction that has used any locks either commits or aborts.

The majority of the changes provide plumbing so that a call to Buffer#pruneMvvValues can return a List of consequent CleanupAction instances rather than enqueuing them on the CleanupManager. These are the applied during the call to Transaction#end so that the transaction cannot leave unpruned locks. In general this is efficient because the lock volume _should be_ small, and therefore memory resident. We hope never to see lock volume pages written to disk.

This branch also fixes a couple of related issues discovered while diagnosing and fixing the problem.

(1) Temporary volumes are not designed to be threadsafe. So there is now a new VolumeStorageL2 class that combines behavior of VolumeStorageT2 and VolumeStorageV2. In particular, VolumeStorageL2 has a head page that is used for synchronization. Also, since there is at most a single lock volume in the system, it now has a distinguished name, and it appears on the visible volumes list in the UI.

(2) The UI was using the volume's path as its identifier. This has been wrong, but unnoticed, for some time. The UI now uses the name as the unique identifier, and it now possible to examine trees in the lock volume using the UI. One minor change in the AdminUI.properties file swaps the name and path columns of the UI's main page.

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

Does pruneLockPages() really need to call updateActiveTransactionCache()? It already happens every 10ms and doing it synchronously seems unnecessary.

VolumeStorageT2 and L2 are 99% identical. Can we pull some of that out into a base class, particularly the non-trivial stuff like read and write page? The javadoc also wasn't changed for L2.

Otherwise looks fine.

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

Yes, removing the call to updateActiveTransactionCache makes the test fail. My hope is that by adding an update timestamp condition to it, there will be many instances where the update will happen asynchronously while the commit is being completed so that on a busy system we don't add an overwhelming number of synchronous executions.

Good point about L2. It is now a subclass of T2 with almost no code and corrected Javadoc.

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

Making transactions that perform writes slower by doing the cache update synchronously seems like a bad conscious choice to make. Bucket locking, which recomputing the cache does, is exclusive right now. I have a feeling this will really hurt concurrency.

Do we have any perf tests for this or am I being too pessimistic?

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

I don't like it either, but I couldn't find another way to solve the
problem. I guess the question we need to ask is how many transactions will
actually lock something. Certainly no read transactions. Can you suggest
a good multi-thread concurrent server benchmark?

On Mon, Mar 11, 2013 at 4:08 PM, Nathan Williams <email address hidden>wrote:

> Making transactions that perform writes slower by doing the cache update
> synchronously seems like a bad conscious choice to make. Bucket locking,
> which recomputing the cache does, is exclusive right now. I have a feeling
> this will really hurt concurrency.
>
> Do we have any perf tests for this or am I being too pessimistic?
> --
>
> https://code.launchpad.net/~pbeaman/akiban-persistit/fix-1126868-lock-table-pruning/+merge/152063
> You are the owner of
> lp:~pbeaman/akiban-persistit/fix-1126868-lock-table-pruning.
>

Revision history for this message
Thomas Jones-Low (tjoneslo) wrote :

The Multi-Thread Test (MTT) in the akiban-build-scripts repository is designed for this purpose.

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

Peter and I discussed this offline. Merging this now makes sense and we can double check the data-loading-test works as desired.

We can confirm concurrency impact in parallel/after and if there is a problem, there is a bucket level change that probably makes sense.

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

There were 2 failures during build/test:

* job server-build failed at build number 3869: http://172.16.20.104:8080/job/server-build/3869/

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

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

Approving this again. The failure is strange, and the line numbers displayed in the stack traces don't match the code. I will watch this build.

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

There were 2 failures during build/test:

* job server-build failed at build number 3879: http://172.16.20.104:8080/job/server-build/3879/

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

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

Server tests run fine on local machine, but fail on build machine. Adding better logging and Approving in attempt to diagnose the problem.

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

There were 2 failures during build/test:

* job server-build failed at build number 3881: http://172.16.20.104:8080/job/server-build/3881/

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

review: Needs Fixing
434. By Peter Beaman

Correct BufferSizeUnavailableException cases

435. By Peter Beaman

Get buffer pool from volume structure instead of lookup by page size

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

Trying yet again with some additional changes.

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 2013-01-19 17:52:20 +0000
3+++ src/main/java/com/persistit/Buffer.java 2013-03-13 17:42:20 +0000
4@@ -26,6 +26,7 @@
5 import java.util.List;
6 import java.util.Set;
7
8+import com.persistit.CleanupManager.CleanupAction;
9 import com.persistit.CleanupManager.CleanupAntiValue;
10 import com.persistit.Exchange.Sequence;
11 import com.persistit.JournalRecord.IV;
12@@ -522,7 +523,7 @@
13 final Volume volume = getVolume();
14 if (volume != null) {
15 if (prune) {
16- pruneMvvValues(null, false);
17+ pruneMvvValues(null, false, null);
18 }
19 clearSlack();
20 save();
21@@ -3599,7 +3600,8 @@
22 * buffer
23 * @throws PersistitException
24 */
25- boolean pruneMvvValues(final Tree tree, final boolean pruneLongMVVs) throws PersistitException {
26+ boolean pruneMvvValues(final Tree tree, final boolean pruneLongMVVs, final List<CleanupAction> cleanupActions)
27+ throws PersistitException {
28 boolean changed = false;
29 try {
30 boolean hasLongMvvRecords = false;
31@@ -3611,7 +3613,7 @@
32 final long timestamp = _persistit.getTimestampAllocator().updateTimestamp();
33 _mvvCount = 0;
34 writePageOnCheckpoint(timestamp);
35- final int flags = pruneMvvValuesHelper(tree);
36+ final int flags = pruneMvvValuesHelper(tree, cleanupActions);
37 changed = (flags & PRUNE_MVV_HELPER_CHANGED) != 0;
38 hasLongMvvRecords = (flags & PRUNE_MVV_HELPER_HAS_LONG) != 0;
39
40@@ -3627,7 +3629,7 @@
41
42 final Buffer copy = new Buffer(this);
43 final boolean copyChanged = copy.pruneLongMvvValues(tree, prunedVersions, deferredExceptions,
44- oldChainsToDeallocate);
45+ oldChainsToDeallocate, cleanupActions);
46 if (copyChanged) {
47 changed = true;
48 final long copyTimestamp = _persistit.getTimestampAllocator().updateTimestamp();
49@@ -3662,7 +3664,8 @@
50 return changed;
51 }
52
53- private int pruneMvvValuesHelper(final Tree tree) throws PersistitException {
54+ private int pruneMvvValuesHelper(final Tree tree, final List<CleanupAction> cleanupActions)
55+ throws PersistitException {
56 boolean changed = false;
57 boolean hasLongMvvRecords = false;
58 final List<PrunedVersion> prunedVersions = new ArrayList<PrunedVersion>();
59@@ -3708,7 +3711,7 @@
60 incCountIfMvv(_bytes, offset, newSize);
61 }
62
63- if (pruneAntiValue(valueByte, p, tree)) {
64+ if (pruneAntiValue(valueByte, p, tree, cleanupActions)) {
65 changed = true;
66 p -= KEYBLOCK_LENGTH;
67 }
68@@ -3726,7 +3729,8 @@
69 * successful completion of this process.
70 */
71 private boolean pruneLongMvvValues(final Tree tree, final List<PrunedVersion> prunedVersions,
72- final List<PersistitException> deferredExceptions, final List<Long> toDeallocate) {
73+ final List<PersistitException> deferredExceptions, final List<Long> toDeallocate,
74+ final List<CleanupAction> cleanupActions) {
75
76 boolean changed = false;
77 for (int p = KEY_BLOCK_START; p < _keyBlockEnd; p += KEYBLOCK_LENGTH) {
78@@ -3768,7 +3772,7 @@
79 value.changeLongRecordMode(false);
80 }
81 }
82- if (pruneAntiValue(valueByte, p, tree)) {
83+ if (pruneAntiValue(valueByte, p, tree, cleanupActions)) {
84 changed = true;
85 p -= KEYBLOCK_LENGTH;
86 }
87@@ -3781,13 +3785,16 @@
88 return changed;
89 }
90
91- private boolean pruneAntiValue(final int valueByte, final int p, final Tree tree) {
92+ private boolean pruneAntiValue(final int valueByte, final int p, final Tree tree,
93+ final List<CleanupAction> cleanupActions) {
94 if (valueByte == MVV.TYPE_ANTIVALUE) {
95 if (p == KEY_BLOCK_START) {
96 if (tree != null) {
97- if (!_enqueuedForAntiValuePruning) {
98- final int treeHandle = tree.getHandle();
99- assert treeHandle != 0 : "MVV found in a temporary tree " + tree;
100+ final int treeHandle = tree.getHandle();
101+ assert treeHandle != 0 : "MVV found in a temporary tree " + tree;
102+ if (cleanupActions != null) {
103+ cleanupActions.add(new CleanupAntiValue(treeHandle, getPageAddress()));
104+ } else if (!_enqueuedForAntiValuePruning) {
105 if (_persistit.getCleanupManager().offer(new CleanupAntiValue(treeHandle, getPageAddress()))) {
106 _enqueuedForAntiValuePruning = true;
107 }
108
109=== modified file 'src/main/java/com/persistit/BufferPool.java'
110--- src/main/java/com/persistit/BufferPool.java 2013-01-28 10:42:29 +0000
111+++ src/main/java/com/persistit/BufferPool.java 2013-03-13 17:42:20 +0000
112@@ -789,7 +789,7 @@
113 // page will find it.
114 //
115 buffer.setValid();
116- if (vol.isTemporary()) {
117+ if (vol.isTemporary() || vol.isLockVolume()) {
118 buffer.setTemporary();
119 } else {
120 buffer.clearTemporary();
121@@ -1468,7 +1468,7 @@
122 }
123 Util.spinSleep();
124 }
125- if (volume1 != null && !volume1.isTemporary()) {
126+ if (volume1 != null && !volume1.isTemporary() && !volume1.isLockVolume()) {
127 value.clear().setStreamMode(true);
128 value.put(volume1.getHandle());
129 value.put(page1);
130
131=== modified file 'src/main/java/com/persistit/CleanupManager.java'
132--- src/main/java/com/persistit/CleanupManager.java 2012-11-26 17:19:45 +0000
133+++ src/main/java/com/persistit/CleanupManager.java 2013-03-13 17:42:20 +0000
134@@ -33,7 +33,7 @@
135
136 interface CleanupAction extends Comparable<CleanupAction> {
137
138- void performAction(Persistit persistit) throws PersistitException;
139+ void performAction(Persistit persistit, List<CleanupAction> consequentActions) throws PersistitException;
140 }
141
142 final static long DEFAULT_CLEANUP_INTERVAL_MS = 1000;
143@@ -177,7 +177,7 @@
144
145 for (final CleanupAction action : workList) {
146 try {
147- action.performAction(_persistit);
148+ action.performAction(_persistit, null);
149 _performed.incrementAndGet();
150 } catch (final PersistitException e) {
151 lastException(e);
152@@ -227,7 +227,11 @@
153 } else {
154 return false;
155 }
156+ }
157
158+ @Override
159+ public int hashCode() {
160+ return (int) (_treeHandle ^ _page);
161 }
162
163 @Override
164@@ -275,10 +279,11 @@
165 }
166
167 @Override
168- public void performAction(final Persistit persistit) throws PersistitException {
169+ public void performAction(final Persistit persistit, final List<CleanupAction> consequentActions)
170+ throws PersistitException {
171 final Exchange exchange = getExchange(persistit);
172 if (exchange != null) {
173- exchange.pruneLeftEdgeValue(_page);
174+ exchange.pruneLeftEdgeValue(_page, consequentActions);
175 }
176 }
177 }
178@@ -290,10 +295,11 @@
179 }
180
181 @Override
182- public void performAction(final Persistit persistit) throws PersistitException {
183+ public void performAction(final Persistit persistit, final List<CleanupAction> consequentActions)
184+ throws PersistitException {
185 final Exchange exchange = getExchange(persistit);
186 if (exchange != null) {
187- exchange.prune(_page);
188+ exchange.prune(_page, consequentActions);
189 }
190 }
191 }
192@@ -307,7 +313,8 @@
193 }
194
195 @Override
196- public void performAction(final Persistit persistit) throws PersistitException {
197+ public void performAction(final Persistit persistit, final List<CleanupAction> consequentActions)
198+ throws PersistitException {
199 final Exchange exchange = getExchange(persistit);
200 if (exchange != null) {
201 exchange.fixIndexHole(_page, _level);
202
203=== modified file 'src/main/java/com/persistit/Exchange.java'
204--- src/main/java/com/persistit/Exchange.java 2013-01-24 18:18:40 +0000
205+++ src/main/java/com/persistit/Exchange.java 2013-03-13 17:42:20 +0000
206@@ -40,11 +40,13 @@
207 import java.util.ArrayList;
208 import java.util.List;
209
210+import com.persistit.CleanupManager.CleanupAction;
211 import com.persistit.Key.Direction;
212 import com.persistit.MVV.PrunedVersion;
213 import com.persistit.ValueHelper.MVVValueWriter;
214 import com.persistit.ValueHelper.RawValueWriter;
215 import com.persistit.VolumeStructure.Chain;
216+import com.persistit.exception.BufferSizeUnavailableException;
217 import com.persistit.exception.CorruptVolumeException;
218 import com.persistit.exception.InUseException;
219 import com.persistit.exception.PersistitException;
220@@ -400,6 +402,7 @@
221 *
222 * @param tree
223 * The <code>Tree</code> to access.
224+ * @throws BufferSizeUnavailableException
225 */
226 public Exchange(final Tree tree) {
227 this(tree._persistit);
228@@ -427,7 +430,8 @@
229 final Volume volume = tree.getVolume();
230 _ignoreTransactions = volume.isTemporary();
231 _ignoreMVCCFetch = false;
232- _pool = _persistit.getBufferPool(volume.getPageSize());
233+ _pool = volume.getStructure().getPool();
234+
235 _transaction = _persistit.getTransaction();
236 _key.clear();
237 _value.clear();
238@@ -1640,7 +1644,7 @@
239 if (splitRequired && !treeClaimAcquired) {
240 if (!didPrune && buffer.isDataPage()) {
241 didPrune = true;
242- if (buffer.pruneMvvValues(_tree, false)) {
243+ if (buffer.pruneMvvValues(_tree, false, null)) {
244 continue;
245 }
246 }
247@@ -1856,7 +1860,6 @@
248 Debug.$assert0.t((buffer.getStatus() & SharedResource.WRITER_MASK) != 0
249 && (buffer.getStatus() & SharedResource.CLAIMED_MASK) != 0);
250 final Sequence sequence = lc.sequence(foundAt);
251-
252 long timestamp = timestamp();
253 buffer.writePageOnCheckpoint(timestamp);
254
255@@ -2853,6 +2856,9 @@
256 lockExchange.getValue().clear().putAntiValueMVV();
257 final int options = StoreOptions.WAIT | StoreOptions.DONT_JOURNAL | StoreOptions.MVCC;
258 lockExchange.storeInternal(lockExchange.getKey(), lockExchange.getValue(), 0, options);
259+ final long page = lockExchange._levelCache[0]._page;
260+ _transaction.addLockPage(page, lockExchange.getTree().getHandle());
261+ _persistit.releaseExchange(lockExchange);
262 }
263
264 /**
265@@ -3993,7 +3999,7 @@
266 search(key, true);
267 buffer = _levelCache[0]._buffer;
268 if (buffer != null) {
269- return buffer.pruneMvvValues(_tree, true);
270+ return buffer.pruneMvvValues(_tree, true, null);
271 } else {
272 return false;
273 }
274@@ -4015,7 +4021,7 @@
275
276 while (buffer != null) {
277 checkPageType(buffer, Buffer.PAGE_TYPE_DATA, false);
278- pruned |= buffer.pruneMvvValues(_tree, true);
279+ pruned |= buffer.pruneMvvValues(_tree, true, null);
280 final int foundAt = buffer.findKey(key2);
281 if (!buffer.isAfterRightEdge(foundAt)) {
282 break;
283@@ -4037,11 +4043,11 @@
284 return pruned;
285 }
286
287- boolean prune(final long page) throws PersistitException {
288+ boolean prune(final long page, final List<CleanupAction> consequentActions) throws PersistitException {
289 Buffer buffer = null;
290 try {
291 buffer = _pool.get(_volume, page, true, true);
292- return buffer.pruneMvvValues(_tree, true);
293+ return buffer.pruneMvvValues(_tree, true, consequentActions);
294 } finally {
295 if (buffer != null) {
296 buffer.release();
297@@ -4049,7 +4055,7 @@
298 }
299 }
300
301- boolean pruneLeftEdgeValue(final long page) throws PersistitException {
302+ boolean pruneLeftEdgeValue(final long page, final List<CleanupAction> consequentActions) throws PersistitException {
303 _ignoreTransactions = true;
304 Buffer buffer = null;
305 try {
306
307=== modified file 'src/main/java/com/persistit/IntegrityCheck.java'
308--- src/main/java/com/persistit/IntegrityCheck.java 2012-09-12 22:02:22 +0000
309+++ src/main/java/com/persistit/IntegrityCheck.java 2013-03-13 17:42:20 +0000
310@@ -1170,7 +1170,7 @@
311 _counters._mvvPageCount++;
312 if (_prune && !_currentVolume.isReadOnly() && _counters._pruningErrorCount < MAX_PRUNING_ERRORS) {
313 try {
314- buffer.pruneMvvValues(tree, true);
315+ buffer.pruneMvvValues(tree, true, null);
316 _counters._prunedPageCount++;
317 } catch (final PersistitException e) {
318 _counters._pruningErrorCount++;
319
320=== modified file 'src/main/java/com/persistit/Management.java'
321--- src/main/java/com/persistit/Management.java 2012-08-31 14:06:47 +0000
322+++ src/main/java/com/persistit/Management.java 2013-03-13 17:42:20 +0000
323@@ -464,7 +464,7 @@
324 * occurred while attempting to acquire the Class.
325 * @throws RemoteException
326 */
327- public Class getRemoteClass(String className) throws RemoteException;
328+ public Class<?> getRemoteClass(String className) throws RemoteException;
329
330 /**
331 * Return the <code>VolumeInfo</code> for the volume specified by the
332@@ -1450,7 +1450,7 @@
333 * returns information about all open Volumes in an array of
334 * <code>VolumeInfo</code> elements.
335 */
336- public static class VolumeInfo extends AcquisitionTimeBase implements Serializable {
337+ public static class VolumeInfo extends AcquisitionTimeBase implements Serializable, Comparable<VolumeInfo> {
338 public final static long serialVersionUID = -1231320633942497896L;
339
340 int pageSize;
341@@ -1785,7 +1785,12 @@
342 @Override
343 public boolean equals(final Object object) {
344 return object instanceof VolumeInfo && ((VolumeInfo) object).getId() == id
345- && ((VolumeInfo) object).getPath().equals(path);
346+ && ((VolumeInfo) object).getName().equals(name);
347+ }
348+
349+ @Override
350+ public int compareTo(final VolumeInfo volumeInfo) {
351+ return name.compareTo(volumeInfo.name);
352 }
353 }
354
355
356=== modified file 'src/main/java/com/persistit/ManagementImpl.java'
357--- src/main/java/com/persistit/ManagementImpl.java 2012-08-24 13:57:19 +0000
358+++ src/main/java/com/persistit/ManagementImpl.java 2013-03-13 17:42:20 +0000
359@@ -22,6 +22,7 @@
360 import java.rmi.registry.LocateRegistry;
361 import java.rmi.server.UnicastRemoteObject;
362 import java.util.ArrayList;
363+import java.util.Arrays;
364 import java.util.HashMap;
365 import java.util.Iterator;
366 import java.util.List;
367@@ -798,6 +799,7 @@
368 for (int index = 0; index < volumes.size(); index++) {
369 result[index] = new VolumeInfo(volumes.get(index));
370 }
371+ Arrays.sort(result);
372 return result;
373 }
374
375
376=== modified file 'src/main/java/com/persistit/Persistit.java'
377--- src/main/java/com/persistit/Persistit.java 2013-02-26 17:23:35 +0000
378+++ src/main/java/com/persistit/Persistit.java 2013-03-13 17:42:20 +0000
379@@ -1079,15 +1079,7 @@
380 * @throws PersistitException
381 */
382 public Volume createTemporaryVolume() throws PersistitException {
383- int pageSize = _configuration.getTmpVolPageSize();
384- if (pageSize == 0) {
385- for (final int size : _bufferPoolTable.keySet()) {
386- if (size > pageSize) {
387- pageSize = size;
388- }
389- }
390- }
391- return createTemporaryVolume(pageSize);
392+ return createTemporaryVolume(temporaryVolumePageSize());
393 }
394
395 /**
396@@ -1115,6 +1107,18 @@
397 return Volume.createTemporaryVolume(this, pageSize, directory);
398 }
399
400+ private int temporaryVolumePageSize() {
401+ int pageSize = _configuration.getTmpVolPageSize();
402+ if (pageSize == 0) {
403+ for (final int size : _bufferPoolTable.keySet()) {
404+ if (size > pageSize) {
405+ pageSize = size;
406+ }
407+ }
408+ }
409+ return pageSize;
410+ }
411+
412 /**
413 * Delete a volume currently loaded volume and remove it from the list
414 * returned by {@link #getVolumes()}.
415@@ -1296,8 +1300,14 @@
416 checkInitialized();
417 checkClosed();
418 if (_lockVolume == null) {
419- _lockVolume = createTemporaryVolume();
420- _lockVolume.setHandle(Volume.LOCK_VOLUME_HANDLE);
421+ final int pageSize = temporaryVolumePageSize();
422+ if (!Volume.isValidPageSize(pageSize)) {
423+ throw new IllegalArgumentException("Invalid page size " + pageSize);
424+ }
425+ final String directoryName = getConfiguration().getTmpVolDir();
426+ final File directory = directoryName == null ? null : new File(directoryName);
427+ _lockVolume = Volume.createLockVolume(this, pageSize, directory);
428+ _volumes.add(_lockVolume);
429 }
430 return _lockVolume;
431 }
432
433=== modified file 'src/main/java/com/persistit/Transaction.java'
434--- src/main/java/com/persistit/Transaction.java 2013-02-20 16:52:45 +0000
435+++ src/main/java/com/persistit/Transaction.java 2013-03-13 17:42:20 +0000
436@@ -21,8 +21,14 @@
437 import static com.persistit.util.ThreadSequencer.sequence;
438
439 import java.nio.ByteBuffer;
440+import java.util.ArrayList;
441+import java.util.HashSet;
442+import java.util.List;
443+import java.util.Set;
444
445 import com.persistit.Accumulator.Delta;
446+import com.persistit.CleanupManager.CleanupAction;
447+import com.persistit.CleanupManager.CleanupPruneAction;
448 import com.persistit.JournalRecord.D0;
449 import com.persistit.JournalRecord.D1;
450 import com.persistit.JournalRecord.DR;
451@@ -434,6 +440,8 @@
452
453 private String _threadName;
454
455+ private final Set<CleanupAction> _lockCleanupActions = new HashSet<CleanupAction>();
456+
457 public static enum CommitPolicy {
458 /**
459 * The {@link Transaction#commit} method returns before all updates have
460@@ -675,6 +683,11 @@
461 _commitCount++;
462 _rollbacksSinceLastCommit = 0;
463 }
464+ try {
465+ pruneLockPages();
466+ } catch (Exception e) {
467+ _persistit.getLogBase().pruneException.log(e, "locks");
468+ }
469 _transactionStatus = null;
470 _rollbackPending = false;
471 _threadName = null;
472@@ -1317,6 +1330,32 @@
473 return treeHandle;
474 }
475
476+ void addLockPage(final Long page, final int treeHandle) {
477+ _lockCleanupActions.add(new CleanupPruneAction(treeHandle, page));
478+ }
479+
480+ void pruneLockPages() {
481+ if (_lockCleanupActions.isEmpty()) {
482+ return;
483+ }
484+
485+ _persistit.getTransactionIndex().updateActiveTransactionCache(_commitTimestamp);
486+ List<CleanupAction> actions = new ArrayList<CleanupAction>(_lockCleanupActions);
487+ _lockCleanupActions.clear();
488+
489+ while (!actions.isEmpty()) {
490+ final List<CleanupAction> consequentActions = new ArrayList<CleanupAction>();
491+ for (final CleanupAction cleanupAction : actions) {
492+ try {
493+ cleanupAction.performAction(_persistit, consequentActions);
494+ } catch (final PersistitException pe) {
495+ _persistit.getLogBase().pruneException.log(pe, this);
496+ }
497+ actions = consequentActions;
498+ }
499+ }
500+ }
501+
502 /**
503 * For unit tests only
504 *
505
506=== modified file 'src/main/java/com/persistit/TransactionIndex.java'
507--- src/main/java/com/persistit/TransactionIndex.java 2012-10-26 19:44:17 +0000
508+++ src/main/java/com/persistit/TransactionIndex.java 2013-03-13 17:42:20 +0000
509@@ -969,6 +969,18 @@
510 }
511 }
512
513+ /**
514+ * Update the floor only if it is smaller than the supplied timestamp.
515+ *
516+ * @param ts
517+ * The timestamp
518+ */
519+ public void updateActiveTransactionCache(final long ts) {
520+ if (_atCache._floor < ts) {
521+ updateActiveTransactionCache();
522+ }
523+ }
524+
525 /*
526 * (non-Javadoc)
527 *
528
529=== modified file 'src/main/java/com/persistit/Tree.java'
530--- src/main/java/com/persistit/Tree.java 2013-01-19 17:42:22 +0000
531+++ src/main/java/com/persistit/Tree.java 2013-03-13 17:42:20 +0000
532@@ -244,8 +244,8 @@
533 */
534 @Override
535 public String toString() {
536- return "<Tree " + _name + " rootPageAddr=" + _rootPageAddr + " depth=" + _depth + " status="
537- + getStatusDisplayString() + ">";
538+ return "<Tree " + _name + " in volume " + _volume.getName() + " rootPageAddr=" + _rootPageAddr + " depth="
539+ + _depth + " status=" + getStatusDisplayString() + ">";
540 }
541
542 /**
543
544=== modified file 'src/main/java/com/persistit/Volume.java'
545--- src/main/java/com/persistit/Volume.java 2013-01-19 17:42:22 +0000
546+++ src/main/java/com/persistit/Volume.java 2013-03-13 17:42:20 +0000
547@@ -20,6 +20,7 @@
548 import java.util.concurrent.atomic.AtomicInteger;
549 import java.util.concurrent.atomic.AtomicReference;
550
551+import com.persistit.exception.BufferSizeUnavailableException;
552 import com.persistit.exception.InUseException;
553 import com.persistit.exception.PersistitException;
554 import com.persistit.exception.ReadOnlyVolumeException;
555@@ -49,6 +50,7 @@
556 public class Volume {
557
558 final static int LOCK_VOLUME_HANDLE = Integer.MAX_VALUE;
559+ final static String LOCK_VOLUME_NAME = "_lock";
560
561 private final String _name;
562 private long _id;
563@@ -86,7 +88,21 @@
564 final Volume volume = new Volume(
565 Thread.currentThread().getName() + TEMP_VOLUME_NAME_SUFFIX_FOR_FIXUP_DETECTION,
566 TEMP_VOLUME_ID_FOR_FIXUP_DETECTION);
567- volume.openTemporary(persistit, pageSize, tempDirectory);
568+ volume.openInternal(persistit, pageSize);
569+
570+ volume._storage = new VolumeStorageT2(persistit, volume, tempDirectory);
571+ volume._storage.create();
572+
573+ return volume;
574+ }
575+
576+ static Volume createLockVolume(final Persistit persistit, final int pageSize, final File tempDirectory)
577+ throws PersistitException {
578+ final Volume volume = new Volume(LOCK_VOLUME_NAME, 0);
579+ volume.setHandle(Volume.LOCK_VOLUME_HANDLE);
580+ volume.openInternal(persistit, pageSize);
581+ volume._storage = new VolumeStorageL2(persistit, volume, tempDirectory);
582+ volume._storage.create();
583 return volume;
584 }
585
586@@ -452,7 +468,7 @@
587 throw new UnderSpecifiedVolumeException(getName());
588 }
589 if (persistit.getBufferPool(_specification.getPageSize()) == null) {
590- throw new IllegalStateException(getName());
591+ throw new BufferSizeUnavailableException(getName());
592 }
593 final boolean exists = VolumeHeader.verifyVolumeHeader(_specification, persistit.getCurrentTimestamp());
594
595@@ -485,21 +501,16 @@
596 persistit.addVolume(this);
597 }
598
599- void openTemporary(final Persistit persistit, final int pageSize, final File tempDirectory)
600- throws PersistitException {
601+ private void openInternal(final Persistit persistit, final int pageSize) throws PersistitException {
602 checkClosing();
603 if (_storage != null) {
604 throw new IllegalStateException("This volume has already been opened");
605 }
606 if (persistit.getBufferPool(pageSize) == null) {
607- throw new IllegalStateException("There is no buffer pool for pages of size " + pageSize);
608+ throw new BufferSizeUnavailableException("There is no buffer pool for pages of size " + pageSize);
609 }
610-
611 _structure = new VolumeStructure(persistit, this, pageSize);
612- _storage = new VolumeStorageT2(persistit, this, tempDirectory);
613 _statistics = new VolumeStatistics();
614-
615- _storage.create();
616 }
617
618 public String getName() {
619
620=== added file 'src/main/java/com/persistit/VolumeStorageL2.java'
621--- src/main/java/com/persistit/VolumeStorageL2.java 1970-01-01 00:00:00 +0000
622+++ src/main/java/com/persistit/VolumeStorageL2.java 2013-03-13 17:42:20 +0000
623@@ -0,0 +1,89 @@
624+/**
625+ * Copyright © 2011-2012 Akiban Technologies, Inc. All rights reserved.
626+ *
627+ * This program and the accompanying materials are made available
628+ * under the terms of the Eclipse Public License v1.0 which
629+ * accompanies this distribution, and is available at
630+ * http://www.eclipse.org/legal/epl-v10.html
631+ *
632+ * This program may also be available under different license terms.
633+ * For more information, see www.akiban.com or contact licensing@akiban.com.
634+ *
635+ * Contributors:
636+ * Akiban Technologies, Inc.
637+ */
638+
639+package com.persistit;
640+
641+import java.io.File;
642+
643+import com.persistit.exception.InUseException;
644+import com.persistit.exception.PersistitException;
645+
646+/**
647+ * Manage all details of file I/O for a special <code>Volume</code> that backs
648+ * the {@link Exchange#lock()} method. The lock volume differs from a temporary
649+ * volume in the following ways:
650+ * <ul>
651+ * <li>It has a defined name and is visible in the
652+ * {@link Persistit#getVolumes()} array.</li>
653+ * <li>It is threadsafe.</li>
654+ * </ul>
655+ * Like a temporary volume, it is intended that pages of the lock volume should
656+ * seldom, if ever, need to be written to disk. And also like a temporary
657+ * volume, the contents of the lock volume are not recovered during startup.
658+ *
659+ * @author peter
660+ */
661+class VolumeStorageL2 extends VolumeStorageT2 {
662+
663+ final static String LOCK_VOLUME_FILE_PREFIX = "persistit_lockvol_";
664+ private Buffer _headBuffer;
665+
666+ VolumeStorageL2(final Persistit persistit, final Volume volume, final File tempDirectory) {
667+ super(persistit, volume, tempDirectory);
668+ }
669+
670+ /**
671+ * Indicate whether this is a temporary volume. The Lock volume is not
672+ * temporary, although it inherits most of the characteristics of a
673+ * temporary volume.
674+ *
675+ * @return <code>true</code> if this volume is temporary
676+ */
677+ @Override
678+ boolean isTemp() {
679+ return false;
680+ }
681+
682+ @Override
683+ void truncate() throws PersistitException {
684+ if (!claim(true, 0)) {
685+ throw new InUseException("Unable to acquire claim on " + this);
686+ }
687+ try {
688+ _headBuffer = _volume.getStructure().getPool().get(_volume, 0, true, false);
689+ _headBuffer.init(Buffer.PAGE_TYPE_HEAD);
690+ _headBuffer.setFixed();
691+
692+ truncateInternal();
693+ releaseHeadBuffer();
694+
695+ } finally {
696+ release();
697+ }
698+ }
699+
700+ @Override
701+ void claimHeadBuffer() throws PersistitException {
702+ if (!_headBuffer.claim(true)) {
703+ throw new InUseException("Unable to acquire claim on " + _headBuffer);
704+ }
705+ }
706+
707+ @Override
708+ void releaseHeadBuffer() {
709+ _headBuffer.release();
710+ }
711+
712+}
713
714=== modified file 'src/main/java/com/persistit/VolumeStorageT2.java'
715--- src/main/java/com/persistit/VolumeStorageT2.java 2013-01-04 00:12:33 +0000
716+++ src/main/java/com/persistit/VolumeStorageT2.java 2013-03-13 17:42:20 +0000
717@@ -44,7 +44,6 @@
718 class VolumeStorageT2 extends VolumeStorage {
719
720 final static String TEMP_FILE_PREFIX = "persistit_tempvol_";
721- private final static String TEMP_FILE_UNCREATED_NAME = "temp_volume_file_not_created_yet";
722 private final File _tempDirectory;
723 private long _maxPages;
724 private volatile String _path;
725@@ -117,7 +116,7 @@
726 void create() throws PersistitException {
727 final long maxSize = _persistit.getConfiguration().getTmpVolMaxSize();
728 _maxPages = maxSize / _volume.getStructure().getPageSize();
729- _path = TEMP_FILE_UNCREATED_NAME;
730+ _path = "";
731 _channel = null;
732 truncate();
733 _opened = true;
734@@ -220,21 +219,23 @@
735 throw new InUseException("Unable to acquire claim on " + this);
736 }
737 try {
738- final VolumeStatistics stat = _volume.getStatistics();
739- final VolumeStructure struc = _volume.getStructure();
740-
741- final long now = System.currentTimeMillis();
742- stat.setCreateTime(now);
743- stat.setOpenTime(now);
744-
745- _nextAvailablePage = 1;
746-
747- struc.init(0, 0);
748+ truncateInternal();
749 } finally {
750 release();
751 }
752- flushMetaData();
753-
754+ }
755+
756+ protected void truncateInternal() throws PersistitException {
757+ final VolumeStatistics stat = _volume.getStatistics();
758+ final VolumeStructure struc = _volume.getStructure();
759+
760+ final long now = System.currentTimeMillis();
761+ stat.setCreateTime(now);
762+ stat.setOpenTime(now);
763+
764+ _nextAvailablePage = 1;
765+
766+ struc.init(0, 0);
767 }
768
769 @Override
770
771=== modified file 'src/main/java/com/persistit/VolumeStructure.java'
772--- src/main/java/com/persistit/VolumeStructure.java 2012-11-28 17:13:21 +0000
773+++ src/main/java/com/persistit/VolumeStructure.java 2013-03-13 17:42:20 +0000
774@@ -26,6 +26,7 @@
775
776 import com.persistit.AlertMonitor.AlertLevel;
777 import com.persistit.AlertMonitor.Event;
778+import com.persistit.exception.BufferSizeUnavailableException;
779 import com.persistit.exception.CorruptVolumeException;
780 import com.persistit.exception.InUseException;
781 import com.persistit.exception.PersistitException;
782@@ -128,13 +129,13 @@
783 _persistit.getJournalManager().truncate(_volume, timestamp);
784 }
785
786- Exchange directoryExchange() {
787+ Exchange directoryExchange() throws BufferSizeUnavailableException {
788 final Exchange ex = new Exchange(_directoryTree);
789 ex.ignoreTransactions();
790 return ex;
791 }
792
793- Exchange accumulatorExchange() {
794+ Exchange accumulatorExchange() throws BufferSizeUnavailableException {
795 return new Exchange(_directoryTree);
796 }
797
798@@ -502,7 +503,9 @@
799 return buffer;
800 } finally {
801 garbageBuffer = releaseBuffer(garbageBuffer);
802- deallocateGarbageChain(chains);
803+ if (!chains.isEmpty()) {
804+ deallocateGarbageChain(chains);
805+ }
806 }
807 }
808 } finally {
809@@ -517,7 +520,6 @@
810 buffer.init(Buffer.PAGE_TYPE_UNALLOCATED);
811 Debug.$assert0.t(buffer.getPageAddress() != 0);
812 return buffer;
813-
814 }
815
816 void deallocateGarbageChain(final long left, final long right) throws PersistitException {
817
818=== modified file 'src/main/java/com/persistit/ui/AdminUISummaryPanel.java'
819--- src/main/java/com/persistit/ui/AdminUISummaryPanel.java 2012-08-24 13:57:19 +0000
820+++ src/main/java/com/persistit/ui/AdminUISummaryPanel.java 2013-03-13 17:42:20 +0000
821@@ -250,7 +250,7 @@
822 final Management.VolumeInfo[] array = (Management.VolumeInfo[]) _volumeInfoArrayModel
823 .getInfoArray();
824 if (array != null && index < array.length) {
825- _selectedVolumeName = array[index].getPath();
826+ _selectedVolumeName = array[index].getName();
827 } else {
828 _selectedVolumeName = null;
829 }
830@@ -423,7 +423,7 @@
831 final Management.VolumeInfo[] via = management.getVolumeInfoArray();
832
833 if (_selectedVolumeName == null && via.length > 0) {
834- _selectedVolumeName = via[0].getPath();
835+ _selectedVolumeName = via[0].getName();
836 }
837
838 for (int index = 0; index < via.length; index++) {
839
840=== modified file 'src/main/java/com/persistit/ui/AdminUITreePanel.java'
841--- src/main/java/com/persistit/ui/AdminUITreePanel.java 2012-08-24 13:57:19 +0000
842+++ src/main/java/com/persistit/ui/AdminUITreePanel.java 2013-03-13 17:42:20 +0000
843@@ -263,7 +263,7 @@
844 }
845
846 private void selectVolume(final Management.VolumeInfo volumeInfo) {
847- final String newName = volumeInfo == null ? null : volumeInfo.getPath();
848+ final String newName = volumeInfo == null ? null : volumeInfo.getName();
849 if (!equals(newName, _selectedVolumeName)) {
850 _logicalRecordArrayModel.setInfoArray(null);
851 _selectedTreeName = null;
852
853=== modified file 'src/main/java/com/persistit/ui/VTComboBoxModel.java'
854--- src/main/java/com/persistit/ui/VTComboBoxModel.java 2012-08-24 13:57:19 +0000
855+++ src/main/java/com/persistit/ui/VTComboBoxModel.java 2013-03-13 17:42:20 +0000
856@@ -74,7 +74,7 @@
857 if (_parent == null) {
858 final VolumeInfo[] volumes = _management.getVolumeInfoArray();
859 for (int index = 0; index < volumes.length; index++) {
860- _cachedList.add(volumes[index].getPath());
861+ _cachedList.add(volumes[index].getName());
862 }
863 } else {
864 final String volumeName = (String) _parent.getSelectedItem();
865
866=== modified file 'src/main/resources/com/persistit/ui/AdminUI.properties'
867--- src/main/resources/com/persistit/ui/AdminUI.properties 2012-11-08 15:04:52 +0000
868+++ src/main/resources/com/persistit/ui/AdminUI.properties 2013-03-13 17:42:20 +0000
869@@ -37,8 +37,8 @@
870 lnf = com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel
871
872 VolumeInfo.flags = A:All,S:Size,P:Performance,T:Time
873-VolumeInfo.column.0 = getPath:180:A:Path
874-VolumeInfo.column.1 = getName:100:A:Name
875+VolumeInfo.column.0 = getName:100:A:Name
876+VolumeInfo.column.1 = getPath:180:A:Path
877 VolumeInfo.column.2 = getPageSize:100:A:Page Size
878 VolumeInfo.column.3 = getCurrentSize:100:A:Current Size
879 VolumeInfo.column.4 = getMaximumSize:100:A:Max Size
880
881=== modified file 'src/test/java/com/persistit/Bug1041293Test.java'
882--- src/test/java/com/persistit/Bug1041293Test.java 2012-10-06 02:44:20 +0000
883+++ src/test/java/com/persistit/Bug1041293Test.java 2013-03-13 17:42:20 +0000
884@@ -17,6 +17,7 @@
885
886 import org.junit.Test;
887
888+import com.persistit.exception.BufferSizeUnavailableException;
889 import com.persistit.exception.UnderSpecifiedVolumeException;
890
891 /**
892@@ -39,7 +40,7 @@
893 volume.open(_persistit);
894 }
895
896- @Test(expected = IllegalStateException.class)
897+ @Test(expected = BufferSizeUnavailableException.class)
898 public void mismatchedVolumeSpecificationNPE() throws Exception {
899 final Configuration config = _persistit.getConfiguration();
900 final VolumeSpecification vspec = config.volumeSpecification("${datapath}/test,pageSize:2048,create,"
901@@ -48,7 +49,7 @@
902 volume.open(_persistit);
903 }
904
905- @Test(expected = IllegalStateException.class)
906+ @Test(expected = BufferSizeUnavailableException.class)
907 public void mismatchedTemporaryVolumePageSize() throws Exception {
908 _persistit.createTemporaryVolume(2048);
909 }
910
911=== modified file 'src/test/java/com/persistit/CleanupManagerTest.java'
912--- src/test/java/com/persistit/CleanupManagerTest.java 2012-08-24 13:57:19 +0000
913+++ src/test/java/com/persistit/CleanupManagerTest.java 2013-03-13 17:42:20 +0000
914@@ -19,6 +19,7 @@
915 import static org.junit.Assert.assertTrue;
916
917 import java.lang.ref.WeakReference;
918+import java.util.List;
919
920 import org.junit.Test;
921
922@@ -48,7 +49,8 @@
923 }
924
925 @Override
926- public void performAction(final Persistit persistit) throws PersistitException {
927+ public void performAction(final Persistit persistit, final List<CleanupAction> consequentActions)
928+ throws PersistitException {
929 assertEquals(_last + 1, _sequence);
930 _last = _sequence;
931 _counter++;
932
933=== modified file 'src/test/java/com/persistit/ExchangeLockTest.java'
934--- src/test/java/com/persistit/ExchangeLockTest.java 2013-02-15 15:39:42 +0000
935+++ src/test/java/com/persistit/ExchangeLockTest.java 2013-03-13 17:42:20 +0000
936@@ -19,6 +19,8 @@
937 import static org.junit.Assert.assertTrue;
938 import static org.junit.Assert.fail;
939
940+import java.util.Properties;
941+import java.util.Random;
942 import java.util.concurrent.Semaphore;
943
944 import org.junit.Test;
945@@ -26,11 +28,17 @@
946 import com.persistit.exception.InUseException;
947 import com.persistit.exception.InvalidKeyException;
948 import com.persistit.exception.PersistitException;
949+import com.persistit.unit.UnitTestProperties;
950
951 public class ExchangeLockTest extends PersistitUnitTestCase {
952 private final static long DMILLIS = SharedResource.DEFAULT_MAX_WAIT_TIME;
953 private final Semaphore _coordinator = new Semaphore(0);
954
955+ @Override
956+ public Properties getProperties(final boolean cleanup) {
957+ return UnitTestProperties.getBiggerProperties(cleanup);
958+ }
959+
960 @Test
961 public void singleThreadedLock() throws Exception {
962 final Exchange ex = _persistit.getExchange("persistit", "ExchangeLockTest", true);
963@@ -231,37 +239,34 @@
964 assertEquals(1, succeeded);
965 }
966
967+ /**
968+ * This test is intended to exercise lock management for transactions
969+ * executed sequentially, each of which performs lots of locks (similar to
970+ * DataLoadingTest.)
971+ *
972+ * @throws Exception
973+ */
974 @Test
975 public void lockTablePruning() throws Exception {
976 final Exchange ex = _persistit.getExchange("persistit", "ExchangeLockTest", true);
977+ final Random random = new Random();
978 final Transaction txn = ex.getTransaction();
979- txn.begin();
980- for (int i = 0; i < 10000; i++) {
981- ex.clear().append(i).append(RED_FOX).lock();
982+ for (int j = 0; j < 100; j++) {
983+ txn.begin();
984+ for (int i = 0; i < 10000; i++) {
985+ final int k = random.nextInt(100000);
986+ ex.clear().append(k + (j * 100000)).append(RED_FOX).lock();
987+ }
988+ txn.commit();
989+ txn.end();
990 }
991- txn.commit();
992- txn.end();
993+ assertTrue("Too many lock volume pages uses",
994+ _persistit.getLockVolume().getStorage().getNextAvailablePage() < 100);
995
996 final Exchange lockExchange = new Exchange(_persistit.getLockVolume().getTree("ExchangeLockTest", false));
997- lockExchange.ignoreMVCCFetch(true);
998-
999- final int count1 = keyCount(lockExchange);
1000- assertTrue(count1 > 0);
1001-
1002- _persistit.getTransactionIndex().updateActiveTransactionCache();
1003-
1004- for (int i = 0; i < 10000; i++) {
1005- lockExchange.clear().append(i).append(RED_FOX).prune();
1006- }
1007-
1008- final int count2 = keyCount(lockExchange);
1009- assertTrue(count2 < count1);
1010-
1011- _persistit.getCleanupManager().poll();
1012-
1013- final int count3 = keyCount(lockExchange);
1014- assertEquals(0, count3);
1015-
1016+ final int count = keyCount(lockExchange);
1017+
1018+ assertEquals("Unpruned lock records", 0, count);
1019 }
1020
1021 private int keyCount(final Exchange ex) throws PersistitException {
1022
1023=== modified file 'src/test/java/com/persistit/MVCCPruneBufferTest.java'
1024--- src/test/java/com/persistit/MVCCPruneBufferTest.java 2012-09-26 13:31:13 +0000
1025+++ src/test/java/com/persistit/MVCCPruneBufferTest.java 2013-03-13 17:42:20 +0000
1026@@ -43,7 +43,7 @@
1027 final int available = buffer1.getAvailableSize();
1028 final int keys = buffer1.getKeyCount();
1029 buffer1.claim(true);
1030- buffer1.pruneMvvValues(null, true);
1031+ buffer1.pruneMvvValues(null, true, null);
1032 assertEquals(keys, buffer1.getKeyCount());
1033 assertTrue(buffer1.getMvvCount() > 0);
1034 assertEquals(available, buffer1.getAvailableSize());
1035@@ -53,7 +53,7 @@
1036
1037 _persistit.getTransactionIndex().updateActiveTransactionCache();
1038
1039- buffer1.pruneMvvValues(null, true);
1040+ buffer1.pruneMvvValues(null, true, null);
1041 assertEquals(0, _persistit.getCleanupManager().getAcceptedCount());
1042 assertTrue("Pruning should have removed primordial Anti-values", keys > buffer1.getKeyCount());
1043 // mvvCount is 1 because there is still a leading primordial AntiValue
1044@@ -78,7 +78,7 @@
1045 final int available = buffer1.getAvailableSize();
1046 final int keys = buffer1.getKeyCount();
1047 buffer1.claim(true);
1048- buffer1.pruneMvvValues(null, true);
1049+ buffer1.pruneMvvValues(null, true, null);
1050 buffer1.release();
1051 assertEquals(keys, buffer1.getKeyCount());
1052 assertTrue(buffer1.getMvvCount() > 0);
1053@@ -102,7 +102,7 @@
1054 for (long page = 1; page < pageCount; page++) {
1055 final Buffer buffer = ex1.getBufferPool().get(ex1.getVolume(), page, true, true);
1056 try {
1057- buffer.pruneMvvValues(null, true);
1058+ buffer.pruneMvvValues(null, true, null);
1059 } finally {
1060 buffer.release();
1061 }
1062@@ -123,7 +123,7 @@
1063 for (long page = 1; page < pageCount; page++) {
1064 final Buffer buffer = ex1.getBufferPool().get(ex1.getVolume(), page, true, true);
1065 try {
1066- buffer.pruneMvvValues(ex1.getTree(), true);
1067+ buffer.pruneMvvValues(ex1.getTree(), true, null);
1068 } finally {
1069 buffer.release();
1070 }
1071
1072=== modified file 'src/test/java/com/persistit/TestShim.java'
1073--- src/test/java/com/persistit/TestShim.java 2012-08-24 13:57:19 +0000
1074+++ src/test/java/com/persistit/TestShim.java 2013-03-13 17:42:20 +0000
1075@@ -18,6 +18,7 @@
1076 import java.nio.ByteBuffer;
1077 import java.nio.channels.FileChannel;
1078
1079+import com.persistit.exception.BufferSizeUnavailableException;
1080 import com.persistit.exception.InvalidKeyException;
1081 import com.persistit.exception.PersistitException;
1082 import com.persistit.exception.PersistitInterruptedException;
1083@@ -104,7 +105,7 @@
1084 jman.copyBack();
1085 }
1086
1087- public static Exchange directoryExchange(final Volume volume) {
1088+ public static Exchange directoryExchange(final Volume volume) throws BufferSizeUnavailableException {
1089 return volume.getStructure().directoryExchange();
1090 }
1091

Subscribers

People subscribed via source and target branches