Merge lp:~pbeaman/akiban-persistit/fix-1056489-mvv-step-visibility into lp:akiban-persistit

Proposed by Peter Beaman
Status: Merged
Approved by: Peter Beaman
Approved revision: 370
Merged at revision: 371
Proposed branch: lp:~pbeaman/akiban-persistit/fix-1056489-mvv-step-visibility
Merge into: lp:akiban-persistit
Diff against target: 231 lines (+148/-18)
3 files modified
src/main/java/com/persistit/MVV.java (+17/-5)
src/test/java/com/persistit/Bug1056489Test.java (+125/-0)
src/test/java/com/persistit/MVVTest.java (+6/-13)
To merge this branch: bzr merge lp:~pbeaman/akiban-persistit/fix-1056489-mvv-step-visibility
Reviewer Review Type Date Requested Status
Akiban Build User Needs Fixing
Nathan Williams Approve
Review via email: mp+126522@code.launchpad.net

Description of the change

Fix bug 1056489 MVV and step visibility and pruning errors. This bug arises to incorrect handling of MVV versions when a single transaction performs two or more updates at different step numbers, and when those updates are not ordered by increasing step value. For example, inserting a value with step=2 and then removing the value with step=1 will result in an MVV that sometimes yields the correct result and sometimes appears to have no value.

The assumption in MVV#storeVersion that versions could only arrive in increasing version-handle order was wrong in this case. The primary change is to allow step #01 to be inserted into the MVV at the correct location with respect to step #02 rather than at the end. A new unit test based on Nathan's original investigation code has also been added.

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

Keeping the mvv array in strict order is probably simplest. 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 433: http://172.16.20.104:8080/job/persistit-build/433/

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

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

Jenkins setup of AMI failed, apache mirror down?

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 438: http://172.16.20.104:8080/job/persistit-build/438/

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

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

Real failures in MVVTest that time.

371. By Peter Beaman

Modify MVVTest contants to match reordering now done by MVV.storeVersion

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

