aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store/src/main/java/tools
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 /subprojects/store/src/main/java/tools
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.
Diffstat (limited to 'subprojects/store/src/main/java/tools')
-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
23 files changed, 258 insertions, 162 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);