diff options
Diffstat (limited to 'subprojects')
6 files changed, 135 insertions, 58 deletions
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/AnyVersionedMap.java b/subprojects/store/src/main/java/tools/refinery/store/map/AnyVersionedMap.java index b94b9f38..f82a8bb1 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/AnyVersionedMap.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/AnyVersionedMap.java | |||
@@ -2,4 +2,39 @@ package tools.refinery.store.map; | |||
2 | 2 | ||
3 | public sealed interface AnyVersionedMap extends Versioned permits VersionedMap { | 3 | public sealed interface AnyVersionedMap extends Versioned permits VersionedMap { |
4 | long getSize(); | 4 | long getSize(); |
5 | |||
6 | int contentHashCode(ContentHashCode mode); | ||
7 | |||
8 | boolean contentEquals(AnyVersionedMap other); | ||
9 | |||
10 | /** | ||
11 | * Returns a hash code value for the object. | ||
12 | * | ||
13 | * @return A hash code value for this object. | ||
14 | * @deprecated {@link AnyVersionedMap} instances are mutable, and it is inappropriate to use them as keys in | ||
15 | * hash-based collections. Use {@link AnyVersionedMap#contentHashCode(ContentHashCode)} to compute a | ||
16 | * <code>hashCode</code> for a {@link AnyVersionedMap} instance according to its contents. | ||
17 | */ | ||
18 | @Override | ||
19 | // This method is mark as @Deprecated to prevent inappropriate use of built-in Java API. | ||
20 | // Therefore, we don't follow normal procedures for removing deprecated code. | ||
21 | @SuppressWarnings("squid:S1133") | ||
22 | @Deprecated(since = "0.0.0") | ||
23 | int hashCode(); | ||
24 | |||
25 | /** | ||
26 | * Compares two objects by reference. | ||
27 | * | ||
28 | * @param obj The reference object with which to compare. | ||
29 | * @return <code>true</code> if this object is the same as the <code>obj</code> argument. | ||
30 | * @deprecated {@link AnyVersionedMap} instances are mutable, and it is inappropriate to use them as keys in | ||
31 | * hash-based collections. Use {@link AnyVersionedMap#contentEquals(AnyVersionedMap)} to compare two | ||
32 | * {@link AnyVersionedMap} instances by their contents. | ||
33 | */ | ||
34 | @Override | ||
35 | // This method is mark as @Deprecated to prevent inappropriate use of built-in Java API. | ||
36 | // Therefore, we don't follow normal procedures for removing deprecated code. | ||
37 | @SuppressWarnings("squid:S1133") | ||
38 | @Deprecated(since = "0.0.0") | ||
39 | boolean equals(Object obj); | ||
5 | } | 40 | } |
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/ContentHashCode.java b/subprojects/store/src/main/java/tools/refinery/store/map/ContentHashCode.java new file mode 100644 index 00000000..8deeab23 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/map/ContentHashCode.java | |||
@@ -0,0 +1,19 @@ | |||
1 | package tools.refinery.store.map; | ||
2 | |||
3 | public enum ContentHashCode { | ||
4 | /** | ||
5 | * Calculate the <code>hashCode</code> of the contents of this {@link AnyVersionedMap} to reduce hash collisions as | ||
6 | * much as possible, even iterating over the full contents in necessary. | ||
7 | */ | ||
8 | PRECISE_SLOW, | ||
9 | |||
10 | /** | ||
11 | * Compute an approximate <code>hashCode</code> of the contents of this {@link AnyVersionedMap} that may have a | ||
12 | * large number of hash collisions, but can be calculated without iterating over the full contents. | ||
13 | * <p> | ||
14 | * In the extreme case, {@link AnyVersionedMap#contentHashCode(ContentHashCode)} may return the same | ||
15 | * <code>hashCode</code> irrespectively of the actual contents of the {@link AnyVersionedMap}. | ||
16 | * </p> | ||
17 | */ | ||
18 | APPROXIMATE_FAST | ||
19 | } | ||
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java index 1698830f..91a71e3d 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java | |||
@@ -1,6 +1,7 @@ | |||
1 | package tools.refinery.store.map.internal; | 1 | package tools.refinery.store.map.internal; |
2 | 2 | ||
3 | import tools.refinery.store.map.AnyVersionedMap; | 3 | import tools.refinery.store.map.AnyVersionedMap; |
4 | import tools.refinery.store.map.ContentHashCode; | ||
4 | import tools.refinery.store.map.Cursor; | 5 | import tools.refinery.store.map.Cursor; |
5 | import tools.refinery.store.map.VersionedMap; | 6 | import tools.refinery.store.map.VersionedMap; |
6 | 7 | ||
@@ -45,7 +46,7 @@ public class MapCursor<K, V> implements Cursor<K, V> { | |||
45 | 46 | ||
46 | // Initializing state | 47 | // Initializing state |
47 | this.map = map; | 48 | this.map = map; |
48 | this.creationHash = map.hashCode(); | 49 | this.creationHash = map.contentHashCode(ContentHashCode.APPROXIMATE_FAST); |
49 | } | 50 | } |
50 | 51 | ||
51 | public K getKey() { | 52 | public K getKey() { |
@@ -87,7 +88,7 @@ public class MapCursor<K, V> implements Cursor<K, V> { | |||
87 | 88 | ||
88 | @Override | 89 | @Override |
89 | public boolean isDirty() { | 90 | public boolean isDirty() { |
90 | return this.map.hashCode() != this.creationHash; | 91 | return this.map.contentHashCode(ContentHashCode.APPROXIMATE_FAST) != this.creationHash; |
91 | } | 92 | } |
92 | 93 | ||
93 | @Override | 94 | @Override |
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java index 866e7b33..301bcb95 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java | |||
@@ -5,6 +5,7 @@ import tools.refinery.store.map.*; | |||
5 | import java.util.Iterator; | 5 | import java.util.Iterator; |
6 | import java.util.LinkedList; | 6 | import java.util.LinkedList; |
7 | import java.util.List; | 7 | import java.util.List; |
8 | import java.util.Objects; | ||
8 | 9 | ||
9 | /** | 10 | /** |
10 | * Not threadSafe in itself | 11 | * Not threadSafe in itself |
@@ -145,4 +146,15 @@ public class VersionedMapImpl<K, V> implements VersionedMap<K, V> { | |||
145 | this.root.checkIntegrity(hashProvider, defaultValue, 0); | 146 | this.root.checkIntegrity(hashProvider, defaultValue, 0); |
146 | } | 147 | } |
147 | } | 148 | } |
149 | |||
150 | @Override | ||
151 | public int contentHashCode(ContentHashCode mode) { | ||
152 | // Calculating the root hashCode is always fast, because {@link Node} caches its hashCode. | ||
153 | return Objects.hashCode(root); | ||
154 | } | ||
155 | |||
156 | @Override | ||
157 | public boolean contentEquals(AnyVersionedMap other) { | ||
158 | return other instanceof VersionedMapImpl<?, ?> otherImpl && Objects.equals(root, otherImpl.root); | ||
159 | } | ||
148 | } | 160 | } |
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java index d7f77d1a..93ecfec3 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java | |||
@@ -17,12 +17,11 @@ import java.util.List; | |||
17 | import java.util.Random; | 17 | import java.util.Random; |
18 | import java.util.stream.Stream; | 18 | import java.util.stream.Stream; |
19 | 19 | ||
20 | import static org.junit.jupiter.api.Assertions.assertEquals; | 20 | import static org.junit.jupiter.api.Assertions.*; |
21 | import static org.junit.jupiter.api.Assertions.fail; | ||
22 | 21 | ||
23 | class ContentEqualsFuzzTest { | 22 | class ContentEqualsFuzzTest { |
24 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, | 23 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, |
25 | boolean evilHash) { | 24 | boolean evilHash) { |
26 | String[] values = MapTestEnvironment.prepareValues(maxValue); | 25 | String[] values = MapTestEnvironment.prepareValues(maxValue); |
27 | ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); | 26 | ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); |
28 | 27 | ||
@@ -31,7 +30,9 @@ class ContentEqualsFuzzTest { | |||
31 | iterativeRandomPutsAndCommitsThenCompare(scenario, chp, steps, maxKey, values, r, commitFrequency); | 30 | iterativeRandomPutsAndCommitsThenCompare(scenario, chp, steps, maxKey, values, r, commitFrequency); |
32 | } | 31 | } |
33 | 32 | ||
34 | private void iterativeRandomPutsAndCommitsThenCompare(String scenario, ContinousHashProvider<Integer> chp, int steps, int maxKey, String[] values, Random r, int commitFrequency) { | 33 | private void iterativeRandomPutsAndCommitsThenCompare(String scenario, ContinousHashProvider<Integer> chp, |
34 | int steps, int maxKey, String[] values, Random r, | ||
35 | int commitFrequency) { | ||
35 | VersionedMapStore<Integer, String> store1 = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); | 36 | VersionedMapStore<Integer, String> store1 = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); |
36 | VersionedMap<Integer, String> sut1 = store1.createMap(); | 37 | VersionedMap<Integer, String> sut1 = store1.createMap(); |
37 | 38 | ||
@@ -67,58 +68,43 @@ class ContentEqualsFuzzTest { | |||
67 | int index2 = 1; | 68 | int index2 = 1; |
68 | for (SimpleEntry<Integer, String> entry : content) { | 69 | for (SimpleEntry<Integer, String> entry : content) { |
69 | sut2.put(entry.getKey(), entry.getValue()); | 70 | sut2.put(entry.getKey(), entry.getValue()); |
70 | if(index2++%commitFrequency == 0) | 71 | if (index2++ % commitFrequency == 0) |
71 | sut2.commit(); | 72 | sut2.commit(); |
72 | } | 73 | } |
73 | 74 | ||
74 | // Check the integrity of the maps | 75 | // Check the integrity of the maps |
75 | ((VersionedMapImpl<Integer,String>) sut1).checkIntegrity(); | 76 | ((VersionedMapImpl<Integer, String>) sut1).checkIntegrity(); |
76 | ((VersionedMapImpl<Integer,String>) sut2).checkIntegrity(); | 77 | ((VersionedMapImpl<Integer, String>) sut2).checkIntegrity(); |
77 | 78 | ||
78 | // // Compare the two maps | 79 | // Compare the two maps |
79 | // By size | 80 | MapTestEnvironment.compareTwoMaps(scenario, sut1, sut2); |
80 | assertEquals(sut1.getSize(), content.size()); | ||
81 | assertEquals(sut2.getSize(), content.size()); | ||
82 | |||
83 | // By cursors | ||
84 | Cursor<Integer, String> cursor1 = sut1.getAll(); | ||
85 | Cursor<Integer, String> cursor2 = sut2.getAll(); | ||
86 | int index3 = 1; | ||
87 | boolean canMove = true; | ||
88 | do{ | ||
89 | boolean canMove1 = cursor1.move(); | ||
90 | boolean canMove2 = cursor2.move(); | ||
91 | assertEquals(canMove1, canMove2, scenario + ":" + index3 +" Cursors stopped at different times!"); | ||
92 | assertEquals(cursor1.getKey(), cursor2.getKey(), scenario + ":" + index3 +" Cursors have different keys!"); | ||
93 | assertEquals(cursor1.getValue(), cursor2.getValue(), scenario + ":" + index3 +" Cursors have different values!"); | ||
94 | |||
95 | canMove = canMove1; | ||
96 | MapTestEnvironment.printStatus(scenario, index3++, content.size(), "Compare"); | ||
97 | } while (canMove); | ||
98 | } | 81 | } |
99 | 82 | ||
100 | @ParameterizedTest(name = "Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | 83 | @ParameterizedTest(name = "Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} " + |
84 | "evil-hash={6}") | ||
101 | @MethodSource | 85 | @MethodSource |
102 | @Timeout(value = 10) | 86 | @Timeout(value = 10) |
103 | @Tag("fuzz") | 87 | @Tag("fuzz") |
104 | void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | 88 | void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, |
105 | boolean evilHash) { | 89 | boolean evilHash) { |
106 | runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, | 90 | runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, |
107 | commitFrequency, evilHash); | 91 | commitFrequency, evilHash); |
108 | } | 92 | } |
109 | 93 | ||
110 | static Stream<Arguments> parametrizedFastFuzz() { | 94 | static Stream<Arguments> parametrizedFastFuzz() { |
111 | return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, | 95 | return FuzzTestUtils.permutationWithSize(new Object[]{FuzzTestUtils.FAST_STEP_COUNT}, new Object[]{3, 32, |
112 | new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, | 96 | 32 * 32}, |
113 | new Object[] { false, true }); | 97 | new Object[]{2, 3}, new Object[]{1, 10, 100}, new Object[]{1, 2, 3}, |
98 | new Object[]{false, true}); | ||
114 | } | 99 | } |
115 | 100 | ||
116 | @ParameterizedTest(name = "Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | 101 | @ParameterizedTest(name = "Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} " + |
102 | "evil-hash={6}") | ||
117 | @MethodSource | 103 | @MethodSource |
118 | @Tag("fuzz") | 104 | @Tag("fuzz") |
119 | @Tag("slow") | 105 | @Tag("slow") |
120 | void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | 106 | void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, |
121 | boolean evilHash) { | 107 | boolean evilHash) { |
122 | runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, | 108 | runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, |
123 | commitFrequency, evilHash); | 109 | commitFrequency, evilHash); |
124 | } | 110 | } |
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java index b73f8b32..2d03ebaf 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java | |||
@@ -1,8 +1,6 @@ | |||
1 | package tools.refinery.store.map.tests.utils; | 1 | package tools.refinery.store.map.tests.utils; |
2 | 2 | ||
3 | import tools.refinery.store.map.ContinousHashProvider; | 3 | import tools.refinery.store.map.*; |
4 | import tools.refinery.store.map.Cursor; | ||
5 | import tools.refinery.store.map.VersionedMap; | ||
6 | import tools.refinery.store.map.internal.VersionedMapImpl; | 4 | import tools.refinery.store.map.internal.VersionedMapImpl; |
7 | 5 | ||
8 | import java.util.*; | 6 | import java.util.*; |
@@ -50,40 +48,65 @@ public class MapTestEnvironment<K, V> { | |||
50 | 48 | ||
51 | } | 49 | } |
52 | 50 | ||
53 | public static <K, V> void compareTwoMaps(String title, VersionedMapImpl<K, V> map1, | 51 | public static <K, V> void compareTwoMaps(String title, VersionedMap<K, V> map1, |
54 | VersionedMapImpl<K, V> map2) { | 52 | VersionedMap<K, V> map2) { |
55 | compareTwoMaps(title, map1, map2, null); | 53 | compareTwoMaps(title, map1, map2, null); |
56 | } | 54 | } |
57 | public static <K, V> void compareTwoMaps(String title, VersionedMapImpl<K, V> map1, | 55 | |
58 | VersionedMapImpl<K, V> map2, List<Throwable> errors) { | 56 | public static <K, V> void compareTwoMaps(String title, VersionedMap<K, V> map1, |
57 | VersionedMap<K, V> map2, List<Throwable> errors) { | ||
58 | assertEqualsList(map1.getSize(), map2.getSize(), title + ": Sizes not equal", errors); | ||
59 | |||
59 | Cursor<K, V> cursor1 = map1.getAll(); | 60 | Cursor<K, V> cursor1 = map1.getAll(); |
60 | Cursor<K, V> cursor2 = map2.getAll(); | 61 | Cursor<K, V> cursor2 = map2.getAll(); |
61 | while (!cursor1.isTerminated()) { | 62 | while (!cursor1.isTerminated()) { |
62 | if (cursor2.isTerminated()) { | 63 | if (cursor2.isTerminated()) { |
63 | fail("cursor 2 terminated before cursor1"); | 64 | fail("cursor 2 terminated before cursor1"); |
64 | } | 65 | } |
65 | assertEqualsList(cursor1.getKey(), cursor2.getKey(),"Keys not equal", errors); | 66 | assertEqualsList(cursor1.getKey(), cursor2.getKey(), title + ": Keys not equal", errors); |
66 | assertEqualsList(cursor2.getValue(), cursor2.getValue(), "Values not equal", errors); | 67 | assertEqualsList(cursor2.getValue(), cursor2.getValue(), title + ": Values not equal", errors); |
67 | cursor1.move(); | 68 | cursor1.move(); |
68 | cursor2.move(); | 69 | cursor2.move(); |
69 | } | 70 | } |
70 | if (!cursor2.isTerminated()) | 71 | if (!cursor2.isTerminated()) { |
71 | fail("cursor 1 terminated before cursor 2"); | 72 | fail("cursor 1 terminated before cursor 2"); |
73 | } | ||
74 | |||
75 | for (var mode : ContentHashCode.values()) { | ||
76 | assertEqualsList(map1.contentHashCode(mode), map2.contentHashCode(mode), | ||
77 | title + ": " + mode + " hashCode check", errors); | ||
78 | } | ||
79 | assertContentEqualsList(map1, map2, title + ": map1.contentEquals(map2)", errors); | ||
80 | assertContentEqualsList(map2, map1, title + ": map2.contentEquals(map1)", errors); | ||
72 | } | 81 | } |
73 | 82 | ||
74 | private static void assertEqualsList(Object o1, Object o2, String message, List<Throwable> errors) { | 83 | private static void assertEqualsList(Object o1, Object o2, String message, List<Throwable> errors) { |
75 | if(errors == null) { | 84 | if (errors == null) { |
76 | assertEquals(o1, o2, message); | 85 | assertEquals(o1, o2, message); |
77 | } else { | 86 | } else { |
78 | if(o1 != null) { | 87 | if (o1 != null) { |
79 | if(!(o1.equals(o2))) { | 88 | if (!(o1.equals(o2))) { |
80 | AssertionError error = new AssertionError((message != null ? message+" " : "") + "expected: " + o1 + " but was : " + o2); | 89 | AssertionError error = |
90 | new AssertionError((message != null ? message + " " : "") + "expected: " + o1 + " but was " + | ||
91 | ": " + o2); | ||
81 | errors.add(error); | 92 | errors.add(error); |
82 | } | 93 | } |
83 | } | 94 | } |
84 | } | 95 | } |
85 | } | 96 | } |
86 | 97 | ||
98 | private static void assertContentEqualsList(AnyVersionedMap o1, AnyVersionedMap o2, String message, | ||
99 | List<Throwable> errors) { | ||
100 | boolean result = o1.contentEquals(o2); | ||
101 | if (errors == null) { | ||
102 | assertTrue(result, message); | ||
103 | } else if (!result) { | ||
104 | AssertionError error = | ||
105 | new AssertionError((message != null ? message + " " : "") + "expected: true but was: false"); | ||
106 | errors.add(error); | ||
107 | } | ||
108 | } | ||
109 | |||
87 | public VersionedMapImpl<K, V> sut; | 110 | public VersionedMapImpl<K, V> sut; |
88 | Map<K, V> oracle = new HashMap<K, V>(); | 111 | Map<K, V> oracle = new HashMap<K, V>(); |
89 | 112 | ||
@@ -99,10 +122,10 @@ public class MapTestEnvironment<K, V> { | |||
99 | } else { | 122 | } else { |
100 | oldOracleValue = oracle.remove(key); | 123 | oldOracleValue = oracle.remove(key); |
101 | } | 124 | } |
102 | if(oldSutValue == sut.getDefaultValue() && oldOracleValue != null) { | 125 | if (oldSutValue == sut.getDefaultValue() && oldOracleValue != null) { |
103 | fail("After put, SUT old nodeId was default, but oracle old value was " + oldOracleValue); | 126 | fail("After put, SUT old nodeId was default, but oracle old value was " + oldOracleValue); |
104 | } | 127 | } |
105 | if(oldSutValue != sut.getDefaultValue()) { | 128 | if (oldSutValue != sut.getDefaultValue()) { |
106 | assertEquals(oldOracleValue, oldSutValue); | 129 | assertEquals(oldOracleValue, oldSutValue); |
107 | } | 130 | } |
108 | } | 131 | } |
@@ -158,14 +181,15 @@ public class MapTestEnvironment<K, V> { | |||
158 | } | 181 | } |
159 | } | 182 | } |
160 | 183 | ||
161 | public static <K,V> void checkOrder(String scenario, VersionedMap<K,V> versionedMap) { | 184 | public static <K, V> void checkOrder(String scenario, VersionedMap<K, V> versionedMap) { |
162 | K previous = null; | 185 | K previous = null; |
163 | Cursor<K, V> cursor = versionedMap.getAll(); | 186 | Cursor<K, V> cursor = versionedMap.getAll(); |
164 | while(cursor.move()) { | 187 | while (cursor.move()) { |
165 | System.out.println(cursor.getKey() + " " + ((VersionedMapImpl<K, V>) versionedMap).getHashProvider().getHash(cursor.getKey(), 0)); | 188 | System.out.println(cursor.getKey() + " " + ((VersionedMapImpl<K, V>) versionedMap).getHashProvider().getHash(cursor.getKey(), 0)); |
166 | if(previous != null) { | 189 | if (previous != null) { |
167 | int comparisonResult = ((VersionedMapImpl<K, V>) versionedMap).getHashProvider().compare(previous, cursor.getKey()); | 190 | int comparisonResult = ((VersionedMapImpl<K, V>) versionedMap).getHashProvider().compare(previous, |
168 | assertTrue(comparisonResult<0,scenario+" Cursor order is not incremental!"); | 191 | cursor.getKey()); |
192 | assertTrue(comparisonResult < 0, scenario + " Cursor order is not incremental!"); | ||
169 | } | 193 | } |
170 | previous = cursor.getKey(); | 194 | previous = cursor.getKey(); |
171 | } | 195 | } |