MVVTest contains constants that no longer match MVV.storeVersion. Fixed the constants.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/main/java/com/persistit/MVV.java'
--- src/main/java/com/persistit/MVV.java 2012-08-24 13:57:19 +0000
+++ src/main/java/com/persistit/MVV.java 2012-09-27 17:48:28 +0000
@@ -252,6 +252,9 @@
252 final int sourceLength) {252 final int sourceLength) {
253 int existedMask = 0;253 int existedMask = 0;
254 int to = targetOffset;254 int to = targetOffset;
255 int remainder = 0;
256 int end = targetOffset + targetLength;
257
255 if (targetLimit > target.length) {258 if (targetLimit > target.length) {
256 throw new IllegalArgumentException("Target limit exceed target array length: " + targetLimit + " > "259 throw new IllegalArgumentException("Target limit exceed target array length: " + targetLimit + " > "
257 + target.length);260 + target.length);
@@ -314,8 +317,7 @@
314 */317 */
315 to++;318 to++;
316 int next = to;319 int next = to;
317 int end = targetOffset + targetLength;320
318
319 while (next < end) {321 while (next < end) {
320 final long curVersion = getVersion(target, to);322 final long curVersion = getVersion(target, to);
321 final int vlength = getLength(target, to);323 final int vlength = getLength(target, to);
@@ -340,20 +342,30 @@
340 end -= (next - to);342 end -= (next - to);
341 next = to;343 next = to;
342 }344 }
345 } else if (curVersion > versionHandle) {
346 if (vh2ts(versionHandle) != vh2ts(curVersion)) {
347 throw new IllegalStateException("Versions out of order");
348 }
349 remainder = end - to;
350 break;
343 }351 }
344 to = next;352 to = next;
345 }353 }
346 }354 }
347 assertCapacity(targetLimit, to + LENGTH_PER_VERSION + sourceLength);355 assertCapacity(targetLimit, end + LENGTH_PER_VERSION + sourceLength);
356 // Move same-transaction steps that are higher
357 if (remainder > 0) {
358 System.arraycopy(target, to, target, to + sourceLength + LENGTH_PER_VERSION, remainder);
359 }
348 // Append new value360 // Append new value
349 putVersion(target, to, versionHandle);361 putVersion(target, to, versionHandle);
350 putLength(target, to, sourceLength);362 putLength(target, to, sourceLength);
351 to += LENGTH_PER_VERSION;363 to += LENGTH_PER_VERSION;
352 System.arraycopy(source, sourceOffset, target, to, sourceLength);364 System.arraycopy(source, sourceOffset, target, to, sourceLength);
353 to += sourceLength;365 to += sourceLength;
354 Debug.$assert0.t(verify(target, targetOffset, to - targetOffset));366 Debug.$assert0.t(verify(target, targetOffset, to - targetOffset + remainder));
355367
356 return (to - targetOffset) | existedMask;368 return (to - targetOffset + remainder) | existedMask;
357 }369 }
358370
359 /**371 /**
360372
=== added file 'src/test/java/com/persistit/Bug1056489Test.java'
--- src/test/java/com/persistit/Bug1056489Test.java 1970-01-01 00:00:00 +0000
+++ src/test/java/com/persistit/Bug1056489Test.java 2012-09-27 17:48:28 +0000
@@ -0,0 +1,125 @@
1/**
2 * Copyright © 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;
20
21import org.junit.Test;
22
23import com.persistit.exception.PersistitException;
24import com.persistit.unit.UnitTestProperties;
25
26/**
27 * https://bugs.launchpad.net/akiban-persistit/+bug/1056489
28 *
29 * When utilizing the step capability of transactions there appear to be
30 * inconsistencies between reading, writing, removing, and pruning. Particularly
31 * when steps of a single transaction appear out of order in a single MVV.
32 *
33 * An invariant in MVV#storeVersion is that each version added to an MVV must
34 * have a larger ts than any version already present in the MVV. This follows
35 * from ww-dependency validation; if there's a version tsv on the MVV and my ts
36 * is before that tsv, by definition I'm concurrent with it and can't write.
37 *
38 * But, the step handling code breaks that. A transaction can't conflict with
39 * itself, so no code prevents insertion of versions with step numbers out of
40 * sequence. MVV#storeVersion does not rearrange the MVV in step order, and the
41 * pruning code simply keeps the last value found for each concurrent
42 * transaction. Therefore in the test case for key={2}, the AntiValue for the
43 * remove is stored after the value 200 in the MVV. The MVV looks like this:
44 *
45 * [277<277>:20,282#02<UNCOMMITTED>:200,282#01<UNCOMMITTED>:AntiValue{}]
46 *
47 * Pruning will then remove the value at 282#2 and keep 282#1, the AntiValue
48 * from the remove.
49 *
50 */
51
52public class Bug1056489Test extends PersistitUnitTestCase {
53
54 public void update(final Exchange ex, final int k, final int v) throws Exception {
55 _persistit.getTransaction().setStep(2);
56 ex.getKey().clear().append(k);
57 ex.getValue().clear().put(v);
58 ex.store();
59 }
60
61 public void remove(final Exchange ex, final int k) throws Exception {
62 _persistit.getTransaction().setStep(1);
63 ex.getKey().clear().append(k);
64 ex.remove();
65 }
66
67 @Test
68 public void mvvStepCheck() throws Exception {
69 final Transaction txn = _persistit.getTransaction();
70 final Exchange ex = _persistit.getExchange(UnitTestProperties.VOLUME_NAME, "new_tree1", true);
71
72 txn.begin();
73 for (int i = 1; i <= 3; ++i) {
74 ex.getKey().clear().append(i);
75 ex.getValue().clear().put(i * 10);
76 ex.store();
77 }
78 txn.commit();
79 txn.end();
80 treeCheck(ex, "Initial", 10, 20, 30);
81
82 txn.begin();
83 for (int i = 1; i <= 3; ++i) {
84 ex.clear().append(i);
85 if (i == 2) {
86 update(ex, i, i * 100);
87 remove(ex, i);
88 } else {
89 remove(ex, i);
90 update(ex, i, i * 100);
91 }
92 }
93 treeCheck(ex, "Post update, pre commit", 100, 200, 300);
94 txn.commit();
95 txn.end();
96
97 treeCheck(ex, "Updated, committed", 100, 200, 300);
98
99 while (_persistit.getCleanupManager().getPerformedCount() < _persistit.getCleanupManager().getAcceptedCount()) {
100 Thread.sleep(100);
101 }
102
103 treeCheck(ex, "Updated, committed, pruned", 100, 200, 300);
104
105 _persistit.getTransactionIndex().cleanup();
106 txn.begin();
107
108 treeCheck(ex, "Updated, committed, TI cleaned", 100, 200, 300);
109 ex.clear().append(2);
110 assertTrue("Removed should find key {2}", ex.remove());
111 txn.commit();
112 txn.end();
113 treeCheck(ex, "Updated, committed, TI cleaned, removed", 100, 300);
114 }
115
116 private void treeCheck(final Exchange ex, final String message, final int... expected) throws PersistitException {
117 ex.clear();
118 int index = 0;
119 while (ex.next(true)) {
120 assertTrue("Too many keys", index < expected.length);
121 assertEquals("Wrong value", expected[index++], ex.getValue().getInt());
122
123 }
124 }
125}
0126
=== modified file 'src/test/java/com/persistit/MVVTest.java'
--- src/test/java/com/persistit/MVVTest.java 2012-08-24 13:57:19 +0000
+++ src/test/java/com/persistit/MVVTest.java 2012-09-27 17:48:28 +0000
@@ -179,8 +179,8 @@
179 storedLength &= STORE_LENGTH_MASK;179 storedLength &= STORE_LENGTH_MASK;
180 assertEquals(targetLength - 1, storedLength);180 assertEquals(targetLength - 1, storedLength);
181 assertArrayEqualsLen(181 assertArrayEqualsLen(
182 newArray(TYPE_MVV, 0, 0, 0, 0, 0, 0, 0, vh1, 0, 2, 0x4, 0x5, 0, 0, 0, 0, 0, 0, 0, vh3, 0, 4, 0x6, 0x7,182 newArray(TYPE_MVV, 0, 0, 0, 0, 0, 0, 0, vh1, 0, 2, 0x4, 0x5, 0, 0, 0, 0, 0, 0, 0, vh2, 0, 2, 0xD, 0xE,
183 0x8, 0x9, 0, 0, 0, 0, 0, 0, 0, vh2, 0, 2, 0xD, 0xE), target, storedLength);183 0, 0, 0, 0, 0, 0, 0, vh3, 0, 4, 0x6, 0x7, 0x8, 0x9), target, storedLength);
184 }184 }
185185
186 @Test186 @Test
@@ -197,8 +197,8 @@
197197
198 assertEquals(targetLength + 1, storedLength);198 assertEquals(targetLength + 1, storedLength);
199 assertArrayEqualsLen(199 assertArrayEqualsLen(
200 newArray(TYPE_MVV, 0, 0, 0, 0, 0, 0, 0, vh1, 0, 2, 0x4, 0x5, 0, 0, 0, 0, 0, 0, 0, vh3, 0, 4, 0x6, 0x7,200 newArray(TYPE_MVV, 0, 0, 0, 0, 0, 0, 0, vh1, 0, 2, 0x4, 0x5, 0, 0, 0, 0, 0, 0, 0, vh2, 0, 4, 0xC, 0xD,
201 0x8, 0x9, 0, 0, 0, 0, 0, 0, 0, vh2, 0, 4, 0xC, 0xD, 0xE, 0xF), target, storedLength);201 0xE, 0xF, 0, 0, 0, 0, 0, 0, 0, vh3, 0, 4, 0x6, 0x7, 0x8, 0x9), target, storedLength);
202 }202 }
203203
204 @Test204 @Test
@@ -220,15 +220,8 @@
220220
221 @Test221 @Test
222 public void storeBigVersions() {222 public void storeBigVersions() {
223 final long versions[] = { Integer.MAX_VALUE, 10, 1844674407370955161L /*223 final long versions[] = { 10, Short.MAX_VALUE, Integer.MAX_VALUE, 1844674407370955161L, 8301034833169298227L,
224 * MAX224 Long.MAX_VALUE };
225 * /
226 * 5
227 * -
228 * ish
229 */, Short.MAX_VALUE, Long.MAX_VALUE,
230 8301034833169298227L /* MAX*0.9-ish */
231 };
232 final byte contents[][] = { newArray(0xA0), newArray(0xB0, 0xB1), newArray(0xC0, 0xC1, 0xC2),225 final byte contents[][] = { newArray(0xA0), newArray(0xB0, 0xB1), newArray(0xC0, 0xC1, 0xC2),
233 newArray(0xD0, 0xD1, 0xD2, 0xD3), newArray(0xE0, 0xE1, 0xE2, 0xE3, 0xE4),226 newArray(0xD0, 0xD1, 0xD2, 0xD3), newArray(0xE0, 0xE1, 0xE2, 0xE3, 0xE4),
234 newArray(0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5) };227 newArray(0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5) };

Subscribers

People subscribed via source and target branches