From 8cb6537188dd3ea3875798b35f07a5220f64dd21 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Thu, 2 Feb 2023 16:50:54 +0100 Subject: feat: track ModelQuery pending changes --- .../store/query/viatra/ViatraModelQuery.java | 7 +++-- .../query/viatra/ViatraModelQueryAdapter.java | 8 ++++++ .../query/viatra/ViatraModelQueryStoreAdapter.java | 4 +++ .../query/viatra/internal/RelationalScope.java | 15 +++-------- .../internal/ViatraModelQueryAdapterImpl.java | 30 +++++++++++++++++----- .../internal/ViatraModelQueryStoreAdapterImpl.java | 2 +- .../internal/context/RelationalEngineContext.java | 10 +++----- .../internal/context/RelationalRuntimeContext.java | 10 ++++---- .../internal/update/ModelUpdateListener.java | 13 +++++----- .../update/RelationViewUpdateListener.java | 14 +++++++--- .../TupleChangingRelationViewUpdateListener.java | 6 +++-- .../TuplePreservingRelationViewUpdateListener.java | 7 +++-- .../store/query/viatra/QueryTransactionTest.java | 7 ++++- .../refinery/store/query/ModelQueryAdapter.java | 2 ++ 14 files changed, 87 insertions(+), 48 deletions(-) create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryAdapter.java diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQuery.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQuery.java index ecac570b..677e3c7d 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQuery.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQuery.java @@ -3,15 +3,14 @@ package tools.refinery.store.query.viatra; import tools.refinery.store.adapter.ModelAdapterBuilderFactory; import tools.refinery.store.model.ModelStoreBuilder; import tools.refinery.store.query.ModelQuery; -import tools.refinery.store.query.ModelQueryAdapter; import tools.refinery.store.query.viatra.internal.ViatraModelQueryBuilderImpl; -public final class ViatraModelQuery extends ModelAdapterBuilderFactory { +public final class ViatraModelQuery extends ModelAdapterBuilderFactory { public static final ViatraModelQuery ADAPTER = new ViatraModelQuery(); private ViatraModelQuery() { - super(ModelQueryAdapter.class, ViatraModelQueryStoreAdapter.class, ViatraModelQueryBuilder.class); + super(ViatraModelQueryAdapter.class, ViatraModelQueryStoreAdapter.class, ViatraModelQueryBuilder.class); extendsAdapter(ModelQuery.ADAPTER); } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryAdapter.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryAdapter.java new file mode 100644 index 00000000..7e21476b --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryAdapter.java @@ -0,0 +1,8 @@ +package tools.refinery.store.query.viatra; + +import tools.refinery.store.query.ModelQueryAdapter; + +public interface ViatraModelQueryAdapter extends ModelQueryAdapter { + @Override + ViatraModelQueryStoreAdapter getStoreAdapter(); +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryStoreAdapter.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryStoreAdapter.java index d52575d2..1ee02f12 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryStoreAdapter.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryStoreAdapter.java @@ -1,8 +1,12 @@ package tools.refinery.store.query.viatra; import org.eclipse.viatra.query.runtime.api.ViatraQueryEngineOptions; +import tools.refinery.store.model.Model; import tools.refinery.store.query.ModelQueryStoreAdapter; public interface ViatraModelQueryStoreAdapter extends ModelQueryStoreAdapter { ViatraQueryEngineOptions getEngineOptions(); + + @Override + ViatraModelQueryAdapter createModelAdapter(Model model); } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RelationalScope.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RelationalScope.java index b4d43ef8..8328e759 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RelationalScope.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RelationalScope.java @@ -5,25 +5,18 @@ import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine; import org.eclipse.viatra.query.runtime.api.scope.IEngineContext; import org.eclipse.viatra.query.runtime.api.scope.IIndexingErrorListener; import org.eclipse.viatra.query.runtime.api.scope.QueryScope; -import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; -import tools.refinery.store.model.Model; import tools.refinery.store.query.viatra.internal.context.RelationalEngineContext; -import tools.refinery.store.query.view.AnyRelationView; - -import java.util.Map; public class RelationalScope extends QueryScope { - private final Model model; - private final Map relationViews; + private final ViatraModelQueryAdapterImpl adapter; - public RelationalScope(Model model, Map relationViews) { - this.model = model; - this.relationViews = relationViews; + public RelationalScope(ViatraModelQueryAdapterImpl adapter) { + this.adapter = adapter; } @Override protected IEngineContext createEngineContext(ViatraQueryEngine engine, IIndexingErrorListener errorListener, Logger logger) { - return new RelationalEngineContext(model, relationViews); + return new RelationalEngineContext(adapter); } } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryAdapterImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryAdapterImpl.java index 810d2c32..039f46fa 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryAdapterImpl.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryAdapterImpl.java @@ -8,15 +8,17 @@ import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackend; import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendFactory; import tools.refinery.store.model.Model; import tools.refinery.store.query.DNF; -import tools.refinery.store.query.ModelQueryAdapter; -import tools.refinery.store.query.ModelQueryStoreAdapter; import tools.refinery.store.query.ResultSet; +import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; -import java.util.*; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; -public class ViatraModelQueryAdapterImpl implements ModelQueryAdapter { +public class ViatraModelQueryAdapterImpl implements ViatraModelQueryAdapter { private static final String DELAY_MESSAGE_DELIVERY_FIELD_NAME = "delayMessageDelivery"; private static final String QUERY_BACKENDS_FIELD_NAME = "queryBackends"; @@ -26,11 +28,12 @@ public class ViatraModelQueryAdapterImpl implements ModelQueryAdapter { private final MethodHandle setUpdatePropagationDelayedHandle; private final MethodHandle getQueryBackendsHandle; private final Map resultSets; + private boolean pendingChanges; ViatraModelQueryAdapterImpl(Model model, ViatraModelQueryStoreAdapterImpl storeAdapter) { this.model = model; this.storeAdapter = storeAdapter; - var scope = new RelationalScope(model, storeAdapter.getInputKeys()); + var scope = new RelationalScope(this); queryEngine = (ViatraQueryEngineImpl) AdvancedViatraQueryEngine.createUnmanagedEngine(scope); try { @@ -87,7 +90,7 @@ public class ViatraModelQueryAdapterImpl implements ModelQueryAdapter { } @Override - public ModelQueryStoreAdapter getStoreAdapter() { + public ViatraModelQueryStoreAdapterImpl getStoreAdapter() { return storeAdapter; } @@ -100,11 +103,25 @@ public class ViatraModelQueryAdapterImpl implements ModelQueryAdapter { return resultSet; } + @Override + public boolean hasPendingChanges() { + return pendingChanges; + } + + public void markAsPending() { + if (!pendingChanges) { + pendingChanges = true; + } + } + @Override public void flushChanges() { if (!queryEngine.isUpdatePropagationDelayed()) { throw new IllegalStateException("Trying to flush changes while changes are already being flushed"); } + if (!pendingChanges) { + return; + } setUpdatePropagationDelayed(false); try { for (var queryBackend : getQueryBackends()) { @@ -113,5 +130,6 @@ public class ViatraModelQueryAdapterImpl implements ModelQueryAdapter { } finally { setUpdatePropagationDelayed(true); } + pendingChanges = false; } } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryStoreAdapterImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryStoreAdapterImpl.java index 69f1f146..394e407e 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryStoreAdapterImpl.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryStoreAdapterImpl.java @@ -37,7 +37,7 @@ public class ViatraModelQueryStoreAdapterImpl implements ViatraModelQueryStoreAd return inputKeys.keySet(); } - Map getInputKeys() { + public Map getInputKeys() { return inputKeys; } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalEngineContext.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalEngineContext.java index 3bad01b9..28bc69d0 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalEngineContext.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalEngineContext.java @@ -2,19 +2,15 @@ package tools.refinery.store.query.viatra.internal.context; import org.eclipse.viatra.query.runtime.api.scope.IBaseIndex; import org.eclipse.viatra.query.runtime.api.scope.IEngineContext; -import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext; -import tools.refinery.store.model.Model; -import tools.refinery.store.query.view.AnyRelationView; - -import java.util.Map; +import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; public class RelationalEngineContext implements IEngineContext { private final IBaseIndex baseIndex = new DummyBaseIndexer(); private final RelationalRuntimeContext runtimeContext; - public RelationalEngineContext(Model model, Map< AnyRelationView, IInputKey> inputKeys) { - runtimeContext = new RelationalRuntimeContext(model, inputKeys); + public RelationalEngineContext(ViatraModelQueryAdapterImpl adapter) { + runtimeContext = new RelationalRuntimeContext(adapter); } @Override diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java index 71ab5cb4..01d20d3e 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java @@ -7,13 +7,13 @@ import org.eclipse.viatra.query.runtime.matchers.tuple.TupleMask; import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; import org.eclipse.viatra.query.runtime.matchers.util.Accuracy; import tools.refinery.store.model.Model; +import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; import tools.refinery.store.query.viatra.internal.pquery.RelationViewWrapper; import tools.refinery.store.query.viatra.internal.update.ModelUpdateListener; import tools.refinery.store.query.view.AnyRelationView; import java.lang.reflect.InvocationTargetException; import java.util.Iterator; -import java.util.Map; import java.util.Optional; import java.util.concurrent.Callable; @@ -27,10 +27,10 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext { private final Model model; - RelationalRuntimeContext(Model model, Map inputKeys) { - this.model = model; - metaContext = new RelationalQueryMetaContext(inputKeys); - modelUpdateListener = new ModelUpdateListener(model, inputKeys.keySet()); + RelationalRuntimeContext(ViatraModelQueryAdapterImpl adapter) { + model = adapter.getModel(); + metaContext = new RelationalQueryMetaContext(adapter.getStoreAdapter().getInputKeys()); + modelUpdateListener = new ModelUpdateListener(adapter); } @Override diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java index 1ae3daa7..8a467066 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java @@ -3,26 +3,27 @@ package tools.refinery.store.query.viatra.internal.update; import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener; import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; -import tools.refinery.store.model.Model; +import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; import tools.refinery.store.query.view.AnyRelationView; import tools.refinery.store.query.view.RelationView; -import java.util.Collection; import java.util.HashMap; import java.util.Map; public class ModelUpdateListener { private final Map> relationViewUpdateListeners; - public ModelUpdateListener(Model model, Collection relationViews) { + public ModelUpdateListener(ViatraModelQueryAdapterImpl adapter) { + var relationViews = adapter.getStoreAdapter().getInputKeys().keySet(); relationViewUpdateListeners = new HashMap<>(relationViews.size()); for (var relationView : relationViews) { - registerView(model, (RelationView) relationView); + registerView(adapter, (RelationView) relationView); } } - private void registerView(Model model, RelationView relationView) { - var listener = RelationViewUpdateListener.of(relationView); + private void registerView(ViatraModelQueryAdapterImpl adapter, RelationView relationView) { + var listener = RelationViewUpdateListener.of(adapter, relationView); + var model = adapter.getModel(); var interpretation = model.getInterpretation(relationView.getSymbol()); interpretation.addListener(listener, true); relationViewUpdateListeners.put(relationView, listener); diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewUpdateListener.java index e0d44e34..bf6b4197 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewUpdateListener.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewUpdateListener.java @@ -5,6 +5,7 @@ import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextLis import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple; import tools.refinery.store.model.InterpretationListener; +import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; import tools.refinery.store.query.view.RelationView; import tools.refinery.store.query.view.TuplePreservingRelationView; @@ -12,8 +13,13 @@ import java.util.ArrayList; import java.util.List; public abstract class RelationViewUpdateListener implements InterpretationListener { + private final ViatraModelQueryAdapterImpl adapter; private final List filters = new ArrayList<>(); + protected RelationViewUpdateListener(ViatraModelQueryAdapterImpl adapter) { + this.adapter = adapter; + } + public void addFilter(IInputKey inputKey, ITuple seed, IQueryRuntimeContextListener listener) { filters.add(new RelationViewFilter(inputKey, seed, listener)); } @@ -23,6 +29,7 @@ public abstract class RelationViewUpdateListener implements InterpretationLis } protected void processUpdate(Tuple tuple, boolean isInsertion) { + adapter.markAsPending(); int size = filters.size(); // Use a for loop instead of a for-each loop to avoid Iterator allocation overhead. //noinspection ForLoopReplaceableByForEach @@ -31,10 +38,11 @@ public abstract class RelationViewUpdateListener implements InterpretationLis } } - public static RelationViewUpdateListener of(RelationView relationView) { + public static RelationViewUpdateListener of(ViatraModelQueryAdapterImpl adapter, + RelationView relationView) { if (relationView instanceof TuplePreservingRelationView tuplePreservingRelationView) { - return new TuplePreservingRelationViewUpdateListener<>(tuplePreservingRelationView); + return new TuplePreservingRelationViewUpdateListener<>(adapter, tuplePreservingRelationView); } - return new TupleChangingRelationViewUpdateListener<>(relationView); + return new TupleChangingRelationViewUpdateListener<>(adapter, relationView); } } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java index 0d43eac1..14142884 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java @@ -1,6 +1,7 @@ package tools.refinery.store.query.viatra.internal.update; import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; +import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; import tools.refinery.store.query.view.RelationView; import tools.refinery.store.tuple.Tuple; @@ -9,8 +10,9 @@ import java.util.Arrays; public class TupleChangingRelationViewUpdateListener extends RelationViewUpdateListener { private final RelationView relationView; - TupleChangingRelationViewUpdateListener(RelationView relationView) { - this.relationView = relationView; + TupleChangingRelationViewUpdateListener(ViatraModelQueryAdapterImpl adapter, RelationView relationView) { + super(adapter); + this.relationView = relationView; } @Override diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingRelationViewUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingRelationViewUpdateListener.java index 9c3ef61c..288e018a 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingRelationViewUpdateListener.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingRelationViewUpdateListener.java @@ -1,14 +1,17 @@ package tools.refinery.store.query.viatra.internal.update; import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; +import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; import tools.refinery.store.query.view.TuplePreservingRelationView; import tools.refinery.store.tuple.Tuple; public class TuplePreservingRelationViewUpdateListener extends RelationViewUpdateListener { private final TuplePreservingRelationView view; - TuplePreservingRelationViewUpdateListener(TuplePreservingRelationView view) { - this.view = view; + TuplePreservingRelationViewUpdateListener(ViatraModelQueryAdapterImpl adapter, + TuplePreservingRelationView view) { + super(adapter); + this.view = view; } @Override diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java index 49087a8d..ec2e7647 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java @@ -10,7 +10,7 @@ import tools.refinery.store.query.view.KeyOnlyRelationView; import tools.refinery.store.representation.Symbol; import tools.refinery.store.tuple.Tuple; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.*; class QueryTransactionTest { @Test @@ -38,6 +38,7 @@ class QueryTransactionTest { var predicateResultSet = queryEngine.getResultSet(predicate); assertEquals(0, predicateResultSet.countResults()); + assertFalse(queryEngine.hasPendingChanges()); personInterpretation.put(Tuple.of(0), true); personInterpretation.put(Tuple.of(1), true); @@ -46,14 +47,18 @@ class QueryTransactionTest { assetInterpretation.put(Tuple.of(2), true); assertEquals(0, predicateResultSet.countResults()); + assertTrue(queryEngine.hasPendingChanges()); queryEngine.flushChanges(); assertEquals(2, predicateResultSet.countResults()); + assertFalse(queryEngine.hasPendingChanges()); personInterpretation.put(Tuple.of(4), true); assertEquals(2, predicateResultSet.countResults()); + assertTrue(queryEngine.hasPendingChanges()); queryEngine.flushChanges(); assertEquals(3, predicateResultSet.countResults()); + assertFalse(queryEngine.hasPendingChanges()); } } diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java b/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java index d0cdf02d..7449e39b 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java +++ b/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java @@ -7,5 +7,7 @@ public interface ModelQueryAdapter extends ModelAdapter { ResultSet getResultSet(DNF query); + boolean hasPendingChanges(); + void flushChanges(); } -- cgit v1.2.3-54-g00ecf