aboutsummaryrefslogtreecommitdiffstats
path: root/store
diff options
context:
space:
mode:
authorLibravatar OszkarSemerath <semerath@mit.bme.hu>2021-10-22 02:12:48 +0200
committerLibravatar OszkarSemerath <semerath@mit.bme.hu>2021-10-22 02:12:48 +0200
commiteea121e9a039c2596be1c9438e44ec24e888fda8 (patch)
tree6aee1019b838380423ab9d21ac904e65da778b38 /store
parentRawPatternMatcher for exposing raw pattern matches (diff)
downloadrefinery-eea121e9a039c2596be1c9438e44ec24e888fda8.tar.gz
refinery-eea121e9a039c2596be1c9438e44ec24e888fda8.tar.zst
refinery-eea121e9a039c2596be1c9438e44ec24e888fda8.zip
Buffered Model update listener, first version
Diffstat (limited to 'store')
-rw-r--r--store/src/main/java/tools/refinery/store/query/RelationalScope.java14
-rw-r--r--store/src/main/java/tools/refinery/store/query/internal/ModelUpdateListener.java112
-rw-r--r--store/src/main/java/tools/refinery/store/query/internal/RelationUpdateListener.java52
-rw-r--r--store/src/main/java/tools/refinery/store/query/internal/RelationalEngineContext.java2
-rw-r--r--store/src/main/java/tools/refinery/store/query/internal/RelationalRuntimeContext.java14
-rw-r--r--store/src/main/java/tools/refinery/store/query/internal/ViewUpdate.java4
-rw-r--r--store/src/main/java/tools/refinery/store/query/internal/ViewUpdateBuffer.java46
-rw-r--r--store/src/main/java/tools/refinery/store/query/internal/ViewUpdateTranslator.java (renamed from store/src/main/java/tools/refinery/store/query/internal/RelationUpdateListenerEntry.java)27
8 files changed, 187 insertions, 84 deletions
diff --git a/store/src/main/java/tools/refinery/store/query/RelationalScope.java b/store/src/main/java/tools/refinery/store/query/RelationalScope.java
index 5fe8083a..e37fdb95 100644
--- a/store/src/main/java/tools/refinery/store/query/RelationalScope.java
+++ b/store/src/main/java/tools/refinery/store/query/RelationalScope.java
@@ -9,23 +9,23 @@ import org.eclipse.viatra.query.runtime.api.scope.IIndexingErrorListener;
9import org.eclipse.viatra.query.runtime.api.scope.QueryScope; 9import org.eclipse.viatra.query.runtime.api.scope.QueryScope;
10 10
11import tools.refinery.store.model.Model; 11import tools.refinery.store.model.Model;
12import tools.refinery.store.model.Tuple; 12import tools.refinery.store.query.internal.ModelUpdateListener;
13import tools.refinery.store.query.internal.RelationUpdateListener;
14import tools.refinery.store.query.internal.RelationalEngineContext; 13import tools.refinery.store.query.internal.RelationalEngineContext;
15import tools.refinery.store.query.view.RelationView; 14import tools.refinery.store.query.view.RelationView;
16 15
17public class RelationalScope extends QueryScope{ 16public class RelationalScope extends QueryScope{
18 private final Model model; 17 private final Model model;
19 private final RelationUpdateListener updateListener; 18 private final ModelUpdateListener updateListener;
20 19
21 public RelationalScope(Model model, Set<RelationView<?>> relationViews) { 20 public RelationalScope(Model model, Set<RelationView<?>> relationViews) {
22 this.model = model; 21 this.model = model;
23 updateListener = new RelationUpdateListener(relationViews); 22 this.updateListener = new ModelUpdateListener(relationViews);
23 //this.changeListener = new
24 } 24 }
25 25
26 public <D> void processUpdate(RelationView<D> relationView, Tuple key, D oldValue, D newValue) { 26// public <D> void processUpdate(RelationView<D> relationView, Tuple key, D oldValue, D newValue) {
27 updateListener.processChange(relationView, key, oldValue, newValue); 27// updateListener.processChange(relationView, key, oldValue, newValue);
28 } 28// }
29 29
30 @Override 30 @Override
31 protected IEngineContext createEngineContext(ViatraQueryEngine engine, IIndexingErrorListener errorListener, 31 protected IEngineContext createEngineContext(ViatraQueryEngine engine, IIndexingErrorListener errorListener,
diff --git a/store/src/main/java/tools/refinery/store/query/internal/ModelUpdateListener.java b/store/src/main/java/tools/refinery/store/query/internal/ModelUpdateListener.java
new file mode 100644
index 00000000..425ae8f7
--- /dev/null
+++ b/store/src/main/java/tools/refinery/store/query/internal/ModelUpdateListener.java
@@ -0,0 +1,112 @@
1package tools.refinery.store.query.internal;
2
3import java.util.HashMap;
4import java.util.HashSet;
5import java.util.Map;
6import java.util.Set;
7
8import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener;
9import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple;
10
11import tools.refinery.store.model.Tuple;
12import tools.refinery.store.model.representation.Relation;
13import tools.refinery.store.query.view.RelationView;
14
15public class ModelUpdateListener {
16 /**
17 * Collections of Relations and their Views.
18 */
19 private final Map<Relation<?>, Set<RelationView<?>>> relation2View;
20 /**
21 * Collection of Views and their buffers.
22 */
23 private final Map<RelationView<?>, Set<ViewUpdateBuffer<?>>> view2Buffers;
24
25 public ModelUpdateListener(Set<RelationView<?>> relationViews) {
26 this.relation2View = new HashMap<>();
27 this.view2Buffers = new HashMap<>();
28
29 for (RelationView<?> relationView : relationViews) {
30 registerView(relationView);
31 }
32 }
33
34 private void registerView(RelationView<?> view) {
35 Relation<?> relation = view.getRepresentation();
36
37 // 1. register views to relations, if necessary
38 var views = relation2View.get(relation);
39 if (views == null) {
40 views = new HashSet<>();
41 relation2View.put(relation, views);
42 }
43 views.add(view);
44
45 // 2. register notifier map to views, if necessary
46 if (!view2Buffers.containsKey(view)) {
47 view2Buffers.put(view, new HashSet<>());
48 }
49 }
50
51 boolean containsRelationalView(RelationView<?> relationalKey) {
52 return view2Buffers.containsKey(relationalKey);
53 }
54
55 <D> void addListener(RelationView<D> relationView, ITuple seed, IQueryRuntimeContextListener listener) {
56 if (view2Buffers.containsKey(relationView)) {
57 ViewUpdateTranslator<D> updateListener = new ViewUpdateTranslator<>(relationView, seed, listener);
58 ViewUpdateBuffer<D> updateBuffer = new ViewUpdateBuffer<>(updateListener);
59 view2Buffers.get(relationView).add(updateBuffer);
60 } else
61 throw new IllegalArgumentException();
62 }
63
64 void removeListener(RelationView<?> relationView, ITuple seed, IQueryRuntimeContextListener listener) {
65 if (view2Buffers.containsKey(relationView)) {
66 Set<ViewUpdateBuffer<?>> buffers = this.view2Buffers.get(relationView);
67 for(var buffer : buffers) {
68 if(buffer.getUpdateListener().key == seed && buffer.getUpdateListener().listener == listener) {
69 // remove buffer and terminate immediately, or it will break iterator.
70 buffers.remove(buffer);
71 return;
72 }
73 }
74 } else
75 throw new IllegalArgumentException();
76 }
77
78 public <D> void addUpdate(Relation<D> relation, Tuple key, D oldValue, D newValue) {
79 var views = this.relation2View.get(relation);
80 if (views != null) {
81 for (var view : views) {
82 var buffers = this.view2Buffers.get(view);
83 for (var buffer : buffers) {
84 @SuppressWarnings("unchecked")
85 var typedBuffer = (ViewUpdateBuffer<D>) buffer;
86 typedBuffer.addChange(key, oldValue, newValue);
87 }
88 }
89 } else {
90 throw new IllegalArgumentException(
91 "Relation " + relation.getName() + " is not in the scope of the update listener.");
92 }
93 }
94
95 public boolean hasChange() {
96 for (var bufferCollection : this.view2Buffers.values()) {
97 for (ViewUpdateBuffer<?> buffer : bufferCollection) {
98 if (buffer.hasChange())
99 return true;
100 }
101 }
102 return false;
103 }
104
105 public void flush() {
106 for (var bufferCollection : this.view2Buffers.values()) {
107 for (ViewUpdateBuffer<?> buffer : bufferCollection) {
108 buffer.flush();
109 }
110 }
111 }
112}
diff --git a/store/src/main/java/tools/refinery/store/query/internal/RelationUpdateListener.java b/store/src/main/java/tools/refinery/store/query/internal/RelationUpdateListener.java
deleted file mode 100644
index cf5260f6..00000000
--- a/store/src/main/java/tools/refinery/store/query/internal/RelationUpdateListener.java
+++ /dev/null
@@ -1,52 +0,0 @@
1package tools.refinery.store.query.internal;
2
3import java.util.HashMap;
4import java.util.HashSet;
5import java.util.Map;
6import java.util.Set;
7
8import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener;
9import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple;
10
11import tools.refinery.store.model.Tuple;
12import tools.refinery.store.query.view.RelationView;
13
14public class RelationUpdateListener {
15 private final Map<RelationView<?>,Set<RelationUpdateListenerEntry<?>>> view2Listeners;
16
17 public RelationUpdateListener(Set<RelationView<?>> relationViews) {
18 view2Listeners = new HashMap<>();
19 for(RelationView<?> relationView : relationViews) {
20 view2Listeners.put(relationView, new HashSet<>());
21 }
22 }
23 public boolean containsRelationalView(RelationView<?> relationalKey) {
24 RelationView<?> relationView = relationalKey.getWrappedKey();
25 return view2Listeners.containsKey(relationView);
26 }
27 public void addListener(RelationView<?> relationalKey, ITuple seed, IQueryRuntimeContextListener listener) {
28 RelationView<?> relationView = relationalKey.getWrappedKey();
29 if(view2Listeners.containsKey(relationView)) {
30 RelationUpdateListenerEntry<?> entry = new RelationUpdateListenerEntry<>(relationalKey, seed, listener);
31 view2Listeners.get(relationView).add(entry);
32 } else throw new IllegalArgumentException();
33 }
34 public void removeListener(RelationView<?> relationalKey, ITuple seed, IQueryRuntimeContextListener listener) {
35 RelationView<?> relationView = relationalKey.getWrappedKey();
36 if(view2Listeners.containsKey(relationView)) {
37 RelationUpdateListenerEntry<?> entry = new RelationUpdateListenerEntry<>(relationalKey, seed, listener);
38 view2Listeners.get(relationView).remove(entry);
39 } else throw new IllegalArgumentException();
40 }
41
42 public <D> void processChange(RelationView<D> relationView, Tuple tuple, D oldValue, D newValue) {
43 Set<RelationUpdateListenerEntry<?>> listeners = view2Listeners.get(relationView);
44 if(listeners != null) {
45 for(RelationUpdateListenerEntry<?> listener : listeners) {
46 @SuppressWarnings("unchecked")
47 RelationUpdateListenerEntry<D> typeCorrectListener = (RelationUpdateListenerEntry<D>) listener;
48 typeCorrectListener.processChange(tuple, oldValue, newValue);
49 }
50 } else throw new IllegalArgumentException("View was not indexed in constructor "+relationView);
51 }
52}
diff --git a/store/src/main/java/tools/refinery/store/query/internal/RelationalEngineContext.java b/store/src/main/java/tools/refinery/store/query/internal/RelationalEngineContext.java
index 691baf81..dfbd8545 100644
--- a/store/src/main/java/tools/refinery/store/query/internal/RelationalEngineContext.java
+++ b/store/src/main/java/tools/refinery/store/query/internal/RelationalEngineContext.java
@@ -11,7 +11,7 @@ public class RelationalEngineContext implements IEngineContext{
11 private final RelationalRuntimeContext runtimeContext; 11 private final RelationalRuntimeContext runtimeContext;
12 12
13 13
14 public RelationalEngineContext(Model model, RelationUpdateListener updateListener) { 14 public RelationalEngineContext(Model model, ModelUpdateListener updateListener) {
15 runtimeContext = new RelationalRuntimeContext(model, updateListener); 15 runtimeContext = new RelationalRuntimeContext(model, updateListener);
16 } 16 }
17 17
diff --git a/store/src/main/java/tools/refinery/store/query/internal/RelationalRuntimeContext.java b/store/src/main/java/tools/refinery/store/query/internal/RelationalRuntimeContext.java
index da118f26..d5112128 100644
--- a/store/src/main/java/tools/refinery/store/query/internal/RelationalRuntimeContext.java
+++ b/store/src/main/java/tools/refinery/store/query/internal/RelationalRuntimeContext.java
@@ -25,12 +25,12 @@ import tools.refinery.store.query.view.RelationView;
25 25
26public class RelationalRuntimeContext implements IQueryRuntimeContext { 26public class RelationalRuntimeContext implements IQueryRuntimeContext {
27 private final RelationalQueryMetaContext metaContext = new RelationalQueryMetaContext(); 27 private final RelationalQueryMetaContext metaContext = new RelationalQueryMetaContext();
28 private final RelationUpdateListener relationUpdateListener; 28 private final ModelUpdateListener modelUpdateListener;
29 private final Model model; 29 private final Model model;
30 30
31 public RelationalRuntimeContext(Model model, RelationUpdateListener relationUpdateListener) { 31 public RelationalRuntimeContext(Model model, ModelUpdateListener relationUpdateListener) {
32 this.model = model; 32 this.model = model;
33 this.relationUpdateListener = relationUpdateListener; 33 this.modelUpdateListener = relationUpdateListener;
34 } 34 }
35 35
36 @Override 36 @Override
@@ -58,7 +58,7 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext {
58 @Override 58 @Override
59 public boolean isIndexed(IInputKey key, IndexingService service) { 59 public boolean isIndexed(IInputKey key, IndexingService service) {
60 if(key instanceof RelationView<?> relationalKey) { 60 if(key instanceof RelationView<?> relationalKey) {
61 return this.relationUpdateListener.containsRelationalView(relationalKey); 61 return this.modelUpdateListener.containsRelationalView(relationalKey);
62 } else { 62 } else {
63 return false; 63 return false;
64 } 64 }
@@ -74,7 +74,7 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext {
74 RelationView<?> checkKey(IInputKey key) { 74 RelationView<?> checkKey(IInputKey key) {
75 if(key instanceof RelationView) { 75 if(key instanceof RelationView) {
76 RelationView<?> relationViewKey = (RelationView<?>) key; 76 RelationView<?> relationViewKey = (RelationView<?>) key;
77 if(relationUpdateListener.containsRelationalView(relationViewKey)) { 77 if(modelUpdateListener.containsRelationalView(relationViewKey)) {
78 return relationViewKey; 78 return relationViewKey;
79 } else { 79 } else {
80 throw new IllegalStateException("Query is asking for non-indexed key"); 80 throw new IllegalStateException("Query is asking for non-indexed key");
@@ -144,14 +144,14 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext {
144 @Override 144 @Override
145 public void addUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener) { 145 public void addUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener) {
146 RelationView<?> relationalKey = checkKey(key); 146 RelationView<?> relationalKey = checkKey(key);
147 this.relationUpdateListener.addListener(relationalKey, seed, listener); 147 this.modelUpdateListener.addListener(relationalKey, seed, listener);
148 148
149 } 149 }
150 150
151 @Override 151 @Override
152 public void removeUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener) { 152 public void removeUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener) {
153 RelationView<?> relationalKey = checkKey(key); 153 RelationView<?> relationalKey = checkKey(key);
154 this.relationUpdateListener.removeListener(relationalKey, seed, listener); 154 this.modelUpdateListener.removeListener(relationalKey, seed, listener);
155 } 155 }
156 156
157 @Override 157 @Override
diff --git a/store/src/main/java/tools/refinery/store/query/internal/ViewUpdate.java b/store/src/main/java/tools/refinery/store/query/internal/ViewUpdate.java
new file mode 100644
index 00000000..d4a295f8
--- /dev/null
+++ b/store/src/main/java/tools/refinery/store/query/internal/ViewUpdate.java
@@ -0,0 +1,4 @@
1package tools.refinery.store.query.internal;
2
3record ViewUpdate (Object[] tuple, boolean isInsertion) {
4}
diff --git a/store/src/main/java/tools/refinery/store/query/internal/ViewUpdateBuffer.java b/store/src/main/java/tools/refinery/store/query/internal/ViewUpdateBuffer.java
new file mode 100644
index 00000000..6bc4c96a
--- /dev/null
+++ b/store/src/main/java/tools/refinery/store/query/internal/ViewUpdateBuffer.java
@@ -0,0 +1,46 @@
1package tools.refinery.store.query.internal;
2
3import java.util.ArrayList;
4import java.util.Arrays;
5import java.util.List;
6
7import tools.refinery.store.model.Tuple;
8
9public class ViewUpdateBuffer<D> {
10 protected final ViewUpdateTranslator<D> updateListener;
11 protected final List<ViewUpdate> buffer = new ArrayList<>();
12
13 public ViewUpdateBuffer(ViewUpdateTranslator<D> updateListener) {
14 this.updateListener = updateListener;
15 }
16
17 public ViewUpdateTranslator<D> getUpdateListener() {
18 return updateListener;
19 }
20
21 public boolean hasChange() {
22 return ! buffer.isEmpty();
23 }
24
25 public void addChange(Tuple tuple, D oldValue, D newValue) {
26 if(oldValue != newValue) {
27 Object[] oldTuple = updateListener.isMatching(tuple, oldValue);
28 Object[] newTuple = updateListener.isMatching(tuple, newValue);
29 if(!Arrays.equals(oldTuple, newTuple)) {
30 if(oldTuple != null) {
31 buffer.add(new ViewUpdate(oldTuple, false));
32 }
33 if(newTuple != null) {
34 buffer.add(new ViewUpdate(newTuple, true));
35 }
36 }
37 }
38 }
39
40 public void flush() {
41 for (ViewUpdate viewChange : buffer) {
42 updateListener.processChange(viewChange);
43 }
44 buffer.clear();
45 }
46}
diff --git a/store/src/main/java/tools/refinery/store/query/internal/RelationUpdateListenerEntry.java b/store/src/main/java/tools/refinery/store/query/internal/ViewUpdateTranslator.java
index 860a80b7..4596b9c1 100644
--- a/store/src/main/java/tools/refinery/store/query/internal/RelationUpdateListenerEntry.java
+++ b/store/src/main/java/tools/refinery/store/query/internal/ViewUpdateTranslator.java
@@ -1,6 +1,5 @@
1package tools.refinery.store.query.internal; 1package tools.refinery.store.query.internal;
2 2
3import java.util.Arrays;
4import java.util.Objects; 3import java.util.Objects;
5 4
6import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener; 5import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener;
@@ -10,30 +9,24 @@ import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples;
10import tools.refinery.store.model.Tuple; 9import tools.refinery.store.model.Tuple;
11import tools.refinery.store.query.view.RelationView; 10import tools.refinery.store.query.view.RelationView;
12 11
13public class RelationUpdateListenerEntry<D> { 12public class ViewUpdateTranslator<D> {
14 final RelationView<D> key; 13 final RelationView<D> key;
15 final ITuple filter; 14 final ITuple filter;
16 final IQueryRuntimeContextListener listener; 15 final IQueryRuntimeContextListener listener;
17 16
18 public RelationUpdateListenerEntry(RelationView<D> key, ITuple filter, IQueryRuntimeContextListener listener) { 17 public ViewUpdateTranslator(RelationView<D> key, ITuple filter, IQueryRuntimeContextListener listener) {
19 super(); 18 super();
20 this.key = key; 19 this.key = key;
21 this.filter = filter; 20 this.filter = filter;
22 this.listener = listener; 21 this.listener = listener;
23 } 22 }
24 23
25 public void processChange(Tuple tuple, D oldValue, D newValue) { 24 public void processChange(ViewUpdate change) {
26 Object[] oldTuple = isMatching(key.getWrappedKey().transform(tuple, oldValue), filter); 25 listener.update(key, Tuples.flatTupleOf(change.tuple()), change.isInsertion());
27 Object[] newTuple = isMatching(key.getWrappedKey().transform(tuple, newValue), filter); 26 }
28 27
29 if(!Arrays.equals(oldTuple, newTuple)) { 28 public Object[] isMatching(Tuple tuple, D value){
30 if(oldTuple != null) { 29 return isMatching(key.getWrappedKey().transform(tuple, value), filter);
31 listener.update(key, Tuples.flatTupleOf(oldTuple), false);
32 }
33 if(newTuple != null) {
34 listener.update(key, Tuples.flatTupleOf(newTuple), true);
35 }
36 }
37 } 30 }
38 31
39 private Object[] isMatching(Object[] tuple, ITuple filter) { 32 private Object[] isMatching(Object[] tuple, ITuple filter) {
@@ -55,9 +48,9 @@ public class RelationUpdateListenerEntry<D> {
55 public boolean equals(Object obj) { 48 public boolean equals(Object obj) {
56 if (this == obj) 49 if (this == obj)
57 return true; 50 return true;
58 if (!(obj instanceof RelationUpdateListenerEntry)) 51 if (!(obj instanceof ViewUpdateTranslator))
59 return false; 52 return false;
60 RelationUpdateListenerEntry<?> other = (RelationUpdateListenerEntry<?>) obj; 53 ViewUpdateTranslator<?> other = (ViewUpdateTranslator<?>) obj;
61 return Objects.equals(filter, other.filter) && Objects.equals(key, other.key) 54 return Objects.equals(filter, other.filter) && Objects.equals(key, other.key)
62 && Objects.equals(listener, other.listener); 55 && Objects.equals(listener, other.listener);
63 } 56 }