Merge lp:~pbeaman/akiban-persistit/fix-1073357-Value-getType into lp:akiban-persistit
- fix-1073357-Value-getType
- Merge into trunk
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 | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Akiban Build User | Needs Fixing | ||
Nathan Williams | Approve | ||
Review via email: mp+132758@code.launchpad.net |
Commit message
Description of the change
Fixes bug https:/
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.
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.
Peter Beaman (pbeaman) wrote : | # |
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-
Peter Beaman (pbeaman) wrote : | # |
Good idea, done. The method is now
isNull(boolean skipNull)
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?
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?
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.
Peter Beaman (pbeaman) wrote : | # |
Unless you skip the field, like you said... As usual I responded without reading your comment carefully enough.
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.
Thanks for identifying this issue.
Nathan Williams (nwilliams) wrote : | # |
Looks plausible. And who am I to argue with passing tests.
Akiban Build User (build-akiban) wrote : | # |
There were 2 failures during build/test:
* job persistit-build failed at build number 473: http://
* view must-pass failed: persistit-build is yellow
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
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 | } |
Note: the majority of ValueTest4 was deleted because it was identical to ValueTest3.