Merge lp:~pbeaman/akiban-persistit/fix-1073357-Value-getType into lp:akiban-persistit

Proposed by Peter Beaman
Status: Merged
Approved by: Peter Beaman
Approved revision: 392
Merged at revision: 387
Proposed branch: lp:~pbeaman/akiban-persistit/fix-1073357-Value-getType
Merge into: lp:akiban-persistit
Diff against target: 838 lines (+226/-528)
4 files modified
src/main/java/com/persistit/Key.java (+22/-0)
src/main/java/com/persistit/Value.java (+74/-3)
src/test/java/com/persistit/unit/KeyTest1.java (+25/-0)
src/test/java/com/persistit/unit/ValueTest4.java (+105/-525)
To merge this branch: bzr merge lp:~pbeaman/akiban-persistit/fix-1073357-Value-getType
Reviewer Review Type Date Requested Status
Akiban Build User Needs Fixing
Nathan Williams Approve
Review via email: mp+132758@code.launchpad.net

Description of the change

Fixes bug https://bugs.launchpad.net/akiban-persistit/+bug/1073357 in which the Value#getType() returns Object.class rather than the true type of the value field when that field contains a duplicate of an earlier value.

The Value object encodes object graphs in which possibly may include cycles. To do so it encodes the any reference to an object that has already been serialized into the value as a special "REREF" item with a reference handle. However the Value#getType() method did not follow the handle to the referenced object to determine its class. This proposal corrects that behavior and adds tests for it.

This branch also adds two convenience methods:

Value#skipNull
Key#skipNull

Each of these is equivalent to the corresponding class' isNull method, but if the field is detected to be null the field cursor is advanced to the next field. For example, Key#skipNull is equivalent to

  if (key.isNull()) {
    key.decodeNull();
    return true;
  } else {
    return false;
  }

These are intended to satisfy a need first identified by the server team and are intended to simplify coding in some use cases.

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

Note: the majority of ValueTest4 was deleted because it was identical to ValueTest3.

Revision history for this message
Yuval Shavit (yshavit) wrote :

I mentioned this in person to Peter, but it'd be nice to rename skipNull to isNullSkip or such. That way, the two methods would appear next to each other in IDEs with autocomplete. Not only would that be convenient, but it would also serve as a warning to anyone who (as many people do) navigates an API via autocomplete. Such a programmer would see these two similarly-named methods, and hopefully think, "hm, I should read what the distinction is."

As a slight variant, what about two overloads of isNull? One is isNull(boolean skipIfNull), the other is isNull() { return isNull(false); }. I merely mention that as a way of getting the same benefits (easy to find, autocomplete-friendly, yet consistent behavior for isNull() as compared to the other isXxx methods) with a bit less of linguistic hoop-jumping.

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

Good idea, done. The method is now

isNull(boolean skipNull)

Revision history for this message
Yuval Shavit (yshavit) wrote :

Cool. I don't feel I'm qualified to comment on the rest of the merge prop, though if you'd like me to I can take a stab at it.

One comment on the test, lines 676-7, I believe the original bug was when the two objects were == (not just equal). So maybe create a new Long and then insert it twice, rather than inserting two unique Longs?

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

Looks mostly fine.

What if valueCache() does not contain the object? I'm not terribly familiar with it, but it looks like that is filled lazily. For example, what about Value append(a), append(b), append(a), store, clear, fetch, skip, skip, getType?

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

getValueCache() always returns a ValueCache instance, but that instance may be hollow. If it is hollow, the code throws an ISE. It's an illegal state because the only way to traverse a CLASS_REREF field is from the left, and therefore the referent should have been loaded first.

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

Unless you skip the field, like you said... As usual I responded without reading your comment carefully enough.

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

Modified further so that both get() and getType() correct return the value or type of the skipped field. See com.persistit.unit.ValueTest4#streamModeGetAfterSkip().

Thanks for identifying this issue.

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

Looks plausible. And who am I to argue with passing tests.

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

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

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

