aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar OszkarSemerath <semerath@mit.bme.hu>2023-07-26 17:48:25 +0200
committerLibravatar OszkarSemerath <semerath@mit.bme.hu>2023-07-26 17:48:25 +0200
commitc272a44efcff7d35a6ba31ef3cd12d1eb17640a0 (patch)
tree5db595fcf8b13ea0c3b4969b4fc3ffacd95b08a5
parentMerge branch 'graphs4value:main' into datastructure (diff)
downloadrefinery-c272a44efcff7d35a6ba31ef3cd12d1eb17640a0.tar.gz
refinery-c272a44efcff7d35a6ba31ef3cd12d1eb17640a0.tar.zst
refinery-c272a44efcff7d35a6ba31ef3cd12d1eb17640a0.zip
Versioned.commit + Versioned.restore uses Version instead of long.
When a Version is collected by gc, the store lets the state get collected by gc as well.
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/Version.java26
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/Versioned.java18
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/VersionedMap.java2
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStore.java8
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreFactoryBuilder.java1
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapStoreFactoryBuilderImpl.java23
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/internal/delta/MapTransaction.java10
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/internal/delta/VersionedMapDeltaImpl.java34
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/internal/delta/VersionedMapStoreDeltaImpl.java41
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/internal/state/ImmutableNode.java3
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/internal/state/StateBasedVersionedMapStoreFactory.java11
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/internal/state/VersionedMapStateImpl.java6
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/internal/state/VersionedMapStoreStateConfiguration.java8
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/internal/state/VersionedMapStoreStateImpl.java44
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/Interpretation.java3
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/Model.java8
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/ModelListener.java4
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java8
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java66
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java6
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java37
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelVersion.java39
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java14
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java21
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java16
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java13
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java2
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java5
30 files changed, 298 insertions, 189 deletions
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/Version.java b/subprojects/store/src/main/java/tools/refinery/store/map/Version.java
new file mode 100644
index 00000000..fa2734e4
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/Version.java
@@ -0,0 +1,26 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.map;
7
8/**
9 * Interface denoting versions of {@link Versioned}.
10 */
11public interface Version {
12 /**
13 * Hashcode should be updated in accordance with equals.
14 * @return a hashcode of the object.
15 */
16 int hashCode();
17
18 /**
19 * Equivalence of two {@link Version}. This equivalence must satisfy the following constraint (in addition to the
20 * constraints of {@link Object#equals(Object)}: if {@code v1} and {@code v2} are {@link Version}s, and {@code v1
21 * .equals(v2)}, then {@code versioned.restore(v1)} must be {@code equals} to {@code versioned.restore(v2)}.
22 * @param o the other object.
23 * @return weather the two versions are equals.
24 */
25 boolean equals(Object o);
26}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/Versioned.java b/subprojects/store/src/main/java/tools/refinery/store/map/Versioned.java
index 55720db3..da12b0a9 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/Versioned.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/Versioned.java
@@ -5,8 +5,20 @@
5 */ 5 */
6package tools.refinery.store.map; 6package tools.refinery.store.map;
7 7
8/**
9 * Object that can save and restore its state.
10 */
8public interface Versioned { 11public interface Versioned {
9 public long commit(); 12 /**
10 //maybe revert()? 13 * Saves the state of the object.
11 public void restore(long state); 14 * @return an object that marks the version of the object at the time the function was called.
15 */
16 Version commit();
17
18 /**
19 * Restores the state of the object.
20 * @param state a {@link Version} object that marks the version. The state must be a {@link Version} object
21 * returned by a previous {@link #commit()}!
22 */
23 void restore(Version state);
12} 24}
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 c8226c3e..28194b58 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
@@ -16,5 +16,5 @@ public non-sealed interface VersionedMap<K, V> extends AnyVersionedMap {
16 16
17 void putAll(Cursor<K, V> cursor); 17 void putAll(Cursor<K, V> cursor);
18 18
19 DiffCursor<K, V> getDiffCursor(long state); 19 DiffCursor<K, V> getDiffCursor(Version state);
20} 20}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStore.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStore.java
index b24c404c..55cf08a5 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStore.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStore.java
@@ -7,17 +7,13 @@ package tools.refinery.store.map;
7 7
8import tools.refinery.store.map.internal.VersionedMapStoreFactoryBuilderImpl; 8import tools.refinery.store.map.internal.VersionedMapStoreFactoryBuilderImpl;
9 9
10import java.util.Set;
11
12public interface VersionedMapStore<K, V> { 10public interface VersionedMapStore<K, V> {
13 11
14 VersionedMap<K, V> createMap(); 12 VersionedMap<K, V> createMap();
15 13
16 VersionedMap<K, V> createMap(long state); 14 VersionedMap<K, V> createMap(Version state);
17
18 Set<Long> getStates();
19 15
20 DiffCursor<K,V> getDiffCursor(long fromState, long toState); 16 DiffCursor<K,V> getDiffCursor(Version fromState, Version toState);
21 17
22 static <K,V> VersionedMapStoreFactoryBuilder<K,V> builder() { 18 static <K,V> VersionedMapStoreFactoryBuilder<K,V> builder() {
23 return new VersionedMapStoreFactoryBuilderImpl<>(); 19 return new VersionedMapStoreFactoryBuilderImpl<>();
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreFactoryBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreFactoryBuilder.java
index 6b4fc2a0..0ac196f2 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreFactoryBuilder.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreFactoryBuilder.java
@@ -20,6 +20,7 @@ public interface VersionedMapStoreFactoryBuilder<K,V> {
20 20
21 VersionedMapStoreFactoryBuilder<K,V> defaultValue(V defaultValue); 21 VersionedMapStoreFactoryBuilder<K,V> defaultValue(V defaultValue);
22 VersionedMapStoreFactoryBuilder<K,V> strategy(StoreStrategy strategy); 22 VersionedMapStoreFactoryBuilder<K,V> strategy(StoreStrategy strategy);
23 VersionedMapStoreFactoryBuilder<K,V> versionFreeing(boolean enabled);
23 VersionedMapStoreFactoryBuilder<K,V> stateBasedImmutableWhenCommitting(boolean transformToImmutable); 24 VersionedMapStoreFactoryBuilder<K,V> stateBasedImmutableWhenCommitting(boolean transformToImmutable);
24 VersionedMapStoreFactoryBuilder<K,V> stateBasedSharingStrategy(SharingStrategy sharingStrategy); 25 VersionedMapStoreFactoryBuilder<K,V> stateBasedSharingStrategy(SharingStrategy sharingStrategy);
25 VersionedMapStoreFactoryBuilder<K,V> stateBasedHashProvider(ContinuousHashProvider<K> hashProvider); 26 VersionedMapStoreFactoryBuilder<K,V> stateBasedHashProvider(ContinuousHashProvider<K> hashProvider);
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapStoreFactoryBuilderImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapStoreFactoryBuilderImpl.java
index 47470236..9f419ce1 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapStoreFactoryBuilderImpl.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapStoreFactoryBuilderImpl.java
@@ -18,6 +18,7 @@ public class VersionedMapStoreFactoryBuilderImpl<K, V> implements VersionedMapSt
18 private StoreStrategy strategy = null; 18 private StoreStrategy strategy = null;
19 private Boolean transformToImmutable = null; 19 private Boolean transformToImmutable = null;
20 private SharingStrategy sharingStrategy = null; 20 private SharingStrategy sharingStrategy = null;
21 private Boolean enableVersionFreeing = null;
21 private ContinuousHashProvider<K> continuousHashProvider = null; 22 private ContinuousHashProvider<K> continuousHashProvider = null;
22 private DeltaTransactionStrategy deltaTransactionStrategy = null; 23 private DeltaTransactionStrategy deltaTransactionStrategy = null;
23 24
@@ -65,6 +66,13 @@ public class VersionedMapStoreFactoryBuilderImpl<K, V> implements VersionedMapSt
65 } 66 }
66 67
67 @Override 68 @Override
69 public VersionedMapStoreFactoryBuilder<K, V> versionFreeing(boolean enabled) {
70 this.enableVersionFreeing = enabled;
71 checkStrategy();
72 return this;
73 }
74
75 @Override
68 public VersionedMapStoreFactoryBuilder<K, V> stateBasedImmutableWhenCommitting(boolean transformToImmutable) { 76 public VersionedMapStoreFactoryBuilder<K, V> stateBasedImmutableWhenCommitting(boolean transformToImmutable) {
69 this.transformToImmutable = transformToImmutable; 77 this.transformToImmutable = transformToImmutable;
70 checkStrategy(); 78 checkStrategy();
@@ -118,6 +126,7 @@ public class VersionedMapStoreFactoryBuilderImpl<K, V> implements VersionedMapSt
118 yield new StateBasedVersionedMapStoreFactory<>(defaultValue, 126 yield new StateBasedVersionedMapStoreFactory<>(defaultValue,
119 getOrDefault(transformToImmutable,true), 127 getOrDefault(transformToImmutable,true),
120 getOrDefault(sharingStrategy, SharingStrategy.SHARED_NODE_CACHE_IN_GROUP), 128 getOrDefault(sharingStrategy, SharingStrategy.SHARED_NODE_CACHE_IN_GROUP),
129 getOrDefault(enableVersionFreeing, true),
121 continuousHashProvider); 130 continuousHashProvider);
122 } 131 }
123 case DELTA -> new DeltaBasedVersionedMapStoreFactory<>(defaultValue, 132 case DELTA -> new DeltaBasedVersionedMapStoreFactory<>(defaultValue,
@@ -127,13 +136,15 @@ public class VersionedMapStoreFactoryBuilderImpl<K, V> implements VersionedMapSt
127 136
128 @Override 137 @Override
129 public String toString() { 138 public String toString() {
130 return "VersionedMapStoreBuilder{" + 139 return "VersionedMapStoreFactoryBuilderImpl{" +
131 "defaultValue=" + defaultValue + 140 "defaultSet=" + defaultSet +
141 ", defaultValue=" + defaultValue +
132 ", strategy=" + strategy + 142 ", strategy=" + strategy +
133 ", stateBasedImmutableWhenCommitting=" + transformToImmutable + 143 ", transformToImmutable=" + transformToImmutable +
134 ", stateBasedNodeSharingStrategy=" + sharingStrategy + 144 ", sharingStrategy=" + sharingStrategy +
135 ", hashProvider=" + continuousHashProvider + 145 ", enableVersionFreeing=" + enableVersionFreeing +
136 ", deltaStorageStrategy=" + deltaTransactionStrategy + 146 ", continuousHashProvider=" + continuousHashProvider +
147 ", deltaTransactionStrategy=" + deltaTransactionStrategy +
137 '}'; 148 '}';
138 } 149 }
139} 150}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/delta/MapTransaction.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/delta/MapTransaction.java
index 7f9ccd7f..6f3fa6d7 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/delta/MapTransaction.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/delta/MapTransaction.java
@@ -5,17 +5,19 @@
5 */ 5 */
6package tools.refinery.store.map.internal.delta; 6package tools.refinery.store.map.internal.delta;
7 7
8import tools.refinery.store.map.Version;
9
8import java.util.Arrays; 10import java.util.Arrays;
9import java.util.Objects; 11import java.util.Objects;
10 12
11public record MapTransaction<K, V>(MapDelta<K, V>[] deltas, long version, MapTransaction<K, V> parent) { 13public record MapTransaction<K, V>(MapDelta<K, V>[] deltas, MapTransaction<K, V> parent, int depth) implements Version {
12 14
13 @Override 15 @Override
14 public int hashCode() { 16 public int hashCode() {
15 final int prime = 31; 17 final int prime = 31;
16 int result = 1; 18 int result = 1;
17 result = prime * result + Arrays.hashCode(deltas); 19 result = prime * result + Arrays.hashCode(deltas);
18 result = prime * result + Objects.hash(parent, version); 20 result = prime * result + Objects.hash(parent, depth);
19 return result; 21 return result;
20 } 22 }
21 23
@@ -29,11 +31,11 @@ public record MapTransaction<K, V>(MapDelta<K, V>[] deltas, long version, MapTra
29 return false; 31 return false;
30 @SuppressWarnings("unchecked") 32 @SuppressWarnings("unchecked")
31 MapTransaction<K, V> other = (MapTransaction<K, V>) obj; 33 MapTransaction<K, V> other = (MapTransaction<K, V>) obj;
32 return Arrays.equals(deltas, other.deltas) && Objects.equals(parent, other.parent) && version == other.version; 34 return depth == other.depth && Objects.equals(parent, other.parent) && Arrays.equals(deltas, other.deltas);
33 } 35 }
34 36
35 @Override 37 @Override
36 public String toString() { 38 public String toString() {
37 return "MapTransaction " + version + " " + Arrays.toString(deltas); 39 return "MapTransaction " + depth + " " + Arrays.toString(deltas);
38 } 40 }
39} 41}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/delta/VersionedMapDeltaImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/delta/VersionedMapDeltaImpl.java
index 5bb864ac..c19cc817 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/delta/VersionedMapDeltaImpl.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/delta/VersionedMapDeltaImpl.java
@@ -38,15 +38,15 @@ public class VersionedMapDeltaImpl<K, V> implements VersionedMap<K, V> {
38 } 38 }
39 39
40 @Override 40 @Override
41 public long commit() { 41 public Version commit() {
42 MapDelta<K, V>[] deltas = uncommittedStore.extractAndDeleteDeltas(); 42 MapDelta<K, V>[] deltas = uncommittedStore.extractAndDeleteDeltas();
43 long[] versionContainer = new long[1]; 43 final MapTransaction<K,V> committedTransaction = this.store.appendTransaction(deltas, previous);
44 this.previous = this.store.appendTransaction(deltas, previous, versionContainer); 44 this.previous = committedTransaction;
45 return versionContainer[0]; 45 return committedTransaction;
46 } 46 }
47 47
48 @Override 48 @Override
49 public void restore(long state) { 49 public void restore(Version state) {
50 // 1. restore uncommitted states 50 // 1. restore uncommitted states
51 MapDelta<K, V>[] uncommitted = this.uncommittedStore.extractAndDeleteDeltas(); 51 MapDelta<K, V>[] uncommitted = this.uncommittedStore.extractAndDeleteDeltas();
52 if (uncommitted != null) { 52 if (uncommitted != null) {
@@ -61,7 +61,7 @@ public class VersionedMapDeltaImpl<K, V> implements VersionedMap<K, V> {
61 this.forward(forward); 61 this.forward(forward);
62 } else { 62 } else {
63 List<MapDelta<K, V>[]> backward = new ArrayList<>(); 63 List<MapDelta<K, V>[]> backward = new ArrayList<>();
64 parent = this.store.getPath(this.previous.version(), state, backward, forward); 64 parent = this.store.getPath(this.previous, state, backward, forward);
65 this.backward(backward); 65 this.backward(backward);
66 this.forward(forward); 66 this.forward(forward);
67 } 67 }
@@ -75,12 +75,16 @@ public class VersionedMapDeltaImpl<K, V> implements VersionedMap<K, V> {
75 } 75 }
76 76
77 protected void backward(List<MapDelta<K, V>[]> changes) { 77 protected void backward(List<MapDelta<K, V>[]> changes) {
78 //Currently, this loop statement is faster.
79 //noinspection ForLoopReplaceableByForEach
78 for (int i = 0; i < changes.size(); i++) { 80 for (int i = 0; i < changes.size(); i++) {
79 backward(changes.get(i)); 81 backward(changes.get(i));
80 } 82 }
81 } 83 }
82 84
83 protected void forward(MapDelta<K, V>[] changes) { 85 protected void forward(MapDelta<K, V>[] changes) {
86 //Currently, this loop statement is faster.
87 //noinspection ForLoopReplaceableByForEach
84 for (int i = 0; i < changes.length; i++) { 88 for (int i = 0; i < changes.length; i++) {
85 final MapDelta<K, V> change = changes[i]; 89 final MapDelta<K, V> change = changes[i];
86 K key = change.getKey(); 90 K key = change.getKey();
@@ -168,7 +172,7 @@ public class VersionedMapDeltaImpl<K, V> implements VersionedMap<K, V> {
168 } 172 }
169 173
170 @Override 174 @Override
171 public DiffCursor<K, V> getDiffCursor(long state) { 175 public DiffCursor<K, V> getDiffCursor(Version state) {
172 MapDelta<K, V>[] backward = this.uncommittedStore.extractDeltas(); 176 MapDelta<K, V>[] backward = this.uncommittedStore.extractDeltas();
173 List<MapDelta<K, V>[]> backwardTransactions = new ArrayList<>(); 177 List<MapDelta<K, V>[]> backwardTransactions = new ArrayList<>();
174 List<MapDelta<K, V>[]> forwardTransactions = new ArrayList<>(); 178 List<MapDelta<K, V>[]> forwardTransactions = new ArrayList<>();
@@ -178,7 +182,7 @@ public class VersionedMapDeltaImpl<K, V> implements VersionedMap<K, V> {
178 } 182 }
179 183
180 if (this.previous != null) { 184 if (this.previous != null) {
181 store.getPath(this.previous.version(), state, backwardTransactions, forwardTransactions); 185 store.getPath(this.previous, state, backwardTransactions, forwardTransactions);
182 } else { 186 } else {
183 store.getPath(state, forwardTransactions); 187 store.getPath(state, forwardTransactions);
184 } 188 }
@@ -216,5 +220,19 @@ public class VersionedMapDeltaImpl<K, V> implements VersionedMap<K, V> {
216 throw new IllegalStateException("null value stored in map!"); 220 throw new IllegalStateException("null value stored in map!");
217 } 221 }
218 } 222 }
223 MapTransaction<K,V> transaction = this.previous;
224 while(transaction != null) {
225 MapTransaction<K,V> parent = transaction.parent();
226 if(parent != null) {
227 if(parent.depth() != transaction.depth()-1) {
228 throw new IllegalStateException("Parent depths are inconsistent!");
229 }
230 } else {
231 if(transaction.depth() != 0) {
232 throw new IllegalArgumentException("Root depth is not 0!");
233 }
234 }
235 transaction = transaction.parent();
236 }
219 } 237 }
220} 238}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/delta/VersionedMapStoreDeltaImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/delta/VersionedMapStoreDeltaImpl.java
index 7f56ea77..ed169409 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/delta/VersionedMapStoreDeltaImpl.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/delta/VersionedMapStoreDeltaImpl.java
@@ -6,6 +6,7 @@
6package tools.refinery.store.map.internal.delta; 6package tools.refinery.store.map.internal.delta;
7 7
8import tools.refinery.store.map.DiffCursor; 8import tools.refinery.store.map.DiffCursor;
9import tools.refinery.store.map.Version;
9import tools.refinery.store.map.VersionedMap; 10import tools.refinery.store.map.VersionedMap;
10import tools.refinery.store.map.VersionedMapStore; 11import tools.refinery.store.map.VersionedMapStore;
11 12
@@ -18,10 +19,6 @@ public class VersionedMapStoreDeltaImpl<K, V> implements VersionedMapStore<K, V>
18 // Static data 19 // Static data
19 protected final V defaultValue; 20 protected final V defaultValue;
20 21
21 // Dynamic data
22 protected final Map<Long, MapTransaction<K, V>> states = new HashMap<>();
23 protected long nextID = 0;
24
25 public VersionedMapStoreDeltaImpl(boolean summarizeChanges, V defaultValue) { 22 public VersionedMapStoreDeltaImpl(boolean summarizeChanges, V defaultValue) {
26 this.summarizeChanges = summarizeChanges; 23 this.summarizeChanges = summarizeChanges;
27 this.defaultValue = defaultValue; 24 this.defaultValue = defaultValue;
@@ -33,30 +30,32 @@ public class VersionedMapStoreDeltaImpl<K, V> implements VersionedMapStore<K, V>
33 } 30 }
34 31
35 @Override 32 @Override
36 public VersionedMap<K, V> createMap(long state) { 33 public VersionedMap<K, V> createMap(Version state) {
37 VersionedMapDeltaImpl<K, V> result = new VersionedMapDeltaImpl<>(this, this.summarizeChanges, this.defaultValue); 34 VersionedMapDeltaImpl<K, V> result = new VersionedMapDeltaImpl<>(this, this.summarizeChanges, this.defaultValue);
38 result.restore(state); 35 result.restore(state);
39 return result; 36 return result;
40 } 37 }
41 38
42 public synchronized MapTransaction<K, V> appendTransaction(MapDelta<K, V>[] deltas, MapTransaction<K, V> previous, long[] versionContainer) { 39 public MapTransaction<K, V> appendTransaction(MapDelta<K, V>[] deltas, MapTransaction<K, V> previous) {
43 long version = nextID++;
44 versionContainer[0] = version;
45 if (deltas == null) { 40 if (deltas == null) {
46 states.put(version, previous);
47 return previous; 41 return previous;
48 } else { 42 } else {
49 MapTransaction<K, V> transaction = new MapTransaction<>(deltas, version, previous); 43 final int depth;
50 states.put(version, transaction); 44 if(previous != null) {
51 return transaction; 45 depth = previous.depth()+1;
46 } else {
47 depth = 0;
48 }
49 return new MapTransaction<>(deltas, previous, depth);
52 } 50 }
53 } 51 }
54 52
55 private synchronized MapTransaction<K, V> getState(long state) { 53 @SuppressWarnings("unchecked")
56 return states.get(state); 54 private MapTransaction<K, V> getState(Version state) {
55 return (MapTransaction<K, V>) state;
57 } 56 }
58 57
59 public MapTransaction<K, V> getPath(long to, List<MapDelta<K, V>[]> forwardTransactions) { 58 public MapTransaction<K, V> getPath(Version to, List<MapDelta<K, V>[]> forwardTransactions) {
60 final MapTransaction<K, V> target = getState(to); 59 final MapTransaction<K, V> target = getState(to);
61 MapTransaction<K, V> toTransaction = target; 60 MapTransaction<K, V> toTransaction = target;
62 while (toTransaction != null) { 61 while (toTransaction != null) {
@@ -66,7 +65,7 @@ public class VersionedMapStoreDeltaImpl<K, V> implements VersionedMapStore<K, V>
66 return target; 65 return target;
67 } 66 }
68 67
69 public MapTransaction<K, V> getPath(long from, long to, 68 public MapTransaction<K, V> getPath(Version from, Version to,
70 List<MapDelta<K, V>[]> backwardTransactions, 69 List<MapDelta<K, V>[]> backwardTransactions,
71 List<MapDelta<K, V>[]> forwardTransactions) { 70 List<MapDelta<K, V>[]> forwardTransactions) {
72 MapTransaction<K, V> fromTransaction = getState(from); 71 MapTransaction<K, V> fromTransaction = getState(from);
@@ -74,7 +73,7 @@ public class VersionedMapStoreDeltaImpl<K, V> implements VersionedMapStore<K, V>
74 MapTransaction<K, V> toTransaction = target; 73 MapTransaction<K, V> toTransaction = target;
75 74
76 while (fromTransaction != toTransaction) { 75 while (fromTransaction != toTransaction) {
77 if (fromTransaction == null || (toTransaction != null && fromTransaction.version() < toTransaction.version())) { 76 if (fromTransaction == null || (toTransaction != null && fromTransaction.depth() < toTransaction.depth())) {
78 forwardTransactions.add(toTransaction.deltas()); 77 forwardTransactions.add(toTransaction.deltas());
79 toTransaction = toTransaction.parent(); 78 toTransaction = toTransaction.parent();
80 } else { 79 } else {
@@ -85,14 +84,8 @@ public class VersionedMapStoreDeltaImpl<K, V> implements VersionedMapStore<K, V>
85 return target; 84 return target;
86 } 85 }
87 86
88
89 @Override
90 public synchronized Set<Long> getStates() {
91 return new HashSet<>(states.keySet());
92 }
93
94 @Override 87 @Override
95 public DiffCursor<K, V> getDiffCursor(long fromState, long toState) { 88 public DiffCursor<K, V> getDiffCursor(Version fromState, Version toState) {
96 List<MapDelta<K, V>[]> backwardTransactions = new ArrayList<>(); 89 List<MapDelta<K, V>[]> backwardTransactions = new ArrayList<>();
97 List<MapDelta<K, V>[]> forwardTransactions = new ArrayList<>(); 90 List<MapDelta<K, V>[]> forwardTransactions = new ArrayList<>();
98 getPath(fromState, toState, backwardTransactions, forwardTransactions); 91 getPath(fromState, toState, backwardTransactions, forwardTransactions);
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/state/ImmutableNode.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/state/ImmutableNode.java
index 722f9ed7..5b1d8b77 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/state/ImmutableNode.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/state/ImmutableNode.java
@@ -9,8 +9,9 @@ import java.util.Arrays;
9import java.util.Map; 9import java.util.Map;
10 10
11import tools.refinery.store.map.ContinuousHashProvider; 11import tools.refinery.store.map.ContinuousHashProvider;
12import tools.refinery.store.map.Version;
12 13
13public class ImmutableNode<K, V> extends Node<K, V> { 14public class ImmutableNode<K, V> extends Node<K, V> implements Version {
14 /** 15 /**
15 * Bitmap defining the stored key and values. 16 * Bitmap defining the stored key and values.
16 */ 17 */
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/state/StateBasedVersionedMapStoreFactory.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/state/StateBasedVersionedMapStoreFactory.java
index 9409ace0..ccc791a8 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/state/StateBasedVersionedMapStoreFactory.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/state/StateBasedVersionedMapStoreFactory.java
@@ -14,14 +14,19 @@ public class StateBasedVersionedMapStoreFactory<K, V> implements VersionedMapSto
14 private final ContinuousHashProvider<K> continuousHashProvider; 14 private final ContinuousHashProvider<K> continuousHashProvider;
15 private final VersionedMapStoreStateConfiguration config; 15 private final VersionedMapStoreStateConfiguration config;
16 16
17 public StateBasedVersionedMapStoreFactory(V defaultValue, Boolean transformToImmutable, VersionedMapStoreFactoryBuilder.SharingStrategy sharingStrategy, ContinuousHashProvider<K> continuousHashProvider) { 17 public StateBasedVersionedMapStoreFactory(V defaultValue, Boolean transformToImmutable,
18 VersionedMapStoreFactoryBuilder.SharingStrategy sharingStrategy,
19 boolean versionFreeingEnabled,
20 ContinuousHashProvider<K> continuousHashProvider) {
18 this.defaultValue = defaultValue; 21 this.defaultValue = defaultValue;
19 this.continuousHashProvider = continuousHashProvider; 22 this.continuousHashProvider = continuousHashProvider;
20 23
21 this.config = new VersionedMapStoreStateConfiguration( 24 this.config = new VersionedMapStoreStateConfiguration(
22 transformToImmutable, 25 transformToImmutable,
23 sharingStrategy == VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE || sharingStrategy == VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE_IN_GROUP, 26 sharingStrategy == VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE
24 sharingStrategy == VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE_IN_GROUP); 27 || sharingStrategy == VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE_IN_GROUP,
28 sharingStrategy == VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE_IN_GROUP,
29 versionFreeingEnabled);
25 } 30 }
26 31
27 @Override 32 @Override
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/state/VersionedMapStateImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/state/VersionedMapStateImpl.java
index 817fc70b..57eeccf6 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/state/VersionedMapStateImpl.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/state/VersionedMapStateImpl.java
@@ -115,7 +115,7 @@ public class VersionedMapStateImpl<K, V> implements VersionedMap<K, V> {
115 } 115 }
116 116
117 @Override 117 @Override
118 public DiffCursor<K, V> getDiffCursor(long toVersion) { 118 public DiffCursor<K, V> getDiffCursor(Version toVersion) {
119 InOrderMapCursor<K, V> fromCursor = new InOrderMapCursor<>(this); 119 InOrderMapCursor<K, V> fromCursor = new InOrderMapCursor<>(this);
120 VersionedMapStateImpl<K, V> toMap = (VersionedMapStateImpl<K, V>) this.store.createMap(toVersion); 120 VersionedMapStateImpl<K, V> toMap = (VersionedMapStateImpl<K, V>) this.store.createMap(toVersion);
121 InOrderMapCursor<K, V> toCursor = new InOrderMapCursor<>(toMap); 121 InOrderMapCursor<K, V> toCursor = new InOrderMapCursor<>(toMap);
@@ -124,7 +124,7 @@ public class VersionedMapStateImpl<K, V> implements VersionedMap<K, V> {
124 124
125 125
126 @Override 126 @Override
127 public long commit() { 127 public Version commit() {
128 return this.store.commit(root, this); 128 return this.store.commit(root, this);
129 } 129 }
130 130
@@ -133,7 +133,7 @@ public class VersionedMapStateImpl<K, V> implements VersionedMap<K, V> {
133 } 133 }
134 134
135 @Override 135 @Override
136 public void restore(long state) { 136 public void restore(Version state) {
137 root = this.store.revert(state); 137 root = this.store.revert(state);
138 } 138 }
139 139
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/state/VersionedMapStoreStateConfiguration.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/state/VersionedMapStoreStateConfiguration.java
index 45f30cc7..6650f565 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/state/VersionedMapStoreStateConfiguration.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/state/VersionedMapStoreStateConfiguration.java
@@ -14,11 +14,12 @@ public class VersionedMapStoreStateConfiguration {
14 14
15 } 15 }
16 public VersionedMapStoreStateConfiguration(boolean immutableWhenCommitting, boolean sharedNodeCacheInStore, 16 public VersionedMapStoreStateConfiguration(boolean immutableWhenCommitting, boolean sharedNodeCacheInStore,
17 boolean sharedNodeCacheInStoreGroups) { 17 boolean sharedNodeCacheInStoreGroups, boolean versionFreeingEnabled) {
18 super(); 18 super();
19 this.immutableWhenCommitting = immutableWhenCommitting; 19 this.immutableWhenCommitting = immutableWhenCommitting;
20 this.sharedNodeCacheInStore = sharedNodeCacheInStore; 20 this.sharedNodeCacheInStore = sharedNodeCacheInStore;
21 this.sharedNodeCacheInStoreGroups = sharedNodeCacheInStoreGroups; 21 this.sharedNodeCacheInStoreGroups = sharedNodeCacheInStoreGroups;
22 this.versionFreeingEnabled = versionFreeingEnabled;
22 } 23 }
23 24
24 /** 25 /**
@@ -53,4 +54,9 @@ public class VersionedMapStoreStateConfiguration {
53 public boolean isSharedNodeCacheInStoreGroups() { 54 public boolean isSharedNodeCacheInStoreGroups() {
54 return sharedNodeCacheInStoreGroups; 55 return sharedNodeCacheInStoreGroups;
55 } 56 }
57
58 private boolean versionFreeingEnabled = true;
59 public boolean isVersionFreeingEnabled() {
60 return versionFreeingEnabled;
61 }
56} 62}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/state/VersionedMapStoreStateImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/state/VersionedMapStoreStateImpl.java
index 0651772a..8ff3f8e7 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/state/VersionedMapStoreStateImpl.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/state/VersionedMapStoreStateImpl.java
@@ -17,10 +17,7 @@ public class VersionedMapStoreStateImpl<K, V> implements VersionedMapStore<K, V>
17 protected final ContinuousHashProvider<K> hashProvider; 17 protected final ContinuousHashProvider<K> hashProvider;
18 protected final V defaultValue; 18 protected final V defaultValue;
19 19
20 // Dynamic data
21 protected final Map<Long, ImmutableNode<K, V>> states = new HashMap<>();
22 protected final Map<Node<K, V>, ImmutableNode<K, V>> nodeCache; 20 protected final Map<Node<K, V>, ImmutableNode<K, V>> nodeCache;
23 protected long nextID = 0;
24 21
25 public VersionedMapStoreStateImpl(ContinuousHashProvider<K> hashProvider, V defaultValue, 22 public VersionedMapStoreStateImpl(ContinuousHashProvider<K> hashProvider, V defaultValue,
26 VersionedMapStoreStateConfiguration config) { 23 VersionedMapStoreStateConfiguration config) {
@@ -28,7 +25,7 @@ public class VersionedMapStoreStateImpl<K, V> implements VersionedMapStore<K, V>
28 this.hashProvider = hashProvider; 25 this.hashProvider = hashProvider;
29 this.defaultValue = defaultValue; 26 this.defaultValue = defaultValue;
30 if (config.isSharedNodeCacheInStore()) { 27 if (config.isSharedNodeCacheInStore()) {
31 nodeCache = new HashMap<>(); 28 nodeCache = createNoteCache(config);
32 } else { 29 } else {
33 nodeCache = null; 30 nodeCache = null;
34 } 31 }
@@ -53,7 +50,7 @@ public class VersionedMapStoreStateImpl<K, V> implements VersionedMapStore<K, V>
53 if (config.isSharedNodeCacheInStoreGroups()) { 50 if (config.isSharedNodeCacheInStoreGroups()) {
54 Map<Node<K, V>, ImmutableNode<K, V>> nodeCache; 51 Map<Node<K, V>, ImmutableNode<K, V>> nodeCache;
55 if (config.isSharedNodeCacheInStore()) { 52 if (config.isSharedNodeCacheInStore()) {
56 nodeCache = new HashMap<>(); 53 nodeCache = createNoteCache(config);
57 } else { 54 } else {
58 nodeCache = null; 55 nodeCache = null;
59 } 56 }
@@ -68,39 +65,36 @@ public class VersionedMapStoreStateImpl<K, V> implements VersionedMapStore<K, V>
68 return result; 65 return result;
69 } 66 }
70 67
68 private static <K,V> Map<K,V> createNoteCache(VersionedMapStoreStateConfiguration config) {
69 if(config.isVersionFreeingEnabled()) {
70 return new WeakHashMap<>();
71 } else {
72 return new HashMap<>();
73 }
74 }
75
71 public static <K, V> List<VersionedMapStore<K, V>> createSharedVersionedMapStores(int amount, 76 public static <K, V> List<VersionedMapStore<K, V>> createSharedVersionedMapStores(int amount,
72 ContinuousHashProvider<K> hashProvider, V defaultValue) { 77 ContinuousHashProvider<K> hashProvider, V defaultValue) {
73 return createSharedVersionedMapStores(amount, hashProvider, defaultValue, new VersionedMapStoreStateConfiguration()); 78 return createSharedVersionedMapStores(amount, hashProvider, defaultValue, new VersionedMapStoreStateConfiguration());
74 } 79 }
75 80
76 @Override 81 @Override
77 public synchronized Set<Long> getStates() {
78 return new HashSet<>(states.keySet());
79 }
80
81 @Override
82 public VersionedMap<K, V> createMap() { 82 public VersionedMap<K, V> createMap() {
83 return new VersionedMapStateImpl<>(this, hashProvider, defaultValue); 83 return new VersionedMapStateImpl<>(this, hashProvider, defaultValue);
84 } 84 }
85 85
86 @Override 86 @Override
87 public VersionedMap<K, V> createMap(long state) { 87 public VersionedMap<K, V> createMap(Version state) {
88 ImmutableNode<K, V> data = revert(state); 88 ImmutableNode<K, V> data = revert(state);
89 return new VersionedMapStateImpl<>(this, hashProvider, defaultValue, data); 89 return new VersionedMapStateImpl<>(this, hashProvider, defaultValue, data);
90 } 90 }
91 91
92 public synchronized ImmutableNode<K, V> revert(long state) { 92 @SuppressWarnings("unchecked")
93 if (states.containsKey(state)) { 93 public synchronized ImmutableNode<K, V> revert(Version state) {
94 return states.get(state); 94 return (ImmutableNode<K, V>) state;
95 } else {
96 ArrayList<Long> existingKeys = new ArrayList<>(states.keySet());
97 Collections.sort(existingKeys);
98 throw new IllegalArgumentException("Store does not contain state " + state + "! Available states: "
99 + Arrays.toString(existingKeys.toArray()));
100 }
101 } 95 }
102 96
103 public synchronized long commit(Node<K, V> data, VersionedMapStateImpl<K, V> mapToUpdateRoot) { 97 public synchronized Version commit(Node<K, V> data, VersionedMapStateImpl<K, V> mapToUpdateRoot) {
104 ImmutableNode<K, V> immutable; 98 ImmutableNode<K, V> immutable;
105 if (data != null) { 99 if (data != null) {
106 immutable = data.toImmutable(this.nodeCache); 100 immutable = data.toImmutable(this.nodeCache);
@@ -108,18 +102,14 @@ public class VersionedMapStoreStateImpl<K, V> implements VersionedMapStore<K, V>
108 immutable = null; 102 immutable = null;
109 } 103 }
110 104
111 if (nextID == Long.MAX_VALUE)
112 throw new IllegalStateException("Map store run out of Id-s");
113 long id = nextID++;
114 this.states.put(id, immutable);
115 if (this.immutableWhenCommitting) { 105 if (this.immutableWhenCommitting) {
116 mapToUpdateRoot.setRoot(immutable); 106 mapToUpdateRoot.setRoot(immutable);
117 } 107 }
118 return id; 108 return immutable;
119 } 109 }
120 110
121 @Override 111 @Override
122 public DiffCursor<K, V> getDiffCursor(long fromState, long toState) { 112 public DiffCursor<K, V> getDiffCursor(Version fromState, Version toState) {
123 VersionedMapStateImpl<K, V> map1 = (VersionedMapStateImpl<K, V>) createMap(fromState); 113 VersionedMapStateImpl<K, V> map1 = (VersionedMapStateImpl<K, V>) createMap(fromState);
124 VersionedMapStateImpl<K, V> map2 = (VersionedMapStateImpl<K, V>) createMap(toState); 114 VersionedMapStateImpl<K, V> map2 = (VersionedMapStateImpl<K, V>) createMap(toState);
125 InOrderMapCursor<K, V> cursor1 = new InOrderMapCursor<>(map1); 115 InOrderMapCursor<K, V> cursor1 = new InOrderMapCursor<>(map1);
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/Interpretation.java b/subprojects/store/src/main/java/tools/refinery/store/model/Interpretation.java
index 26ad9a69..72f188d3 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/Interpretation.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/Interpretation.java
@@ -7,6 +7,7 @@ package tools.refinery.store.model;
7 7
8import tools.refinery.store.map.Cursor; 8import tools.refinery.store.map.Cursor;
9import tools.refinery.store.map.DiffCursor; 9import tools.refinery.store.map.DiffCursor;
10import tools.refinery.store.map.Version;
10import tools.refinery.store.representation.Symbol; 11import tools.refinery.store.representation.Symbol;
11import tools.refinery.store.tuple.Tuple; 12import tools.refinery.store.tuple.Tuple;
12 13
@@ -22,7 +23,7 @@ public non-sealed interface Interpretation<T> extends AnyInterpretation {
22 23
23 void putAll(Cursor<Tuple, T> cursor); 24 void putAll(Cursor<Tuple, T> cursor);
24 25
25 DiffCursor<Tuple, T> getDiffCursor(long to); 26 DiffCursor<Tuple, T> getDiffCursor(Version to);
26 27
27 void addListener(InterpretationListener<T> listener, boolean alsoWhenRestoring); 28 void addListener(InterpretationListener<T> listener, boolean alsoWhenRestoring);
28 29
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/Model.java b/subprojects/store/src/main/java/tools/refinery/store/model/Model.java
index d58d91c3..a028b81b 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/Model.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/Model.java
@@ -6,6 +6,7 @@
6package tools.refinery.store.model; 6package tools.refinery.store.model;
7 7
8import tools.refinery.store.adapter.ModelAdapter; 8import tools.refinery.store.adapter.ModelAdapter;
9import tools.refinery.store.map.Version;
9import tools.refinery.store.map.Versioned; 10import tools.refinery.store.map.Versioned;
10import tools.refinery.store.representation.AnySymbol; 11import tools.refinery.store.representation.AnySymbol;
11import tools.refinery.store.representation.Symbol; 12import tools.refinery.store.representation.Symbol;
@@ -13,11 +14,10 @@ import tools.refinery.store.representation.Symbol;
13import java.util.Optional; 14import java.util.Optional;
14 15
15public interface Model extends Versioned { 16public interface Model extends Versioned {
16 long NO_STATE_ID = -1; 17 Version NO_STATE_ID = null;
17
18 ModelStore getStore(); 18 ModelStore getStore();
19 19
20 long getState(); 20 Version getState();
21 21
22 boolean hasUncommittedChanges(); 22 boolean hasUncommittedChanges();
23 23
@@ -27,7 +27,7 @@ public interface Model extends Versioned {
27 27
28 <T> Interpretation<T> getInterpretation(Symbol<T> symbol); 28 <T> Interpretation<T> getInterpretation(Symbol<T> symbol);
29 29
30 ModelDiffCursor getDiffCursor(long to); 30 ModelDiffCursor getDiffCursor(Version to);
31 31
32 <T extends ModelAdapter> Optional<T> tryGetAdapter(Class<? extends T> adapterType); 32 <T extends ModelAdapter> Optional<T> tryGetAdapter(Class<? extends T> adapterType);
33 33
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/ModelListener.java b/subprojects/store/src/main/java/tools/refinery/store/model/ModelListener.java
index a9ad8cfd..703ee10a 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/ModelListener.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/ModelListener.java
@@ -5,6 +5,8 @@
5 */ 5 */
6package tools.refinery.store.model; 6package tools.refinery.store.model;
7 7
8import tools.refinery.store.map.Version;
9
8public interface ModelListener { 10public interface ModelListener {
9 default void beforeCommit() { 11 default void beforeCommit() {
10 } 12 }
@@ -12,7 +14,7 @@ public interface ModelListener {
12 default void afterCommit() { 14 default void afterCommit() {
13 } 15 }
14 16
15 default void beforeRestore(long state) { 17 default void beforeRestore(Version state) {
16 } 18 }
17 19
18 default void afterRestore() { 20 default void afterRestore() {
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java
index b10eb8a4..89382b3a 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java
@@ -6,23 +6,21 @@
6package tools.refinery.store.model; 6package tools.refinery.store.model;
7 7
8import tools.refinery.store.adapter.ModelStoreAdapter; 8import tools.refinery.store.adapter.ModelStoreAdapter;
9import tools.refinery.store.map.Version;
9import tools.refinery.store.model.internal.ModelStoreBuilderImpl; 10import tools.refinery.store.model.internal.ModelStoreBuilderImpl;
10import tools.refinery.store.representation.AnySymbol; 11import tools.refinery.store.representation.AnySymbol;
11 12
12import java.util.Collection; 13import java.util.Collection;
13import java.util.Optional; 14import java.util.Optional;
14import java.util.Set;
15 15
16public interface ModelStore { 16public interface ModelStore {
17 Collection<AnySymbol> getSymbols(); 17 Collection<AnySymbol> getSymbols();
18 18
19 Model createEmptyModel(); 19 Model createEmptyModel();
20 20
21 Model createModelForState(long state); 21 Model createModelForState(Version state);
22 22
23 Set<Long> getStates(); 23 ModelDiffCursor getDiffCursor(Version from, Version to);
24
25 ModelDiffCursor getDiffCursor(long from, long to);
26 24
27 <T extends ModelStoreAdapter> Optional<T> tryGetAdapter(Class<? extends T> adapterType); 25 <T extends ModelStoreAdapter> Optional<T> tryGetAdapter(Class<? extends T> adapterType);
28 26
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java
index c5475a1a..c2ad9257 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java
@@ -8,6 +8,7 @@ package tools.refinery.store.model.internal;
8import tools.refinery.store.adapter.AdapterUtils; 8import tools.refinery.store.adapter.AdapterUtils;
9import tools.refinery.store.adapter.ModelAdapter; 9import tools.refinery.store.adapter.ModelAdapter;
10import tools.refinery.store.map.DiffCursor; 10import tools.refinery.store.map.DiffCursor;
11import tools.refinery.store.map.Version;
11import tools.refinery.store.model.*; 12import tools.refinery.store.model.*;
12import tools.refinery.store.representation.AnySymbol; 13import tools.refinery.store.representation.AnySymbol;
13import tools.refinery.store.representation.Symbol; 14import tools.refinery.store.representation.Symbol;
@@ -17,21 +18,21 @@ import java.util.*;
17 18
18public class ModelImpl implements Model { 19public class ModelImpl implements Model {
19 private final ModelStore store; 20 private final ModelStore store;
20 private long state; 21 private Version state;
21 private Map<? extends AnySymbol, ? extends VersionedInterpretation<?>> interpretations; 22 private LinkedHashMap<? extends AnySymbol, ? extends VersionedInterpretation<?>> interpretations;
22 private final List<ModelAdapter> adapters; 23 private final List<ModelAdapter> adapters;
23 private final List<ModelListener> listeners = new ArrayList<>(); 24 private final List<ModelListener> listeners = new ArrayList<>();
24 private boolean uncommittedChanges; 25 private boolean uncommittedChanges;
25 private ModelAction pendingAction = ModelAction.NONE; 26 private ModelAction pendingAction = ModelAction.NONE;
26 private long restoringToState = NO_STATE_ID; 27 private Version restoringToState = null;
27 28
28 ModelImpl(ModelStore store, long state, int adapterCount) { 29 ModelImpl(ModelStore store, Version state, int adapterCount) {
29 this.store = store; 30 this.store = store;
30 this.state = state; 31 this.state = state;
31 adapters = new ArrayList<>(adapterCount); 32 adapters = new ArrayList<>(adapterCount);
32 } 33 }
33 34
34 void setInterpretations(Map<? extends AnySymbol, ? extends VersionedInterpretation<?>> interpretations) { 35 void setInterpretations(LinkedHashMap<? extends AnySymbol, ? extends VersionedInterpretation<?>> interpretations) {
35 this.interpretations = interpretations; 36 this.interpretations = interpretations;
36 } 37 }
37 38
@@ -41,7 +42,7 @@ public class ModelImpl implements Model {
41 } 42 }
42 43
43 @Override 44 @Override
44 public long getState() { 45 public Version getState() {
45 return state; 46 return state;
46 } 47 }
47 48
@@ -57,7 +58,7 @@ public class ModelImpl implements Model {
57 } 58 }
58 59
59 @Override 60 @Override
60 public ModelDiffCursor getDiffCursor(long to) { 61 public ModelDiffCursor getDiffCursor(Version to) {
61 var diffCursors = new HashMap<AnySymbol, DiffCursor<Tuple, ?>>(interpretations.size()); 62 var diffCursors = new HashMap<AnySymbol, DiffCursor<Tuple, ?>>(interpretations.size());
62 for (var entry : interpretations.entrySet()) { 63 for (var entry : interpretations.entrySet()) {
63 diffCursors.put(entry.getKey(), entry.getValue().getDiffCursor(to)); 64 diffCursors.put(entry.getKey(), entry.getValue().getDiffCursor(to));
@@ -65,7 +66,7 @@ public class ModelImpl implements Model {
65 return new ModelDiffCursor(diffCursors); 66 return new ModelDiffCursor(diffCursors);
66 } 67 }
67 68
68 private void setState(long state) { 69 private void setState(Version state) {
69 this.state = state; 70 this.state = state;
70 uncommittedChanges = false; 71 uncommittedChanges = false;
71 } 72 }
@@ -82,11 +83,11 @@ public class ModelImpl implements Model {
82 } 83 }
83 84
84 private boolean hasPendingAction() { 85 private boolean hasPendingAction() {
85 return pendingAction != ModelAction.NONE || restoringToState != NO_STATE_ID; 86 return pendingAction != ModelAction.NONE || restoringToState != null;
86 } 87 }
87 88
88 @Override 89 @Override
89 public long commit() { 90 public Version commit() {
90 if (hasPendingAction()) { 91 if (hasPendingAction()) {
91 throw pendingActionError("commit"); 92 throw pendingActionError("commit");
92 } 93 }
@@ -94,43 +95,40 @@ public class ModelImpl implements Model {
94 try { 95 try {
95 int listenerCount = listeners.size(); 96 int listenerCount = listeners.size();
96 int i = listenerCount; 97 int i = listenerCount;
97 long version = 0; 98
99 // Before commit message to listeners
98 while (i > 0) { 100 while (i > 0) {
99 i--; 101 i--;
100 listeners.get(i).beforeCommit(); 102 listeners.get(i).beforeCommit();
101 } 103 }
102 boolean versionSet = false; 104
103 for (var interpretation : interpretations.values()) { 105 // Doing the commit on the interpretations
104 long newVersion = interpretation.commit(); 106 Version[] interpretationVersions = new Version[interpretations.size()];
105 if (versionSet) { 107 int j = 0;
106 if (version != newVersion) { 108 for(var interpretationEntry : interpretations.entrySet()) {
107 throw new IllegalStateException("Interpretations in model have different versions (%d and %d)" 109 interpretationVersions[j++] = interpretationEntry.getValue().commit();
108 .formatted(version, newVersion));
109 }
110 } else {
111 version = newVersion;
112 versionSet = true;
113 }
114 } 110 }
115 setState(version); 111 ModelVersion modelVersion = new ModelVersion(interpretationVersions);
112 setState(modelVersion);
113
114 // After commit message to listeners
116 while (i < listenerCount) { 115 while (i < listenerCount) {
117 listeners.get(i).afterCommit(); 116 listeners.get(i).afterCommit();
118 i++; 117 i++;
119 } 118 }
120 return version; 119
120 return modelVersion;
121 } finally { 121 } finally {
122 pendingAction = ModelAction.NONE; 122 pendingAction = ModelAction.NONE;
123 } 123 }
124 } 124 }
125 125
126 @Override 126 @Override
127 public void restore(long version) { 127 public void restore(Version version) {
128 if (hasPendingAction()) { 128 if (hasPendingAction()) {
129 throw pendingActionError("restore to %d".formatted(version)); 129 throw pendingActionError("restore to %s".formatted(version));
130 }
131 if (!store.getStates().contains(version)) {
132 throw new IllegalArgumentException("Store does not contain state %d".formatted(version));
133 } 130 }
131
134 pendingAction = ModelAction.RESTORE; 132 pendingAction = ModelAction.RESTORE;
135 restoringToState = version; 133 restoringToState = version;
136 try { 134 try {
@@ -140,9 +138,11 @@ public class ModelImpl implements Model {
140 i--; 138 i--;
141 listeners.get(i).beforeRestore(version); 139 listeners.get(i).beforeRestore(version);
142 } 140 }
141 int j = 0;
143 for (var interpretation : interpretations.values()) { 142 for (var interpretation : interpretations.values()) {
144 interpretation.restore(version); 143 interpretation.restore(ModelVersion.getInternalVersion(version,j++));
145 } 144 }
145
146 setState(version); 146 setState(version);
147 while (i < listenerCount) { 147 while (i < listenerCount) {
148 listeners.get(i).afterRestore(); 148 listeners.get(i).afterRestore();
@@ -150,7 +150,7 @@ public class ModelImpl implements Model {
150 } 150 }
151 } finally { 151 } finally {
152 pendingAction = ModelAction.NONE; 152 pendingAction = ModelAction.NONE;
153 restoringToState = NO_STATE_ID; 153 restoringToState = null;
154 } 154 }
155 } 155 }
156 156
@@ -159,7 +159,7 @@ public class ModelImpl implements Model {
159 case NONE -> throw new IllegalArgumentException("Trying to throw pending action error when there is no " + 159 case NONE -> throw new IllegalArgumentException("Trying to throw pending action error when there is no " +
160 "pending action"); 160 "pending action");
161 case COMMIT -> "commit"; 161 case COMMIT -> "commit";
162 case RESTORE -> "restore to %d".formatted(restoringToState); 162 case RESTORE -> "restore to %s".formatted(restoringToState);
163 }; 163 };
164 return new IllegalStateException("Cannot %s due to pending %s".formatted(currentActionName, pendingActionName)); 164 return new IllegalStateException("Cannot %s due to pending %s".formatted(currentActionName, pendingActionName));
165 } 165 }
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java
index 2cc7b19c..65fa8d24 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java
@@ -19,8 +19,8 @@ import tools.refinery.store.tuple.Tuple;
19import java.util.*; 19import java.util.*;
20 20
21public class ModelStoreBuilderImpl implements ModelStoreBuilder { 21public class ModelStoreBuilderImpl implements ModelStoreBuilder {
22 private final Set<AnySymbol> allSymbols = new HashSet<>(); 22 private final LinkedHashSet<AnySymbol> allSymbols = new LinkedHashSet<>();
23 private final Map<SymbolEquivalenceClass<?>, List<AnySymbol>> equivalenceClasses = new HashMap<>(); 23 private final LinkedHashMap<SymbolEquivalenceClass<?>, List<AnySymbol>> equivalenceClasses = new LinkedHashMap<>();
24 private final List<ModelAdapterBuilder> adapters = new ArrayList<>(); 24 private final List<ModelAdapterBuilder> adapters = new ArrayList<>();
25 25
26 @Override 26 @Override
@@ -59,7 +59,7 @@ public class ModelStoreBuilderImpl implements ModelStoreBuilder {
59 59
60 @Override 60 @Override
61 public ModelStore build() { 61 public ModelStore build() {
62 var stores = new HashMap<AnySymbol, VersionedMapStore<Tuple, ?>>(allSymbols.size()); 62 var stores = new LinkedHashMap<AnySymbol, VersionedMapStore<Tuple, ?>>(allSymbols.size());
63 for (var entry : equivalenceClasses.entrySet()) { 63 for (var entry : equivalenceClasses.entrySet()) {
64 createStores(stores, entry.getKey(), entry.getValue()); 64 createStores(stores, entry.getKey(), entry.getValue());
65 } 65 }
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java
index 60b735e6..a320a618 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java
@@ -8,8 +8,8 @@ package tools.refinery.store.model.internal;
8import tools.refinery.store.adapter.AdapterUtils; 8import tools.refinery.store.adapter.AdapterUtils;
9import tools.refinery.store.adapter.ModelStoreAdapter; 9import tools.refinery.store.adapter.ModelStoreAdapter;
10import tools.refinery.store.map.DiffCursor; 10import tools.refinery.store.map.DiffCursor;
11import tools.refinery.store.map.Version;
11import tools.refinery.store.map.VersionedMapStore; 12import tools.refinery.store.map.VersionedMapStore;
12import tools.refinery.store.model.Model;
13import tools.refinery.store.model.ModelDiffCursor; 13import tools.refinery.store.model.ModelDiffCursor;
14import tools.refinery.store.model.ModelStore; 14import tools.refinery.store.model.ModelStore;
15import tools.refinery.store.representation.AnySymbol; 15import tools.refinery.store.representation.AnySymbol;
@@ -18,10 +18,10 @@ import tools.refinery.store.tuple.Tuple;
18import java.util.*; 18import java.util.*;
19 19
20public class ModelStoreImpl implements ModelStore { 20public class ModelStoreImpl implements ModelStore {
21 private final Map<? extends AnySymbol, ? extends VersionedMapStore<Tuple, ?>> stores; 21 private final LinkedHashMap<? extends AnySymbol, ? extends VersionedMapStore<Tuple, ?>> stores;
22 private final List<ModelStoreAdapter> adapters; 22 private final List<ModelStoreAdapter> adapters;
23 23
24 ModelStoreImpl(Map<? extends AnySymbol, ? extends VersionedMapStore<Tuple, ?>> stores, int adapterCount) { 24 ModelStoreImpl(LinkedHashMap<? extends AnySymbol, ? extends VersionedMapStore<Tuple, ?>> stores, int adapterCount) {
25 this.stores = stores; 25 this.stores = stores;
26 adapters = new ArrayList<>(adapterCount); 26 adapters = new ArrayList<>(adapterCount);
27 } 27 }
@@ -31,14 +31,14 @@ public class ModelStoreImpl implements ModelStore {
31 return Collections.unmodifiableCollection(stores.keySet()); 31 return Collections.unmodifiableCollection(stores.keySet());
32 } 32 }
33 33
34 private ModelImpl createModelWithoutInterpretations(long state) { 34 private ModelImpl createModelWithoutInterpretations(Version state) {
35 return new ModelImpl(this, state, adapters.size()); 35 return new ModelImpl(this, state, adapters.size());
36 } 36 }
37 37
38 @Override 38 @Override
39 public ModelImpl createEmptyModel() { 39 public ModelImpl createEmptyModel() {
40 var model = createModelWithoutInterpretations(Model.NO_STATE_ID); 40 var model = createModelWithoutInterpretations(null);
41 var interpretations = new HashMap<AnySymbol, VersionedInterpretation<?>>(stores.size()); 41 var interpretations = new LinkedHashMap<AnySymbol, VersionedInterpretation<?>>(stores.size());
42 for (var entry : this.stores.entrySet()) { 42 for (var entry : this.stores.entrySet()) {
43 var symbol = entry.getKey(); 43 var symbol = entry.getKey();
44 interpretations.put(symbol, VersionedInterpretation.of(model, symbol, entry.getValue())); 44 interpretations.put(symbol, VersionedInterpretation.of(model, symbol, entry.getValue()));
@@ -49,13 +49,21 @@ public class ModelStoreImpl implements ModelStore {
49 } 49 }
50 50
51 @Override 51 @Override
52 public synchronized ModelImpl createModelForState(long state) { 52 public synchronized ModelImpl createModelForState(Version state) {
53 var model = createModelWithoutInterpretations(state); 53 var model = createModelWithoutInterpretations(state);
54 var interpretations = new HashMap<AnySymbol, VersionedInterpretation<?>>(stores.size()); 54 var interpretations = new LinkedHashMap<AnySymbol, VersionedInterpretation<?>>(stores.size());
55
56 int i=0;
55 for (var entry : this.stores.entrySet()) { 57 for (var entry : this.stores.entrySet()) {
56 var symbol = entry.getKey(); 58 var symbol = entry.getKey();
57 interpretations.put(symbol, VersionedInterpretation.of(model, symbol, entry.getValue(), state)); 59 interpretations.put(symbol,
60 VersionedInterpretation.of(
61 model,
62 symbol,
63 entry.getValue(),
64 ModelVersion.getInternalVersion(state,i++)));
58 } 65 }
66
59 model.setInterpretations(interpretations); 67 model.setInterpretations(interpretations);
60 adaptModel(model); 68 adaptModel(model);
61 return model; 69 return model;
@@ -69,16 +77,7 @@ public class ModelStoreImpl implements ModelStore {
69 } 77 }
70 78
71 @Override 79 @Override
72 public synchronized Set<Long> getStates() { 80 public synchronized ModelDiffCursor getDiffCursor(Version from, Version to) {
73 var iterator = stores.values().iterator();
74 if (iterator.hasNext()) {
75 return Set.copyOf(iterator.next().getStates());
76 }
77 return Set.of(0L);
78 }
79
80 @Override
81 public synchronized ModelDiffCursor getDiffCursor(long from, long to) {
82 var diffCursors = new HashMap<AnySymbol, DiffCursor<?, ?>>(); 81 var diffCursors = new HashMap<AnySymbol, DiffCursor<?, ?>>();
83 for (var entry : stores.entrySet()) { 82 for (var entry : stores.entrySet()) {
84 var representation = entry.getKey(); 83 var representation = entry.getKey();
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelVersion.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelVersion.java
new file mode 100644
index 00000000..cf3b7fc6
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelVersion.java
@@ -0,0 +1,39 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.model.internal;
7
8import tools.refinery.store.map.Version;
9
10import java.util.Arrays;
11
12public record ModelVersion(Version[] mapVersions) implements Version{
13
14 public static Version getInternalVersion(Version modelVersion, int interpretationIndex) {
15 return ((ModelVersion)modelVersion).mapVersions()[interpretationIndex];
16 }
17
18 @Override
19 public int hashCode() {
20 return Arrays.hashCode(mapVersions);
21 }
22
23 @Override
24 public boolean equals(Object o) {
25 if (this == o) return true;
26 if (o == null || getClass() != o.getClass()) return false;
27
28 ModelVersion that = (ModelVersion) o;
29
30 return Arrays.equals(mapVersions, that.mapVersions);
31 }
32
33 @Override
34 public String toString() {
35 return "ModelVersion{" +
36 "mapVersions=" + Arrays.toString(mapVersions) +
37 '}';
38 }
39}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java
index 404be65f..76e3baea 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java
@@ -5,10 +5,7 @@
5 */ 5 */
6package tools.refinery.store.model.internal; 6package tools.refinery.store.model.internal;
7 7
8import tools.refinery.store.map.Cursor; 8import tools.refinery.store.map.*;
9import tools.refinery.store.map.DiffCursor;
10import tools.refinery.store.map.VersionedMap;
11import tools.refinery.store.map.VersionedMapStore;
12import tools.refinery.store.model.Interpretation; 9import tools.refinery.store.model.Interpretation;
13import tools.refinery.store.model.InterpretationListener; 10import tools.refinery.store.model.InterpretationListener;
14import tools.refinery.store.model.Model; 11import tools.refinery.store.model.Model;
@@ -110,15 +107,14 @@ public class VersionedInterpretation<T> implements Interpretation<T> {
110 } 107 }
111 108
112 @Override 109 @Override
113 public DiffCursor<Tuple, T> getDiffCursor(long to) { 110 public DiffCursor<Tuple, T> getDiffCursor(Version to) {
114 return map.getDiffCursor(to); 111 return map.getDiffCursor(to);
115 } 112 }
116 113
117 public long commit() { 114 Version commit() {
118 return map.commit(); 115 return map.commit();
119 } 116 }
120 117 void restore(Version state) {
121 public void restore(long state) {
122 if (!restoreListeners.isEmpty()) { 118 if (!restoreListeners.isEmpty()) {
123 var diffCursor = getDiffCursor(state); 119 var diffCursor = getDiffCursor(state);
124 while (diffCursor.move()) { 120 while (diffCursor.move()) {
@@ -150,7 +146,7 @@ public class VersionedInterpretation<T> implements Interpretation<T> {
150 } 146 }
151 147
152 static <T> VersionedInterpretation<T> of(ModelImpl model, AnySymbol symbol, VersionedMapStore<Tuple, T> store, 148 static <T> VersionedInterpretation<T> of(ModelImpl model, AnySymbol symbol, VersionedMapStore<Tuple, T> store,
153 long state) { 149 Version state) {
154 @SuppressWarnings("unchecked") 150 @SuppressWarnings("unchecked")
155 var typedSymbol = (Symbol<T>) symbol; 151 var typedSymbol = (Symbol<T>) symbol;
156 var map = store.createMap(state); 152 var map = store.createMap(state);
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java
index 5a4f8038..94259edc 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java
@@ -10,13 +10,12 @@ import org.junit.jupiter.api.Timeout;
10import org.junit.jupiter.params.ParameterizedTest; 10import org.junit.jupiter.params.ParameterizedTest;
11import org.junit.jupiter.params.provider.Arguments; 11import org.junit.jupiter.params.provider.Arguments;
12import org.junit.jupiter.params.provider.MethodSource; 12import org.junit.jupiter.params.provider.MethodSource;
13import tools.refinery.store.map.DiffCursor; 13import tools.refinery.store.map.*;
14import tools.refinery.store.map.VersionedMap;
15import tools.refinery.store.map.VersionedMapStore;
16import tools.refinery.store.map.VersionedMapStoreFactoryBuilder;
17import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; 14import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils;
18import tools.refinery.store.map.tests.utils.MapTestEnvironment; 15import tools.refinery.store.map.tests.utils.MapTestEnvironment;
19 16
17import java.util.HashMap;
18import java.util.Map;
20import java.util.Random; 19import java.util.Random;
21import java.util.stream.Stream; 20import java.util.stream.Stream;
22 21
@@ -39,6 +38,7 @@ class DiffCursorFuzzTest {
39 int commitFrequency, boolean commitBeforeDiffCursor) { 38 int commitFrequency, boolean commitBeforeDiffCursor) {
40 39
41 int largestCommit = -1; 40 int largestCommit = -1;
41 Map<Integer,Version> index2Version = new HashMap<>();
42 42
43 { 43 {
44 // 1. build a map with versions 44 // 1. build a map with versions
@@ -55,8 +55,9 @@ class DiffCursorFuzzTest {
55 fail(scenario + ":" + index + ": exception happened: " + exception); 55 fail(scenario + ":" + index + ": exception happened: " + exception);
56 } 56 }
57 if (index % commitFrequency == 0) { 57 if (index % commitFrequency == 0) {
58 long version = versioned.commit(); 58 Version version = versioned.commit();
59 largestCommit = (int) version; 59 index2Version.put(index,version);
60 largestCommit = index;
60 } 61 }
61 if (index % 10000 == 0) 62 if (index % 10000 == 0)
62 System.out.println(scenario + ":" + index + "/" + steps + " building finished"); 63 System.out.println(scenario + ":" + index + "/" + steps + " building finished");
@@ -73,20 +74,20 @@ class DiffCursorFuzzTest {
73 int index = i + 1; 74 int index = i + 1;
74 if (index % diffTravelFrequency == 0) { 75 if (index % diffTravelFrequency == 0) {
75 // diff-travel 76 // diff-travel
76 long travelToVersion = r2.nextInt(largestCommit + 1); 77 int travelToVersion = r2.nextInt(largestCommit + 1);
77 78
78 VersionedMap<Integer, String> oracle = store.createMap(travelToVersion); 79 VersionedMap<Integer, String> oracle = store.createMap(index2Version.get(travelToVersion));
79 80
80 if(commitBeforeDiffCursor) { 81 if(commitBeforeDiffCursor) {
81 moving.commit(); 82 moving.commit();
82 } 83 }
83 DiffCursor<Integer, String> diffCursor = moving.getDiffCursor(travelToVersion); 84 DiffCursor<Integer, String> diffCursor = moving.getDiffCursor(index2Version.get(travelToVersion));
84 moving.putAll(diffCursor); 85 moving.putAll(diffCursor);
85 moving.commit(); 86 moving.commit();
86 87
87 MapTestEnvironment.compareTwoMaps(scenario + ":c" + index, oracle, moving); 88 MapTestEnvironment.compareTwoMaps(scenario + ":c" + index, oracle, moving);
88 89
89 moving.restore(travelToVersion); 90 moving.restore(index2Version.get(travelToVersion));
90 91
91 } else { 92 } else {
92 // random puts 93 // random puts
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java
index 9b2e591a..dfe46bae 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java
@@ -13,6 +13,7 @@ import java.util.List;
13import java.util.Map; 13import java.util.Map;
14import java.util.Random; 14import java.util.Random;
15 15
16import tools.refinery.store.map.Version;
16import tools.refinery.store.map.VersionedMap; 17import tools.refinery.store.map.VersionedMap;
17import tools.refinery.store.map.VersionedMapStore; 18import tools.refinery.store.map.VersionedMapStore;
18import tools.refinery.store.map.tests.utils.MapTestEnvironment; 19import tools.refinery.store.map.tests.utils.MapTestEnvironment;
@@ -61,7 +62,7 @@ public class MultiThreadTestRunnable implements Runnable {
61 // 1. build a map with versions 62 // 1. build a map with versions
62 Random r = new Random(seed); 63 Random r = new Random(seed);
63 VersionedMap<Integer, String> versioned = store.createMap(); 64 VersionedMap<Integer, String> versioned = store.createMap();
64 Map<Integer, Long> index2Version = new HashMap<>(); 65 Map<Integer, Version> index2Version = new HashMap<>();
65 66
66 for (int i = 0; i < steps; i++) { 67 for (int i = 0; i < steps; i++) {
67 int index = i + 1; 68 int index = i + 1;
@@ -74,7 +75,7 @@ public class MultiThreadTestRunnable implements Runnable {
74 logAndThrowError(scenario + ":" + index + ": exception happened: " + exception); 75 logAndThrowError(scenario + ":" + index + ": exception happened: " + exception);
75 } 76 }
76 if (index % commitFrequency == 0) { 77 if (index % commitFrequency == 0) {
77 long version = versioned.commit(); 78 Version version = versioned.commit();
78 index2Version.put(i, version); 79 index2Version.put(i, version);
79 } 80 }
80 MapTestEnvironment.printStatus(scenario, index, steps, "building"); 81 MapTestEnvironment.printStatus(scenario, index, steps, "building");
@@ -100,13 +101,12 @@ public class MultiThreadTestRunnable implements Runnable {
100 MapTestEnvironment.compareTwoMaps(scenario + ":" + index, reference, versioned, null); 101 MapTestEnvironment.compareTwoMaps(scenario + ":" + index, reference, versioned, null);
101 102
102 // go back to a random state (probably created by another thread) 103 // go back to a random state (probably created by another thread)
103 List<Long> states = new ArrayList<>(store.getStates()); 104 List<Version> states = new ArrayList<>(index2Version.values());
104 states.sort(Long::compare); 105 //states.sort(Long::compare);
105 Collections.shuffle(states, r2); 106 Collections.shuffle(states, r2);
106 for (Long state : states.subList(0, Math.min(states.size(), 100))) { 107 for (Version state : states.subList(0, Math.min(states.size(), 100))) {
107 long x = state; 108 versioned.restore(state);
108 versioned.restore(x); 109 var clean = store.createMap(state);
109 var clean = store.createMap(x);
110 MapTestEnvironment.compareTwoMaps(scenario + ":" + index, clean, versioned, null); 110 MapTestEnvironment.compareTwoMaps(scenario + ":" + index, clean, versioned, null);
111 } 111 }
112 versioned.restore(index2Version.get(i)); 112 versioned.restore(index2Version.get(i));
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java
index 0b399c3a..5c768788 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java
@@ -10,6 +10,7 @@ import org.junit.jupiter.api.Timeout;
10import org.junit.jupiter.params.ParameterizedTest; 10import org.junit.jupiter.params.ParameterizedTest;
11import org.junit.jupiter.params.provider.Arguments; 11import org.junit.jupiter.params.provider.Arguments;
12import org.junit.jupiter.params.provider.MethodSource; 12import org.junit.jupiter.params.provider.MethodSource;
13import tools.refinery.store.map.Version;
13import tools.refinery.store.map.VersionedMap; 14import tools.refinery.store.map.VersionedMap;
14import tools.refinery.store.map.VersionedMapStore; 15import tools.refinery.store.map.VersionedMapStore;
15import tools.refinery.store.map.VersionedMapStoreFactoryBuilder; 16import tools.refinery.store.map.VersionedMapStoreFactoryBuilder;
@@ -40,7 +41,7 @@ class RestoreFuzzTest {
40 // 1. build a map with versions 41 // 1. build a map with versions
41 Random r = new Random(seed); 42 Random r = new Random(seed);
42 VersionedMap<Integer, String> versioned = store.createMap(); 43 VersionedMap<Integer, String> versioned = store.createMap();
43 Map<Integer, Long> index2Version = new HashMap<>(); 44 Map<Integer, Version> index2Version = new HashMap<>();
44 45
45 for (int i = 0; i < steps; i++) { 46 for (int i = 0; i < steps; i++) {
46 int index = i + 1; 47 int index = i + 1;
@@ -53,7 +54,7 @@ class RestoreFuzzTest {
53 fail(scenario + ":" + index + ": exception happened: " + exception); 54 fail(scenario + ":" + index + ": exception happened: " + exception);
54 } 55 }
55 if (index % commitFrequency == 0) { 56 if (index % commitFrequency == 0) {
56 long version = versioned.commit(); 57 Version version = versioned.commit();
57 index2Version.put(i, version); 58 index2Version.put(i, version);
58 } 59 }
59 MapTestEnvironment.printStatus(scenario, index, steps, "building"); 60 MapTestEnvironment.printStatus(scenario, index, steps, "building");
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java
index b17766b7..299c94b1 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java
@@ -19,6 +19,7 @@ import org.junit.jupiter.params.provider.Arguments;
19import org.junit.jupiter.params.provider.MethodSource; 19import org.junit.jupiter.params.provider.MethodSource;
20 20
21import tools.refinery.store.map.ContinuousHashProvider; 21import tools.refinery.store.map.ContinuousHashProvider;
22import tools.refinery.store.map.Version;
22import tools.refinery.store.map.VersionedMapStore; 23import tools.refinery.store.map.VersionedMapStore;
23import tools.refinery.store.map.internal.state.VersionedMapStoreStateImpl; 24import tools.refinery.store.map.internal.state.VersionedMapStoreStateImpl;
24import tools.refinery.store.map.internal.state.VersionedMapStateImpl; 25import tools.refinery.store.map.internal.state.VersionedMapStateImpl;
@@ -47,7 +48,7 @@ class SharedStoreFuzzTest {
47 versioneds.add((VersionedMapStateImpl<Integer, String>) store.createMap()); 48 versioneds.add((VersionedMapStateImpl<Integer, String>) store.createMap());
48 } 49 }
49 50
50 List<Map<Integer, Long>> index2Version = new LinkedList<>(); 51 List<Map<Integer, Version>> index2Version = new LinkedList<>();
51 for (int i = 0; i < stores.size(); i++) { 52 for (int i = 0; i < stores.size(); i++) {
52 index2Version.add(new HashMap<>()); 53 index2Version.add(new HashMap<>());
53 } 54 }
@@ -59,7 +60,7 @@ class SharedStoreFuzzTest {
59 String nextValue = values[r.nextInt(values.length)]; 60 String nextValue = values[r.nextInt(values.length)];
60 versioneds.get(storeIndex).put(nextKey, nextValue); 61 versioneds.get(storeIndex).put(nextKey, nextValue);
61 if (stepIndex % commitFrequency == 0) { 62 if (stepIndex % commitFrequency == 0) {
62 long version = versioneds.get(storeIndex).commit(); 63 Version version = versioneds.get(storeIndex).commit();
63 index2Version.get(storeIndex).put(i, version); 64 index2Version.get(storeIndex).put(i, version);
64 } 65 }
65 MapTestEnvironment.printStatus(scenario, stepIndex, steps, "building"); 66 MapTestEnvironment.printStatus(scenario, stepIndex, steps, "building");
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java
index 4c3ecb09..ec04904e 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java
@@ -18,26 +18,35 @@ public final class FuzzTestCollections {
18 public static final Object[] randomSeedOptions = {1}; 18 public static final Object[] randomSeedOptions = {1};
19 public static final Object[] storeConfigs = { 19 public static final Object[] storeConfigs = {
20 // State based 20 // State based
21 // Default
21 VersionedMapStore.<Integer,String>builder() 22 VersionedMapStore.<Integer,String>builder()
22 .stateBasedImmutableWhenCommitting(true)
23 .stateBasedHashProvider(MapTestEnvironment.prepareHashProvider(false)) 23 .stateBasedHashProvider(MapTestEnvironment.prepareHashProvider(false))
24 .stateBasedSharingStrategy(VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE), 24 .stateBasedSharingStrategy(VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE),
25 // Evil hash code test
25 VersionedMapStore.<Integer,String>builder() 26 VersionedMapStore.<Integer,String>builder()
26 .stateBasedImmutableWhenCommitting(true)
27 .stateBasedHashProvider(MapTestEnvironment.prepareHashProvider(true)) 27 .stateBasedHashProvider(MapTestEnvironment.prepareHashProvider(true))
28 .stateBasedSharingStrategy(VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE), 28 .stateBasedSharingStrategy(VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE),
29 // No weak hashmap test
30 VersionedMapStore.<Integer,String>builder()
31 .versionFreeing(false)
32 .stateBasedHashProvider(MapTestEnvironment.prepareHashProvider(false))
33 .stateBasedSharingStrategy(VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE),
34 // Copy when committing, do not hurt the work copy, share between saves.
29 VersionedMapStore.<Integer,String>builder() 35 VersionedMapStore.<Integer,String>builder()
30 .stateBasedImmutableWhenCommitting(false) 36 .stateBasedImmutableWhenCommitting(false)
31 .stateBasedHashProvider(MapTestEnvironment.prepareHashProvider(false)) 37 .stateBasedHashProvider(MapTestEnvironment.prepareHashProvider(false))
32 .stateBasedSharingStrategy(VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE), 38 .stateBasedSharingStrategy(VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE),
39 // Copy when committing, do not hurt the work copy, do not share between states.
33 VersionedMapStore.<Integer,String>builder() 40 VersionedMapStore.<Integer,String>builder()
34 .stateBasedImmutableWhenCommitting(false) 41 .stateBasedImmutableWhenCommitting(false)
35 .stateBasedHashProvider(MapTestEnvironment.prepareHashProvider(false)) 42 .stateBasedHashProvider(MapTestEnvironment.prepareHashProvider(false))
36 .stateBasedSharingStrategy(VersionedMapStoreFactoryBuilder.SharingStrategy.NO_NODE_CACHE), 43 .stateBasedSharingStrategy(VersionedMapStoreFactoryBuilder.SharingStrategy.NO_NODE_CACHE),
37 44
38 // Delta based 45 // Delta based
46 // Set based transactions
39 VersionedMapStore.<Integer,String>builder() 47 VersionedMapStore.<Integer,String>builder()
40 .deltaTransactionStrategy(VersionedMapStoreFactoryBuilder.DeltaTransactionStrategy.SET), 48 .deltaTransactionStrategy(VersionedMapStoreFactoryBuilder.DeltaTransactionStrategy.SET),
49 // List based transactions
41 VersionedMapStore.<Integer,String>builder() 50 VersionedMapStore.<Integer,String>builder()
42 .deltaTransactionStrategy(VersionedMapStoreFactoryBuilder.DeltaTransactionStrategy.LIST) 51 .deltaTransactionStrategy(VersionedMapStoreFactoryBuilder.DeltaTransactionStrategy.LIST)
43 }; 52 };
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 401f2866..b84df280 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
@@ -125,7 +125,7 @@ public class MapTestEnvironment<K, V> {
125 } 125 }
126 } 126 }
127 127
128 public long commit(){ 128 public Version commit(){
129 return sut.commit(); 129 return sut.commit();
130 } 130 }
131 131
diff --git a/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java b/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java
index 56b75804..dc7b776e 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java
@@ -6,6 +6,7 @@
6package tools.refinery.store.model.tests; 6package tools.refinery.store.model.tests;
7 7
8import org.junit.jupiter.api.Test; 8import org.junit.jupiter.api.Test;
9import tools.refinery.store.map.Version;
9import tools.refinery.store.model.Model; 10import tools.refinery.store.model.Model;
10import tools.refinery.store.model.ModelStore; 11import tools.refinery.store.model.ModelStore;
11import tools.refinery.store.representation.Symbol; 12import tools.refinery.store.representation.Symbol;
@@ -120,7 +121,7 @@ class ModelTest {
120 assertTrue(model.hasUncommittedChanges()); 121 assertTrue(model.hasUncommittedChanges());
121 assertEquals(Model.NO_STATE_ID, model.getState()); 122 assertEquals(Model.NO_STATE_ID, model.getState());
122 123
123 long state1 = model.commit(); 124 Version state1 = model.commit();
124 125
125 assertFalse(model.hasUncommittedChanges()); 126 assertFalse(model.hasUncommittedChanges());
126 assertEquals(state1, model.getState()); 127 assertEquals(state1, model.getState());
@@ -134,7 +135,7 @@ class ModelTest {
134 assertTrue(model.hasUncommittedChanges()); 135 assertTrue(model.hasUncommittedChanges());
135 assertEquals(state1, model.getState()); 136 assertEquals(state1, model.getState());
136 137
137 long state2 = model.commit(); 138 Version state2 = model.commit();
138 139
139 assertFalse(model.hasUncommittedChanges()); 140 assertFalse(model.hasUncommittedChanges());
140 assertEquals(state2, model.getState()); 141 assertEquals(state2, model.getState());