diff options
author | 2023-02-13 01:29:28 +0100 | |
---|---|---|
committer | 2023-02-13 01:29:28 +0100 | |
commit | 4f447bb7efd453eb6aa17fb29b8a0d7d65c03fcd (patch) | |
tree | 0bbfe721403b1ada3b323993e2f5322fd58abfbc /subprojects/store/src | |
parent | VersionedMapStoreBuilder returns builder state. (diff) | |
download | refinery-4f447bb7efd453eb6aa17fb29b8a0d7d65c03fcd.tar.gz refinery-4f447bb7efd453eb6aa17fb29b8a0d7d65c03fcd.tar.zst refinery-4f447bb7efd453eb6aa17fb29b8a0d7d65c03fcd.zip |
Multiple small updates and fixes to support all upcoming tests.
- AnyVersionedMap.checkIntegrity added to the superclass
- Default value of the map is gettable.
- Errors fixed:
- Delta store failed to update reference to the previous transaction in some cases. Fixed in VersionedMapStoreDeltaImpl.java
import java.util.HashMap;
- Null values caused issues in UncommittedDeltaMapStore.java as putIfAbsent does not work with null.
- Small fixes in DeltaDiffCursor.java and IteratorAsCursor.java
Diffstat (limited to 'subprojects/store/src')
9 files changed, 107 insertions, 25 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 f82a8bb1..ead79878 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 | |||
@@ -37,4 +37,9 @@ public sealed interface AnyVersionedMap extends Versioned permits VersionedMap { | |||
37 | @SuppressWarnings("squid:S1133") | 37 | @SuppressWarnings("squid:S1133") |
38 | @Deprecated(since = "0.0.0") | 38 | @Deprecated(since = "0.0.0") |
39 | boolean equals(Object obj); | 39 | boolean equals(Object obj); |
40 | |||
41 | /** | ||
42 | * Checks the integrity of the map, and throws an exception if an inconsistency is detected. | ||
43 | */ | ||
44 | void checkIntegrity(); | ||
40 | } | 45 | } |
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMap.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMap.java index 31985e94..08ce1dbd 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMap.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMap.java | |||
@@ -1,6 +1,8 @@ | |||
1 | package tools.refinery.store.map; | 1 | package tools.refinery.store.map; |
2 | 2 | ||
3 | public non-sealed interface VersionedMap<K, V> extends AnyVersionedMap { | 3 | public non-sealed interface VersionedMap<K, V> extends AnyVersionedMap { |
4 | V getDefaultValue(); | ||
5 | |||
4 | V get(K key); | 6 | V get(K key); |
5 | 7 | ||
6 | Cursor<K, V> getAll(); | 8 | Cursor<K, V> getAll(); |
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java index 98dec2bb..e556a8bb 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreDeltaImpl.java | |||
@@ -49,21 +49,22 @@ public class VersionedMapStoreDeltaImpl<K, V> implements VersionedMapStore<K, V> | |||
49 | return states.get(state); | 49 | return states.get(state); |
50 | } | 50 | } |
51 | 51 | ||
52 | public void getPath(long to, List<MapDelta<K, V>[]> forwardTransactions) { | 52 | public MapTransaction<K, V> getPath(long to, List<MapDelta<K, V>[]> forwardTransactions) { |
53 | MapTransaction<K, V> toTransaction = getState(to); | 53 | MapTransaction<K, V> toTransaction = getState(to); |
54 | while (toTransaction != null) { | 54 | while (toTransaction != null) { |
55 | forwardTransactions.add(toTransaction.deltas()); | 55 | forwardTransactions.add(toTransaction.deltas()); |
56 | toTransaction = toTransaction.parent(); | 56 | toTransaction = toTransaction.parent(); |
57 | } | 57 | } |
58 | return toTransaction; | ||
58 | } | 59 | } |
59 | 60 | ||
60 | public void getPath(long from, long to, | 61 | public MapTransaction<K, V> getPath(long from, long to, |
61 | List<MapDelta<K, V>[]> backwardTransactions, | 62 | List<MapDelta<K, V>[]> backwardTransactions, |
62 | List<MapDelta<K, V>[]> forwardTransactions) { | 63 | List<MapDelta<K, V>[]> forwardTransactions) { |
63 | MapTransaction<K, V> fromTransaction = getState(from); | 64 | MapTransaction<K, V> fromTransaction = getState(from); |
64 | MapTransaction<K, V> toTransaction = getState(to); | 65 | MapTransaction<K, V> toTransaction = getState(to); |
65 | while (fromTransaction != toTransaction) { | 66 | while (fromTransaction != toTransaction) { |
66 | if (fromTransaction == null || fromTransaction.version() < toTransaction.version()) { | 67 | if (fromTransaction == null || (toTransaction != null && fromTransaction.version() < toTransaction.version())) { |
67 | forwardTransactions.add(toTransaction.deltas()); | 68 | forwardTransactions.add(toTransaction.deltas()); |
68 | toTransaction = toTransaction.parent(); | 69 | toTransaction = toTransaction.parent(); |
69 | } else { | 70 | } else { |
@@ -71,6 +72,7 @@ public class VersionedMapStoreDeltaImpl<K, V> implements VersionedMapStore<K, V> | |||
71 | fromTransaction = fromTransaction.parent(); | 72 | fromTransaction = fromTransaction.parent(); |
72 | } | 73 | } |
73 | } | 74 | } |
75 | return toTransaction; | ||
74 | } | 76 | } |
75 | 77 | ||
76 | 78 | ||
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaDiffCursor.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaDiffCursor.java index 75180bf9..49ea1f67 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaDiffCursor.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/DeltaDiffCursor.java | |||
@@ -62,6 +62,7 @@ public class DeltaDiffCursor<K, V> implements DiffCursor<K, V> { | |||
62 | return this.direction && listIndex == -1; | 62 | return this.direction && listIndex == -1; |
63 | } | 63 | } |
64 | 64 | ||
65 | |||
65 | @Override | 66 | @Override |
66 | public boolean move() { | 67 | public boolean move() { |
67 | if (isTerminated()) { | 68 | if (isTerminated()) { |
@@ -74,6 +75,7 @@ public class DeltaDiffCursor<K, V> implements DiffCursor<K, V> { | |||
74 | } else { | 75 | } else { |
75 | if (listIndex-1 >= 0) { | 76 | if (listIndex-1 >= 0) { |
76 | listIndex--; | 77 | listIndex--; |
78 | arrayIndex = 0; | ||
77 | return true; | 79 | return true; |
78 | } else { | 80 | } else { |
79 | listIndex = -1; | 81 | listIndex = -1; |
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/IteratorAsCursor.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/IteratorAsCursor.java index 4a8e9709..c1a0aec4 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/IteratorAsCursor.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/IteratorAsCursor.java | |||
@@ -18,7 +18,6 @@ public class IteratorAsCursor<K, V> implements Cursor<K, V> { | |||
18 | public IteratorAsCursor(VersionedMap<K, V> source, Map<K, V> current) { | 18 | public IteratorAsCursor(VersionedMap<K, V> source, Map<K, V> current) { |
19 | this.iterator = current.entrySet().iterator(); | 19 | this.iterator = current.entrySet().iterator(); |
20 | this.source = source; | 20 | this.source = source; |
21 | move(); | ||
22 | } | 21 | } |
23 | 22 | ||
24 | @Override | 23 | @Override |
@@ -38,7 +37,7 @@ public class IteratorAsCursor<K, V> implements Cursor<K, V> { | |||
38 | 37 | ||
39 | @Override | 38 | @Override |
40 | public boolean move() { | 39 | public boolean move() { |
41 | terminated = iterator.hasNext(); | 40 | terminated = !iterator.hasNext(); |
42 | if (terminated) { | 41 | if (terminated) { |
43 | this.key = null; | 42 | this.key = null; |
44 | this.value = null; | 43 | this.value = null; |
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaMapStore.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaMapStore.java index 73df5080..31423b1c 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaMapStore.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaMapStore.java | |||
@@ -1,7 +1,6 @@ | |||
1 | package tools.refinery.store.map.internal; | 1 | package tools.refinery.store.map.internal; |
2 | 2 | ||
3 | import java.util.HashMap; | 3 | import java.util.*; |
4 | import java.util.Map; | ||
5 | import java.util.Map.Entry; | 4 | import java.util.Map.Entry; |
6 | 5 | ||
7 | import tools.refinery.store.map.VersionedMap; | 6 | import tools.refinery.store.map.VersionedMap; |
@@ -16,7 +15,9 @@ public class UncommittedDeltaMapStore<K, V> implements UncommittedDeltaStore<K, | |||
16 | 15 | ||
17 | @Override | 16 | @Override |
18 | public void processChange(K key, V oldValue, V newValue) { | 17 | public void processChange(K key, V oldValue, V newValue) { |
19 | this.uncommittedOldValues.putIfAbsent(key, oldValue); | 18 | if(!uncommittedOldValues.containsKey(key)) { |
19 | this.uncommittedOldValues.put(key,oldValue); | ||
20 | } | ||
20 | } | 21 | } |
21 | 22 | ||
22 | @Override | 23 | @Override |
@@ -25,13 +26,13 @@ public class UncommittedDeltaMapStore<K, V> implements UncommittedDeltaStore<K, | |||
25 | return null; | 26 | return null; |
26 | } else { | 27 | } else { |
27 | @SuppressWarnings("unchecked") | 28 | @SuppressWarnings("unchecked") |
28 | MapDelta<K, V>[] deltas = new MapDelta[uncommittedOldValues.size()]; | 29 | MapDelta<K,V>[] deltas = new MapDelta[uncommittedOldValues.size()]; |
29 | int i = 0; | 30 | int i = 0; |
30 | for (Entry<K, V> entry : uncommittedOldValues.entrySet()) { | 31 | for (Entry<K, V> entry : uncommittedOldValues.entrySet()) { |
31 | final K key = entry.getKey(); | 32 | final K key = entry.getKey(); |
32 | final V oldValue = entry.getValue(); | 33 | final V oldValue = entry.getValue(); |
33 | final V newValue = source.get(key); | 34 | final V newValue = source.get(key); |
34 | deltas[i] = new MapDelta<>(key, oldValue, newValue); | 35 | deltas[i++] = new MapDelta<>(key, oldValue, newValue); |
35 | } | 36 | } |
36 | 37 | ||
37 | return deltas; | 38 | return deltas; |
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaStore.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaStore.java index 37e5817c..7b017c8e 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaStore.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/UncommittedDeltaStore.java | |||
@@ -7,4 +7,18 @@ public interface UncommittedDeltaStore<K, V> { | |||
7 | 7 | ||
8 | MapDelta<K, V>[] extractAndDeleteDeltas(); | 8 | MapDelta<K, V>[] extractAndDeleteDeltas(); |
9 | 9 | ||
10 | default void checkIntegrity() { | ||
11 | MapDelta<K, V>[] extractedDeltas = extractDeltas(); | ||
12 | if(extractedDeltas != null) { | ||
13 | for(var uncommittedOldValue : extractedDeltas) { | ||
14 | if(uncommittedOldValue == null) { | ||
15 | throw new IllegalArgumentException("Null entry in deltas!"); | ||
16 | } | ||
17 | if(uncommittedOldValue.getKey() == null) { | ||
18 | throw new IllegalStateException("Null key in deltas!"); | ||
19 | } | ||
20 | } | ||
21 | } | ||
22 | } | ||
23 | |||
10 | } | 24 | } |
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapDeltaImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapDeltaImpl.java index 6f2996e1..d09e54ba 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapDeltaImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapDeltaImpl.java | |||
@@ -19,7 +19,7 @@ public class VersionedMapDeltaImpl<K, V> implements VersionedMap<K, V> { | |||
19 | this.defaultValue = defaultValue; | 19 | this.defaultValue = defaultValue; |
20 | 20 | ||
21 | current = new HashMap<>(); | 21 | current = new HashMap<>(); |
22 | if(summarizeChanges) { | 22 | if (summarizeChanges) { |
23 | this.uncommittedStore = new UncommittedDeltaMapStore<>(this); | 23 | this.uncommittedStore = new UncommittedDeltaMapStore<>(this); |
24 | } else { | 24 | } else { |
25 | this.uncommittedStore = new UncommittedDeltaArrayStore<>(); | 25 | this.uncommittedStore = new UncommittedDeltaArrayStore<>(); |
@@ -27,6 +27,11 @@ public class VersionedMapDeltaImpl<K, V> implements VersionedMap<K, V> { | |||
27 | } | 27 | } |
28 | 28 | ||
29 | @Override | 29 | @Override |
30 | public V getDefaultValue() { | ||
31 | return defaultValue; | ||
32 | } | ||
33 | |||
34 | @Override | ||
30 | public long commit() { | 35 | public long commit() { |
31 | MapDelta<K, V>[] deltas = uncommittedStore.extractAndDeleteDeltas(); | 36 | MapDelta<K, V>[] deltas = uncommittedStore.extractAndDeleteDeltas(); |
32 | long[] versionContainer = new long[1]; | 37 | long[] versionContainer = new long[1]; |
@@ -43,16 +48,18 @@ public class VersionedMapDeltaImpl<K, V> implements VersionedMap<K, V> { | |||
43 | } | 48 | } |
44 | 49 | ||
45 | // 2. get common ancestor | 50 | // 2. get common ancestor |
51 | final MapTransaction<K,V> parent; | ||
46 | List<MapDelta<K, V>[]> forward = new ArrayList<>(); | 52 | List<MapDelta<K, V>[]> forward = new ArrayList<>(); |
47 | if (this.previous == null) { | 53 | if (this.previous == null) { |
48 | this.store.getPath(state, forward); | 54 | parent = this.store.getPath(state, forward); |
49 | this.forward(forward); | 55 | this.forward(forward); |
50 | } else { | 56 | } else { |
51 | List<MapDelta<K, V>[]> backward = new ArrayList<>(); | 57 | List<MapDelta<K, V>[]> backward = new ArrayList<>(); |
52 | this.store.getPath(this.previous.version(), state, backward, forward); | 58 | parent = this.store.getPath(this.previous.version(), state, backward, forward); |
53 | this.backward(backward); | 59 | this.backward(backward); |
54 | this.forward(forward); | 60 | this.forward(forward); |
55 | } | 61 | } |
62 | this.previous = parent; | ||
56 | } | 63 | } |
57 | 64 | ||
58 | protected void forward(List<MapDelta<K, V>[]> changes) { | 65 | protected void forward(List<MapDelta<K, V>[]> changes) { |
@@ -70,14 +77,28 @@ public class VersionedMapDeltaImpl<K, V> implements VersionedMap<K, V> { | |||
70 | protected void forward(MapDelta<K, V>[] changes) { | 77 | protected void forward(MapDelta<K, V>[] changes) { |
71 | for (int i = 0; i < changes.length; i++) { | 78 | for (int i = 0; i < changes.length; i++) { |
72 | final MapDelta<K, V> change = changes[i]; | 79 | final MapDelta<K, V> change = changes[i]; |
73 | current.put(change.getKey(), change.getNewValue()); | 80 | K key = change.getKey(); |
81 | V newValue = change.getNewValue(); | ||
82 | |||
83 | if(newValue == defaultValue) { | ||
84 | current.remove(key); | ||
85 | } else { | ||
86 | current.put(key,newValue); | ||
87 | } | ||
74 | } | 88 | } |
75 | } | 89 | } |
76 | 90 | ||
77 | protected void backward(MapDelta<K, V>[] changes) { | 91 | protected void backward(MapDelta<K, V>[] changes) { |
78 | for (int i = changes.length - 1; i >= 0; i--) { | 92 | for (int i = changes.length - 1; i >= 0; i--) { |
79 | final MapDelta<K, V> change = changes[i]; | 93 | final MapDelta<K, V> change = changes[i]; |
80 | current.put(change.getKey(), change.getOldValue()); | 94 | K key = change.getKey(); |
95 | V oldValue = change.oldValue(); | ||
96 | |||
97 | if(oldValue == defaultValue) { | ||
98 | current.remove(key); | ||
99 | } else { | ||
100 | current.put(key,oldValue); | ||
101 | } | ||
81 | } | 102 | } |
82 | } | 103 | } |
83 | 104 | ||
@@ -93,26 +114,46 @@ public class VersionedMapDeltaImpl<K, V> implements VersionedMap<K, V> { | |||
93 | 114 | ||
94 | @Override | 115 | @Override |
95 | public V put(K key, V value) { | 116 | public V put(K key, V value) { |
96 | if (value == defaultValue) { | 117 | final V oldValue; |
97 | V res = current.remove(key); | 118 | if (Objects.equals(value, defaultValue)) { |
119 | final V res = current.remove(key); | ||
98 | if (res == null) { | 120 | if (res == null) { |
99 | // no changes | 121 | // no changes: default > default |
100 | return defaultValue; | 122 | oldValue = defaultValue; |
101 | } else { | 123 | } else { |
102 | uncommittedStore.processChange(key, res, value); | 124 | oldValue = res; |
103 | return res; | ||
104 | } | 125 | } |
105 | } else { | 126 | } else { |
106 | V oldValue = current.put(key, value); | 127 | final var mapValue = current.put(key, value); |
128 | if (mapValue == null) { | ||
129 | oldValue = defaultValue; | ||
130 | } else { | ||
131 | oldValue = mapValue; | ||
132 | } | ||
133 | } | ||
134 | if(!Objects.equals(oldValue,value)) { | ||
107 | uncommittedStore.processChange(key, oldValue, value); | 135 | uncommittedStore.processChange(key, oldValue, value); |
108 | return oldValue; | ||
109 | } | 136 | } |
137 | return oldValue; | ||
110 | } | 138 | } |
111 | 139 | ||
112 | @Override | 140 | @Override |
113 | public void putAll(Cursor<K, V> cursor) { | 141 | public void putAll(Cursor<K, V> cursor) { |
114 | throw new UnsupportedOperationException(); | 142 | if (cursor.getDependingMaps().contains(this)) { |
115 | 143 | List<K> keys = new ArrayList<>(); | |
144 | List<V> values = new ArrayList<>(); | ||
145 | while (cursor.move()) { | ||
146 | keys.add(cursor.getKey()); | ||
147 | values.add(cursor.getValue()); | ||
148 | } | ||
149 | for (int i = 0; i < keys.size(); i++) { | ||
150 | this.put(keys.get(i), values.get(i)); | ||
151 | } | ||
152 | } else { | ||
153 | while (cursor.move()) { | ||
154 | this.put(cursor.getKey(), cursor.getValue()); | ||
155 | } | ||
156 | } | ||
116 | } | 157 | } |
117 | 158 | ||
118 | @Override | 159 | @Override |
@@ -156,4 +197,18 @@ public class VersionedMapDeltaImpl<K, V> implements VersionedMap<K, V> { | |||
156 | throw new UnsupportedOperationException("Comparing different map implementations is ineffective."); | 197 | throw new UnsupportedOperationException("Comparing different map implementations is ineffective."); |
157 | } | 198 | } |
158 | } | 199 | } |
200 | |||
201 | @Override | ||
202 | public void checkIntegrity() { | ||
203 | this.uncommittedStore.checkIntegrity(); | ||
204 | |||
205 | for (var entry : this.current.entrySet()) { | ||
206 | var value = entry.getValue(); | ||
207 | if (value == this.defaultValue) { | ||
208 | throw new IllegalStateException("Default value stored in map!"); | ||
209 | } else if (value == null) { | ||
210 | throw new IllegalStateException("null value stored in map!"); | ||
211 | } | ||
212 | } | ||
213 | } | ||
159 | } | 214 | } |
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 674ffc47..fb359431 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 | |||
@@ -43,6 +43,7 @@ public class VersionedMapImpl<K, V> implements VersionedMap<K, V> { | |||
43 | this.root = data; | 43 | this.root = data; |
44 | } | 44 | } |
45 | 45 | ||
46 | @Override | ||
46 | public V getDefaultValue() { | 47 | public V getDefaultValue() { |
47 | return defaultValue; | 48 | return defaultValue; |
48 | } | 49 | } |
@@ -141,6 +142,7 @@ public class VersionedMapImpl<K, V> implements VersionedMap<K, V> { | |||
141 | } | 142 | } |
142 | } | 143 | } |
143 | 144 | ||
145 | @Override | ||
144 | public void checkIntegrity() { | 146 | public void checkIntegrity() { |
145 | if (this.root != null) { | 147 | if (this.root != null) { |
146 | this.root.checkIntegrity(hashProvider, defaultValue, 0); | 148 | this.root.checkIntegrity(hashProvider, defaultValue, 0); |