An InUseException which may be either (a) weird I/O on the test machine, or (b) a bug I'm currently trying to track down in the stress tests. At any rate, the failure is unrelated to the code changes so I am re-Approving.

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/Key.java'
2--- src/main/java/com/persistit/Key.java 2012-10-22 14:25:58 +0000
3+++ src/main/java/com/persistit/Key.java 2012-11-06 17:54:23 +0000
4@@ -3108,6 +3108,28 @@
5 }
6
7 /**
8+ * Determine if the current segment would return <code>null</code> if
9+ * {@link #decode()} were called. As a side effect, if <code>skipNull</code>
10+ * is true and the segment does encode a <code>null</code> value, then the
11+ * index is advanced to the beginning of the next segment.
12+ *
13+ * @param skipNull
14+ * whether to advance the index past a null segment value
15+ * @return <code>true</code> if the current segment is null,
16+ * <code>false</code> otherwise.
17+ */
18+ public boolean isNull(final boolean skipNull) {
19+ if (getTypeCode() == TYPE_NULL) {
20+ if (skipNull) {
21+ _index = decodeEnd(_index + 1);
22+ }
23+ return true;
24+ } else {
25+ return false;
26+ }
27+ }
28+
29+ /**
30 * Advance the index to the beginning of the next key segment. If the index
31 * is already at the end of the key, then wrap it to the beginning and
32 * return -1.
33
34=== modified file 'src/main/java/com/persistit/Value.java'
35--- src/main/java/com/persistit/Value.java 2012-09-25 21:00:18 +0000
36+++ src/main/java/com/persistit/Value.java 2012-11-06 17:54:23 +0000
37@@ -963,6 +963,30 @@
38 return getTypeHandle() == TYPE_NULL;
39 }
40
41+ /**
42+ * Determine whether the data held by this <code>Value</code> is null. As a
43+ * side effect, if <code>skipNull</code> is true and <a
44+ * href="#_streamMode">Stream Mode</a> is enabled this method also advances
45+ * the cursor to the next field if the current field is null.
46+ *
47+ * @param skipNull
48+ * if <code>true</code>, the <code>Value</code> is in stream mode
49+ * and the current field is null, then advance the cursor to next
50+ * field
51+ * @return <code>true</code> if the current state of this <code>Value</code>
52+ * represents <i>null</i>.
53+ */
54+ public boolean isNull(final boolean skipNull) {
55+ if (isNull()) {
56+ if (skipNull && _depth > 0) {
57+ _next++;
58+ }
59+ return true;
60+ } else {
61+ return false;
62+ }
63+ }
64+
65 boolean isAntiValue() {
66 return getTypeHandle() == CLASS_ANTIVALUE;
67 }
68@@ -1574,7 +1598,15 @@
69 final int saveEnd = _end;
70 try {
71 final int classHandle = nextType();
72- if (classHandle > 0 && classHandle < CLASSES.length && CLASSES[classHandle] != null) {
73+ if (classHandle == CLASS_REREF) {
74+ final int base = _bytes[_next++] & 0xFF;
75+ final int handle = decodeVariableLengthInt(base);
76+ final Object object = getValueCache().get(handle);
77+ if (object == null) {
78+ throw new IllegalStateException("Reference to handle " + handle + " has no value");
79+ }
80+ return object.getClass();
81+ } else if (classHandle > 0 && classHandle < CLASSES.length && CLASSES[classHandle] != null) {
82 return CLASSES[classHandle];
83 } else if (classHandle == CLASS_ARRAY) {
84 _depth++;
85@@ -3956,8 +3988,12 @@
86 * to be decoded and constructed.
87 */
88 public void skip() {
89- if (_depth == 0)
90+ if (_depth == 0) {
91 return;
92+ }
93+ final int currentHandle = _serializedItemCount++;
94+ final int saveNext = _next;
95+ final int saveEnd = _end;
96 final int classHandle = nextType();
97 if (classHandle == 0)
98 return;
99@@ -3973,6 +4009,7 @@
100 if (size >= 0) {
101 _next += size;
102 } else {
103+ getValueCache().put(currentHandle, new SkippedFieldMarker(this, saveNext, saveEnd));
104 closeVariableLengthItem();
105 }
106 }
107@@ -5015,7 +5052,12 @@
108 * @return The object
109 */
110 Object get(final int handle) {
111- return _array[handle];
112+ Object object = _array[handle];
113+ if (object instanceof SkippedFieldMarker) {
114+ object = ((SkippedFieldMarker) object).get();
115+ _array[handle] = object;
116+ }
117+ return object;
118 }
119
120 /**
121@@ -5078,6 +5120,35 @@
122 }
123 }
124
125+ private static class SkippedFieldMarker {
126+ final Value _value;
127+ final int _next;
128+ final int _end;
129+
130+ private SkippedFieldMarker(final Value value, final int next, final int end) {
131+ _value = value;
132+ _next = next;
133+ _end = end;
134+ }
135+
136+ private Object get() {
137+ final int saveDepth = _value._depth;
138+ final int saveLevel = _value._level;
139+ final int saveNext = _value._next;
140+ final int saveEnd = _value._end;
141+ try {
142+ _value._next = _next;
143+ _value._end = _end;
144+ return _value.get();
145+ } finally {
146+ _value._end = saveEnd;
147+ _value._next = saveNext;
148+ _value._level = saveLevel;
149+ _value._depth = saveDepth;
150+ }
151+ }
152+ }
153+
154 static class Version {
155 private final long _versionHandle;
156 private final long _commitTimestamp;
157
158=== modified file 'src/test/java/com/persistit/unit/KeyTest1.java'
159--- src/test/java/com/persistit/unit/KeyTest1.java 2012-10-22 14:25:58 +0000
160+++ src/test/java/com/persistit/unit/KeyTest1.java 2012-11-06 17:54:23 +0000
161@@ -703,6 +703,31 @@
162 }
163
164 @Test
165+ public void testSkipNull() {
166+ final Key key1 = new Key(_persistit);
167+ key1.clear().append(null).append(1).append(2).append(null).append(null).append(5);
168+ key1.reset();
169+ assertTrue("seg0 is null: " + key1, key1.isNull(true));
170+ assertFalse("seg1 is not null: " + key1, key1.isNull(true));
171+ assertEquals("expect seg1 value", 1, key1.decode());
172+ assertFalse("seg2 is not null: " + key1, key1.isNull(true));
173+ assertEquals("expect seg2 value", 2, key1.decode());
174+ assertTrue("seg3 is null: " + key1, key1.isNull(true));
175+ assertTrue("seg4 is null: " + key1, key1.isNull(true));
176+ assertFalse("seg5 is not null:" + key1, key1.isNull(true));
177+ assertFalse("seg5 is not null:" + key1, key1.isNull(true));
178+ assertFalse("seg5 is not null:" + key1, key1.isNull(true));
179+ assertEquals("expect seg5 value", 5, key1.decodeInt());
180+
181+ try {
182+ key1.isNull(true);
183+ Assert.fail("Expected MissingKeySegmentException!");
184+ } catch (final MissingKeySegmentException e) {
185+ // expected
186+ }
187+ }
188+
189+ @Test
190 public void testFirstUniqueSegmentDepth() {
191 final Key key1 = new Key(_persistit);
192 final Key key2 = new Key(_persistit);
193
194=== modified file 'src/test/java/com/persistit/unit/ValueTest4.java'
195--- src/test/java/com/persistit/unit/ValueTest4.java 2012-08-24 13:57:19 +0000
196+++ src/test/java/com/persistit/unit/ValueTest4.java 2012-11-06 17:54:23 +0000
197@@ -18,536 +18,116 @@
198 import static org.junit.Assert.assertEquals;
199 import static org.junit.Assert.assertTrue;
200
201-import java.io.Externalizable;
202-import java.io.IOException;
203-import java.io.ObjectInput;
204-import java.io.ObjectInputStream;
205-import java.io.ObjectOutput;
206-import java.io.ObjectOutputStream;
207-import java.io.ObjectStreamException;
208-import java.io.ObjectStreamField;
209-import java.io.Serializable;
210-import java.util.ArrayList;
211-
212 import org.junit.Test;
213
214-import com.persistit.DefaultCoderManager;
215-import com.persistit.DefaultValueCoder;
216-import com.persistit.Exchange;
217-import com.persistit.Persistit;
218 import com.persistit.PersistitUnitTestCase;
219 import com.persistit.Value;
220-import com.persistit.encoding.CoderContext;
221-import com.persistit.encoding.CoderManager;
222-import com.persistit.encoding.SerialValueCoder;
223-import com.persistit.encoding.ValueCoder;
224-import com.persistit.exception.PersistitException;
225
226 public class ValueTest4 extends PersistitUnitTestCase {
227
228- /**
229- * Tests JSA 1.1 default serialization. Requires the
230- * enableCompatibleConstructors to be true.
231- */
232- Exchange _exchange;
233-
234- public static class CustomSet extends ArrayList {
235- private final static long serialVersionUID = 1L;
236- }
237-
238- private static class T implements Serializable {
239- private final static long serialVersionUID = 1L;
240-
241- private String _a;
242- private String _b;
243-
244- private T(final String a, final String b) {
245- _a = a;
246- _b = b;
247- }
248-
249- private T(final String a, final String b, final boolean f) {
250- _a = a;
251- _b = b;
252- assertTrue("T 3-arg constructor should not be called", false);
253- }
254-
255- private T(final int x, final boolean y, final String z) {
256- assertTrue("T 3-arg constructor should not be called", false);
257- }
258-
259- @Override
260- public String toString() {
261- return "T:" + _a + _b;
262- }
263- }
264-
265- private static class TT extends T {
266- private final static long serialVersionUID = 1L;
267-
268- private TT(final String a, final String b) {
269- super(a, b);
270- }
271-
272- private TT(final String a, final String b, final boolean f) {
273- super(a, b, f);
274- }
275-
276- private TT(final int x, final boolean y, final String z) {
277- super(x, y, z);
278- }
279-
280- @Override
281- public String toString() {
282- return "T" + super.toString();
283- }
284- }
285-
286- private static class TTT extends TT {
287- private final static long serialVersionUID = 1L;
288-
289- private TTT(final String a, final String b) {
290- super(a, b);
291- assertTrue(a != null);
292- }
293-
294- private TTT(final String a, final String b, final boolean f) {
295- super(a, b, f);
296- assertTrue(a != null);
297- }
298-
299- private TTT(final int x, final boolean y, final String z) {
300- super(x, y, z);
301- }
302-
303- @Override
304- public String toString() {
305- return "T" + super.toString();
306- }
307-
308- }
309-
310- private static class TTTValueCoder extends DefaultValueCoder {
311- static int _getCounter;
312-
313- TTTValueCoder(final Persistit persistit) {
314- super(persistit, TTT.class);
315- }
316-
317- @Override
318- public Object get(final Value value, final Class clazz, final CoderContext context) {
319- _getCounter++;
320- final TTT ttt = new TTT("x", "y");
321- value.registerEncodedObject(ttt);
322- render(value, ttt, clazz, context);
323- return ttt;
324- }
325- }
326-
327- private static class S implements Serializable {
328- String _a;
329- String _b;
330-
331- private final static long serialVersionUID = 1L;
332-
333- public void readObject(final ObjectInputStream ois) throws IOException, ClassNotFoundException {
334- ois.defaultReadObject();
335- }
336-
337- public void writeObject(final ObjectOutputStream oos) throws IOException {
338- oos.defaultWriteObject();
339- }
340-
341- @Override
342- public String toString() {
343- return "S:" + _a + _b;
344- }
345- }
346-
347- private static class SS extends S {
348- private final static long serialVersionUID = 1L;
349-
350- private final String _c;
351- private final String _d;
352- protected String _ff;
353-
354- private SS(final String c, final String d) {
355- _c = c;
356- _d = d;
357- _ff = "Final field";
358- }
359-
360- @Override
361- public String toString() {
362- return "S" + super.toString() + _c + _d;
363- }
364- }
365-
366- private static class SSS extends SS {
367- private final static long serialVersionUID = 1L;
368-
369- R _e;
370- private final W _f;
371-
372- private SSS(final String c, final String d, final boolean e, final int f) {
373- super(c, d);
374- _e = new R(e);
375- _f = new W(f);
376- }
377-
378- @Override
379- public String toString() {
380- return "S" + super.toString() + _e + _f;
381-
382- }
383- }
384-
385- private static class SSSS extends SSS {
386- private final static long serialVersionUID = 1L;
387-
388- private String _g;
389- private String _h;
390-
391- private SSSS() {
392- super("SSSS-c", "SSSS-d", true, 42);
393- _g = "Field g";
394- _h = "Field h";
395- }
396-
397- private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("_g", String.class), };
398-
399- @Override
400- public String toString() {
401- return "S" + super.toString() + _g + _h + _ff;
402- }
403- }
404-
405- private static class R implements Serializable {
406- private final static long serialVersionUID = 1L;
407-
408- final static R R_TRUE = new R(true);
409- final static R R_FALSE = new R(false);
410-
411- boolean _value;
412-
413- R(final boolean b) {
414- _value = b;
415- }
416-
417- public Object readResolve() throws ObjectStreamException {
418- return _value ? R_TRUE : R_FALSE;
419- }
420-
421- @Override
422- public String toString() {
423- if (this == R_TRUE) {
424- return "true";
425- } else if (this == R_FALSE) {
426- return "false";
427- } else {
428- return "notReplaced";
429- }
430- }
431- }
432-
433- private static class W implements Serializable {
434- private final static long serialVersionUID = 1L;
435-
436- int _value;
437-
438- W(final int v) {
439- _value = v;
440- }
441-
442- private Object writeReplace() throws ObjectStreamException {
443- return new WReplacement(_value);
444- }
445-
446- @Override
447- public String toString() {
448- return "W:" + _value;
449- }
450- }
451-
452- private static class WReplacement implements Serializable {
453- private final static long serialVersionUID = 1L;
454-
455- int _value;
456-
457- WReplacement(final int v) {
458- _value = v;
459- }
460-
461- private Object readResolve() throws ObjectStreamException {
462- return new W(_value);
463- }
464-
465- @Override
466- public String toString() {
467- return "WReplacement:" + _value;
468- }
469-
470- }
471-
472- private static class E implements Externalizable {
473- private final static long serialVersionUID = 1L;
474- String _a;
475- String _b;
476-
477- public E() {
478- }
479-
480- @Override
481- public void readExternal(final ObjectInput oi) throws IOException {
482- oi.readUTF(); // "foo"
483- _a = oi.readUTF();
484- _b = oi.readUTF();
485- }
486-
487- @Override
488- public void writeExternal(final ObjectOutput oo) throws IOException {
489- oo.writeUTF("hello");
490- oo.writeUTF(_a);
491- oo.writeUTF(_b);
492- }
493-
494- @Override
495- public String toString() {
496- return "E:" + _a + _b;
497- }
498- }
499-
500- private static class EE extends E {
501- private final static long serialVersionUID = 1L;
502- private final Thread _thread = Thread.currentThread(); // intentionally
503-
504- // not
505- // Serializable
506-
507- public EE() {
508- super();
509- }
510-
511- EE(final String a, final String b) {
512- _a = a;
513- _b = b;
514- }
515-
516- @Override
517- public String toString() {
518- return "E" + super.toString() + (_thread != null ? "" : "");
519- }
520- }
521-
522- @Override
523- public void setUp() throws Exception {
524- super.setUp();
525- _exchange = _persistit.getExchange("persistit", getClass().getSimpleName(), true);
526- }
527-
528- @Override
529- public void tearDown() throws Exception {
530- _persistit.releaseExchange(_exchange);
531- _exchange = null;
532- super.tearDown();
533- }
534-
535- @Test
536- public void test1() throws PersistitException {
537- System.out.print("test1 ");
538- final S s = new S();
539- s._a = "1";
540- s._b = "2";
541- _exchange.getValue().put(s);
542- _exchange.clear().append("test1").store();
543- final Object x = _exchange.getValue().get();
544- assertEquals("S:12", x.toString());
545- System.out.println("- done");
546- }
547-
548- @Test
549- public void test2() throws PersistitException {
550- System.out.print("test2 ");
551- final SS ss = new SS("3", "4");
552- ss._a = "1";
553- ss._b = "2";
554- _exchange.getValue().put(ss);
555- _exchange.clear().append("test2").store();
556- final Object x = _exchange.getValue().get();
557- assertEquals("SS:1234", x.toString());
558- System.out.println("- done");
559- }
560-
561- @Test
562- public void test3() throws PersistitException {
563- System.out.print("test3 ");
564- final E e = new E();
565- e._a = "1";
566- e._b = "2";
567- _exchange.getValue().put(e);
568- _exchange.clear().append("test3").store();
569- final Object x = _exchange.getValue().get();
570- assertEquals("E:12", x.toString());
571- System.out.println("- done");
572- }
573-
574- @Test
575- public void test4() throws PersistitException {
576- System.out.print("test4 ");
577- final EE ee = new EE("6", "7");
578- ee._a = "1";
579- ee._b = "2";
580- _exchange.getValue().put(ee);
581- _exchange.clear().append("test4").store();
582- final Object x = _exchange.getValue().get();
583- assertEquals("EE:12", x.toString());
584- System.out.println("- done");
585- }
586-
587- @Test
588- public void test5() throws PersistitException {
589- System.out.print("test5 ");
590- final T t = new T("1", "2");
591- _exchange.getValue().put(t);
592- _exchange.clear().append("test5").store();
593- final Object x = _exchange.getValue().get();
594- assertEquals("T:12", x.toString());
595- System.out.println("- done");
596- }
597-
598- @Test
599- public void test6() throws PersistitException {
600- System.out.print("test6 ");
601- final TT tt = new TT("1", "2");
602- _exchange.getValue().put(tt);
603- _exchange.clear().append("test6").store();
604- final Object x = _exchange.getValue().get();
605- assertEquals("TT:12", x.toString());
606- System.out.println("- done");
607- }
608-
609- @Test
610- public void test7() throws PersistitException {
611- System.out.print("test7 ");
612- final CoderManager cm = _persistit.getCoderManager();
613- cm.registerValueCoder(TTT.class, new TTTValueCoder(_persistit));
614- TTTValueCoder._getCounter = 0;
615- final TTT ttt = new TTT("1", "2");
616- _exchange.getValue().put(ttt);
617- _exchange.clear().append("test7").store();
618- final Object x = _exchange.getValue().get();
619- assertEquals("TTT:12", x.toString());
620- assertEquals(1, TTTValueCoder._getCounter);
621- cm.unregisterValueCoder(TTT.class);
622- System.out.println("- done");
623- }
624-
625- @Test
626- public void test8() throws PersistitException {
627- System.out.print("test8 ");
628- final CoderManager cm = _persistit.getCoderManager();
629- cm.registerValueCoder(TTT.class, new TTTValueCoder(_persistit));
630- TTTValueCoder._getCounter = 0;
631- final TTT ttt = new TTT("1", "2");
632- _exchange.getValue().put(ttt);
633- _exchange.clear().append("test8").store();
634- final Object x = _exchange.getValue().get();
635- assertEquals("TTT:12", x.toString());
636- assertEquals(1, TTTValueCoder._getCounter);
637- cm.unregisterValueCoder(TTT.class);
638- System.out.println("- done");
639- }
640-
641- @Test
642- public void test9() throws PersistitException {
643- System.out.print("test9 ");
644- final SSS sss = new SSS("3", "4", true, 5);
645- sss._a = "1";
646- sss._b = "2";
647- _exchange.getValue().put(sss);
648- _exchange.clear().append("test9").store();
649- final Object x = _exchange.getValue().get();
650- assertEquals("SSS:1234trueW:5", x.toString());
651- System.out.println("- done");
652- }
653-
654- @Test
655- public void test10() throws PersistitException {
656- System.out.print("test10 ");
657- final SSS sss = new SSS("3", "4", true, 5);
658- sss._a = "1";
659- sss._b = "2";
660- _exchange.getValue().put(sss);
661- _exchange.clear().append("test10").store();
662- final Object x = _exchange.getValue().get();
663- assertEquals("SSS:1234trueW:5", x.toString());
664- System.out.println("- done");
665- }
666-
667- @Test
668- public void test11() throws PersistitException {
669- System.out.print("test11 ");
670- final SSSS ssss = new SSSS();
671- ssss._a = "Field a";
672- ssss._b = "Field b";
673- ssss._g = "Field g";
674- ssss._h = "Field h";
675- _exchange.getValue().put(ssss);
676- _exchange.clear().append("test11").store();
677- final Object x = _exchange.getValue().get();
678- // assertEquals("SSSS:0000falsenull", x.toString());
679- System.out.print(" x=" + x + " ");
680- System.out.println();
681- System.out.println("Value: " + _exchange.getValue());
682- System.out.println("- done");
683- }
684-
685- @Test
686- public void test12() throws PersistitException {
687- System.out.print("test12 ");
688- final CoderManager cm = _persistit.getCoderManager();
689- final ValueCoder defaultCoder = cm.getValueCoder(SSSS.class);
690- _persistit.getCoderManager().registerValueCoder(SSSS.class, new SerialValueCoder(SSSS.class));
691- final SSSS ssss = new SSSS();
692- ssss._a = "Field a";
693- ssss._b = "Field b";
694- ssss._g = "Field g";
695- ssss._h = "Field h";
696- _exchange.getValue().put(ssss);
697- _exchange.clear().append("test12").store();
698- final Object x = _exchange.getValue().get();
699- // assertEquals("SSSS:0000falsenull", x.toString());
700- System.out.print(" x=" + x + " ");
701- System.out.println();
702- System.out.println("Value: " + _exchange.getValue());
703- cm.registerValueCoder(SSSS.class, defaultCoder);
704- System.out.println("- done");
705- }
706-
707- public static void main(final String[] args) throws Exception {
708- new ValueTest4().initAndRunTest();
709- }
710-
711- @Override
712- public void runAllTests() throws Exception {
713- final CoderManager cm = _persistit.getCoderManager();
714- _persistit.setCoderManager(new DefaultCoderManager(_persistit, "com.persistit.unit.ValueTest4$*"));
715- _exchange = _persistit.getExchange("persistit", "ValueTest4", true);
716-
717- test1();
718- test2();
719- test3();
720- test4();
721- test5();
722- test6();
723- test7();
724- test8();
725- test9();
726- test10();
727- test11();
728- test12();
729-
730- _persistit.setCoderManager(cm);
731- }
732-
733+ private final static String ABC = "abc";
734+
735+ @Test
736+ public void streamMode() throws Exception {
737+ final Value value = new Value(_persistit);
738+ value.setStreamMode(true);
739+ value.put(1);
740+ value.put(2f);
741+ value.put(ABC);
742+ value.put(ABC);
743+ value.put("xxabc".substring(2));
744+ value.put(new Long(5));
745+ value.put(new Long(5));
746+ value.setStreamMode(false);
747+ value.setStreamMode(true);
748+ assertEquals("expect primitive int class", int.class, value.getType());
749+ assertEquals("expect value", 1, value.get());
750+ assertEquals("expect primitive float class", float.class, value.getType());
751+ assertEquals("expect value", 2f, value.get());
752+ assertEquals("expect String class", String.class, value.getType());
753+ final String s1 = (String) value.get();
754+ assertEquals("expect String class", String.class, value.getType());
755+ final String s2 = (String) value.get();
756+ assertEquals("expect String class", String.class, value.getType());
757+ final String s3 = (String) value.get();
758+ assertEquals("expect value", ABC, s1);
759+ assertEquals("expect value", ABC, s2);
760+ assertEquals("expect value", ABC, s3);
761+ assertEquals("expect Long class", Long.class, value.getType());
762+ final Long l1 = (Long) value.get();
763+ assertEquals("expect Long class", Long.class, value.getType());
764+ final Long l2 = (Long) value.get();
765+ assertEquals("expect equal values", l1, l2);
766+ assertTrue("encoding of primitive wrapper classes loses identity", l1 == l2);
767+ assertTrue("interned constant \"abc\" has same identity", s1 == s2);
768+ assertTrue("computed object \"xxabc\".substring(2) has different identity", s1 != s3);
769+ }
770+
771+ @Test
772+ public void streamModeSkipNull() throws Exception {
773+ final Value value = new Value(_persistit);
774+ value.setStreamMode(true);
775+ value.put(1);
776+ value.put(2);
777+ value.put(null);
778+ value.put(4);
779+ value.put(null);
780+ value.put(null);
781+ value.put(null);
782+ value.put(8);
783+ value.setStreamMode(false);
784+ value.setStreamMode(true);
785+ assertEquals("expected value of field 1", 1, value.get());
786+ assertEquals("expected value of field 2", 2, value.get());
787+ assertTrue("field 3 is null, don't advance cursor", value.isNull());
788+ assertTrue("field 3 is null, don't advance cursor", value.isNull());
789+ assertTrue("field 3 is null, don't advance cursor", value.isNull());
790+ assertTrue("field 3 is null, do advance cursor", value.isNull(true));
791+ assertTrue("should be field 4", !value.isNull());
792+ assertTrue("should be field 4", !value.isNull(true));
793+ assertEquals("expected value of field 4", 4, value.getInt());
794+ assertTrue("field 5 should be null", value.isNull(true));
795+ assertTrue("field 6 should be null", value.isNull(true));
796+ assertTrue("field 7 should be null", value.isNull(true));
797+ assertTrue("field 8 should not be null", !value.isNull(true));
798+ assertTrue("field 8 should not be null", !value.isNull(true));
799+ assertTrue("field 8 should not be null", !value.isNull(true));
800+ assertTrue("field 8 should not be null", !value.isNull(true));
801+ assertEquals("expected value of field 8", 8, value.get());
802+ }
803+
804+ @Test
805+ public void streamModeGetAfterSkip() throws Exception {
806+ final Value value = new Value(_persistit);
807+ value.setStreamMode(true);
808+ // All same instance due to constant intern
809+ value.put(ABC);
810+ value.put(2);
811+ value.put(ABC);
812+ value.put(4);
813+ value.put(ABC);
814+ value.put(6);
815+ value.put(ABC);
816+ value.put(8);
817+ value.put(ABC);
818+ value.put(ABC);
819+ value.put(ABC);
820+ value.setStreamMode(false);
821+ value.setStreamMode(true);
822+ value.skip(); // "abc"
823+ assertEquals("expect 2", 2, value.getInt());
824+ value.skip(); // "abc"
825+ assertEquals("expect 2", 4, value.getInt());
826+
827+ assertEquals("Field 5 should be a String", String.class, value.getType());
828+ final String s5 = value.getString();
829+ assertEquals("expect value", ABC, s5);
830+
831+ assertEquals("expect 6", 6, value.getInt());
832+
833+ assertEquals("Field 7 should be a String", String.class, value.getType());
834+ final String s7 = value.getString();
835+ assertTrue("expect identical", s5 == s7);
836+
837+ }
838 }

Subscribers

People subscribed via source and target branches