From 1f4133242efdb193390d76b0952ade00a3a88309 Mon Sep 17 00:00:00 2001 From: Antti Villberg Date: Sun, 8 Mar 2020 21:41:04 +0200 Subject: [PATCH] AsyncBarrier.dec runs into refcounting problem gitlab #490 Change-Id: I47b3e917a11038b444a326f03b46352d5671cbe0 --- .../common/request/TransientResourceRead.java | 70 ++++++----- .../db/impl/BlockingAsyncProcedure.java | 42 ++++--- .../db/impl/graph/AsyncBarrierImpl.java | 6 +- .../db/impl/graph/ReadGraphImpl.java | 118 ++++++++---------- .../db/impl/query/QueryListening.java | 2 +- .../db/impl/query/QueryProcessor.java | 3 +- .../layer0/genericrelation/Dependencies.java | 14 ++- .../genericrelation/DependencyResources.java | 14 ++- .../procore/internal/QueryControlImpl.java | 12 ++ .../procore/internal/SessionImplSocket.java | 53 +++----- .../vtt/simantics/procore/internal/State.java | 6 +- .../simantics/db/service/QueryControl.java | 15 +++ 12 files changed, 187 insertions(+), 168 deletions(-) diff --git a/bundles/org.simantics.db.common/src/org/simantics/db/common/request/TransientResourceRead.java b/bundles/org.simantics.db.common/src/org/simantics/db/common/request/TransientResourceRead.java index 117a1a27f..73e612a9f 100644 --- a/bundles/org.simantics.db.common/src/org/simantics/db/common/request/TransientResourceRead.java +++ b/bundles/org.simantics.db.common/src/org/simantics/db/common/request/TransientResourceRead.java @@ -19,37 +19,41 @@ import org.simantics.db.service.QueryControl; abstract public class TransientResourceRead extends BinaryRead implements ReadExt { - protected static final Object WITH_PARENT = new Object(); - - public TransientResourceRead(ReadGraph graph, Resource parameter) throws DatabaseException { - this(graph, graph.getService(QueryControl.class), parameter); - } - - public TransientResourceRead(ReadGraph graph, QueryControl qc, Resource parameter) throws DatabaseException { - super(resolveFirstParameter(graph, qc), parameter); - } - - final private static Object resolveFirstParameter(ReadGraph graph, QueryControl qc) throws DatabaseException { - if(qc.hasParentRequest(graph)) return WITH_PARENT; - else return graph.getModificationCounter(); - } - - @Override - final public R perform(ReadGraph _graph) throws DatabaseException { - if(parameter == WITH_PARENT) { - return perform(_graph, parameter2); - } else { - QueryControl qc = _graph.getService(QueryControl.class); - ReadGraph graph = qc.getIndependentGraph(_graph); - return perform(graph, parameter2); - } - } - - abstract public R perform(ReadGraph graph, Resource parameter) throws DatabaseException; - - @Override - public boolean isImmutable(ReadGraph graph) throws DatabaseException { - return graph.isImmutable(parameter2); - } - + protected static final Object WITH_PARENT = new Object(); + + public TransientResourceRead(ReadGraph graph, Resource parameter) throws DatabaseException { + this(graph, graph.getService(QueryControl.class), parameter); + } + + public TransientResourceRead(ReadGraph graph, QueryControl qc, Resource parameter) throws DatabaseException { + super(resolveFirstParameter(graph, qc), parameter); + } + + final private static Object resolveFirstParameter(ReadGraph graph, QueryControl qc) throws DatabaseException { + if(qc.hasParentRequest(graph)) return WITH_PARENT; + else return graph.getModificationCounter(); + } + + @Override + final public R perform(ReadGraph _graph) throws DatabaseException { + if(parameter == WITH_PARENT) { + return perform(_graph, parameter2); + } else { + QueryControl qc = _graph.getService(QueryControl.class); + return qc.syncRequestIndependent(_graph, new UniqueRead() { + @Override + public R perform(ReadGraph graph) throws DatabaseException { + return TransientResourceRead.this.perform(graph, parameter2); + } + }); + } + } + + abstract public R perform(ReadGraph graph, Resource parameter) throws DatabaseException; + + @Override + public boolean isImmutable(ReadGraph graph) throws DatabaseException { + return graph.isImmutable(parameter2); + } + } diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/BlockingAsyncProcedure.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/BlockingAsyncProcedure.java index 8f96bb9e6..9f89a0d8f 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/BlockingAsyncProcedure.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/BlockingAsyncProcedure.java @@ -19,34 +19,31 @@ import org.simantics.db.impl.query.AsyncReadEntry; import org.simantics.db.impl.query.PendingTaskSupport; import org.simantics.db.procedure.AsyncProcedure; import org.simantics.db.request.AsyncRead; -public class BlockingAsyncProcedure implements AsyncProcedure { + +public class BlockingAsyncProcedure implements AsyncProcedure, Runnable { private static final Object NO_RESULT = new Object(); private final Object key; private final ReadGraphImpl queryGraph; private final ReadGraphImpl callerGraph; + private final AsyncReadEntry entry; private final AsyncProcedure procedure; private PendingTaskSupport pendingTaskSupport; private final boolean needsToBlock; private Object result = NO_RESULT; private Throwable exception = null; - - private ReadGraphImpl queryGraph() { - return queryGraph; - } public BlockingAsyncProcedure(ReadGraphImpl callerGraph, AsyncReadEntry entry, AsyncProcedure procedure, Object key, boolean needsToBlock) { // A new graph for evaluating the query with correct parent and asyncBarrier - queryGraph = callerGraph.withParent(entry, () -> { - - dispatchProcedure(queryGraph(), callerGraph, entry, procedure, needsToBlock); - - }, needsToBlock); - + queryGraph = callerGraph.withParent(entry, this, needsToBlock); queryGraph.asyncBarrier.inc(); + + // This makes sure that caller does not quit before dispatch + callerGraph.asyncBarrier.inc(); + this.entry = entry; this.procedure = procedure; this.key = key; this.queryGraph.asyncBarrier.inc(); @@ -112,34 +109,39 @@ public class BlockingAsyncProcedure implements AsyncProcedure { return "." + procedure; } - private void dispatchProcedure(ReadGraphImpl queryGraph, ReadGraphImpl parentGraph, AsyncReadEntry entry, AsyncProcedure procedure_, boolean needsToBlock) { + @Override + public void run() { - AsyncProcedure procedure = entry != null ? entry : procedure_; + AsyncProcedure procedure__ = entry != null ? entry : procedure; - ReadGraphImpl executeGraph = parentGraph.withParent(parentGraph.parent, null, needsToBlock); + ReadGraphImpl executeGraph = callerGraph.withParent(callerGraph.parent, null, needsToBlock); executeGraph.asyncBarrier.inc(); + + // This counters the inc in the constructor + callerGraph.asyncBarrier.dec(); + try { - if(procedure != null) { - procedure.execute(executeGraph, get()); + if(procedure__ != null) { + procedure__.execute(executeGraph, get()); } } catch (DatabaseException e) { - if(procedure != null) procedure.exception(executeGraph, e); + if(procedure__ != null) procedure__.exception(executeGraph, e); exception = e; } catch (Throwable t) { DatabaseException dbe = new DatabaseException(t); - if(procedure != null) procedure.exception(executeGraph, dbe); + if(procedure__ != null) procedure__.exception(executeGraph, dbe); exception = dbe; } finally { if (entry != null) { assert(entry.isReady()); // This does not throw - entry.performFromCache(executeGraph, procedure_); + entry.performFromCache(executeGraph, procedure); } executeGraph.asyncBarrier.dec(); if(needsToBlock) - executeGraph.asyncBarrier.waitBarrier(procedure, executeGraph); + executeGraph.asyncBarrier.waitBarrier(procedure__, executeGraph); } if (BarrierTracing.BOOKKEEPING) { diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/AsyncBarrierImpl.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/AsyncBarrierImpl.java index 637db3f26..f1e5b5cce 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/AsyncBarrierImpl.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/AsyncBarrierImpl.java @@ -14,13 +14,15 @@ package org.simantics.db.impl.graph; import java.util.Collection; import java.util.concurrent.atomic.AtomicInteger; -import org.simantics.db.common.utils.Logger; import org.simantics.db.exception.RuntimeDatabaseException; import org.simantics.db.impl.query.CacheEntry; import org.simantics.db.impl.query.QueryProcessor.AsyncBarrier; +import org.slf4j.LoggerFactory; public class AsyncBarrierImpl extends AtomicInteger implements AsyncBarrier { + private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(AsyncBarrierImpl.class); + private static final long serialVersionUID = 4724463372850048672L; static final int WAIT_TIME = 60000; @@ -107,7 +109,7 @@ public class AsyncBarrierImpl extends AtomicInteger implements AsyncBarrier { } } if (count < 0) { - Logger.defaultLogError( + LOGGER.error( "Database request processing error. The application code has performed illegal actions (probably called multiple times the execute or exception method of a single result request.", new Exception()); } diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/ReadGraphImpl.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/ReadGraphImpl.java index 48662d190..110e1d59b 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/ReadGraphImpl.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/ReadGraphImpl.java @@ -188,8 +188,6 @@ import org.simantics.utils.DataContainer; import org.simantics.utils.Development; import org.simantics.utils.datastructures.Pair; import org.simantics.utils.datastructures.collections.CollectionUtils; -import org.simantics.utils.threads.logger.ITask; -import org.simantics.utils.threads.logger.ThreadLogger; import org.slf4j.LoggerFactory; import gnu.trove.map.hash.TObjectIntHashMap; @@ -1922,14 +1920,11 @@ public class ReadGraphImpl implements AsyncReadGraph { * Implementation of the interface RequestProcessor */ - @Override - public T syncRequest(final Read request) throws DatabaseException { - assert (request != null); - - T result = (T)QueryCache.runnerReadEntry(this, request, parent, null, null, true); - return result; - - } + @Override + public T syncRequest(final Read request) throws DatabaseException { + assert (request != null); + return (T)QueryCache.runnerReadEntry(this, request, parent, null, null, true); + } @Override public T syncRequest(Read request, SyncListener procedure) @@ -1943,16 +1938,12 @@ public class ReadGraphImpl implements AsyncReadGraph { return syncRequest(request, new NoneToAsyncListener(procedure)); } - @Override - public T syncRequest(final Read request, final AsyncProcedure procedure) throws DatabaseException { - - assert (request != null); - - ListenerBase listener = procedure != null ? getListenerBase(procedure) : null; - T result = (T)QueryCache.runnerReadEntry(this, request, parent, listener, procedure, true); - return result; - - } + @Override + public T syncRequest(final Read request, final AsyncProcedure procedure) throws DatabaseException { + assert (request != null); + ListenerBase listener = procedure != null ? getListenerBase(procedure) : null; + return (T)QueryCache.runnerReadEntry(this, request, parent, listener, procedure, true); + } @Override public T syncRequest(final Read request, @@ -2028,17 +2019,13 @@ public class ReadGraphImpl implements AsyncReadGraph { return syncRequest(request, new NoneToAsyncListener(procedure)); } - @Override - final public T syncRequest(final AsyncRead request, - final AsyncProcedure procedure) throws DatabaseException { - - assert (request != null); - - ListenerBase listener = getListenerBase(procedure); - T result = (T)QueryCache.runnerAsyncReadEntry(this, request, parent, listener, procedure, true); - return result; - - } + @Override + final public T syncRequest(final AsyncRead request, + final AsyncProcedure procedure) throws DatabaseException { + assert (request != null); + ListenerBase listener = getListenerBase(procedure); + return (T)QueryCache.runnerAsyncReadEntry(this, request, parent, listener, procedure, true); + } @Override public T syncRequest(AsyncRead request, @@ -5235,54 +5222,55 @@ public class ReadGraphImpl implements AsyncReadGraph { asyncRequest(request, new NoneToAsyncListener(procedure)); } - @Override - final public void asyncRequest(final AsyncRead request, - final AsyncProcedure procedure) { + @Override + final public void asyncRequest(final AsyncRead request, + final AsyncProcedure procedure) { - assert (request != null); - assert (procedure != null); + assert (request != null); + assert (procedure != null); AsyncBarrierImpl barrier = asyncBarrier; if(barrier != null) barrier.inc(); - processor.scheduleNow(new SessionTask(this) { + processor.scheduleNow(new SessionTask(this) { - @Override - public void run0(int thread) { + @Override + public void run0(int thread) { - if(barrier != null) - barrier.inc(); + if(barrier != null) + barrier.inc(); - try { - final ListenerBase listener = getListenerBase(procedure); - QueryCache.runnerAsyncReadEntry(ReadGraphImpl.this, request, parent, listener, new AsyncProcedure() { + try { + final ListenerBase listener = getListenerBase(procedure); + QueryCache.runnerAsyncReadEntry(ReadGraphImpl.this, request, parent, listener, new AsyncProcedure() { - @Override - public void execute(AsyncReadGraph graph, T result) { - procedure.execute(graph, result); - if(barrier != null) - barrier.dec(); - } + @Override + public void execute(AsyncReadGraph graph, T result) { + procedure.execute(graph, result); + if(barrier != null) + barrier.dec(); + } - @Override - public void exception(AsyncReadGraph graph, Throwable throwable) { - procedure.exception(graph, throwable); + @Override + public void exception(AsyncReadGraph graph, Throwable throwable) { + procedure.exception(graph, throwable); if(barrier != null) barrier.dec(); - } - - }, false); - if(barrier != null) - barrier.dec(); - } catch (DatabaseException e) { - Logger.defaultLogError(e); - } - } - - }); + } + + }, false); + } catch (DatabaseException e) { + LOGGER.error("Error while executing async request", e); + } finally { + if(barrier != null) + barrier.dec(); + } + } - } + }); + + } @Override public void asyncRequest(AsyncRead request, diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryListening.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryListening.java index dd410b4ce..e3bd43741 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryListening.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryListening.java @@ -413,7 +413,7 @@ public class QueryListening { } - public void fireListeners(WriteGraphImpl graph) { + public void fireListeners(ReadGraphImpl graph) { assert (!processor.updating); assert (!processor.cache.collecting); diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryProcessor.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryProcessor.java index a46bc0e8d..6345b7375 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryProcessor.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryProcessor.java @@ -1279,8 +1279,9 @@ final public class QueryProcessor extends AbstractDisposable implements ReadGrap entry.prepareRecompute(querySupport); ReadGraphImpl parentGraph = graph.forRecompute(entry); - + parentGraph.asyncBarrier.inc(); query.recompute(parentGraph); + parentGraph.asyncBarrier.dec(); if(entry.isExcepted()) return ListenerEntry.NO_VALUE; diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/genericrelation/Dependencies.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/genericrelation/Dependencies.java index 0aa36390b..83837a960 100644 --- a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/genericrelation/Dependencies.java +++ b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/genericrelation/Dependencies.java @@ -13,13 +13,14 @@ package org.simantics.db.layer0.genericrelation; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; -import org.simantics.db.common.utils.Logger; +import org.simantics.db.common.request.UniqueRead; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.adapter.GenericRelationIndex; import org.simantics.db.service.QueryControl; import org.simantics.operation.Layer0X; import org.simantics.scl.runtime.function.FunctionImpl4; import org.simantics.scl.runtime.function.UnsaturatedFunction2; +import org.slf4j.LoggerFactory; /** * dependencies: @@ -30,6 +31,8 @@ import org.simantics.scl.runtime.function.UnsaturatedFunction2; */ public class Dependencies extends FunctionImpl4 { + private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(Dependencies.class); + public static final String FIELD_MODEL = "Model"; public static final String FIELD_PARENT = "Parent"; public static final String FIELD_RESOURCE = "Resource"; @@ -71,10 +74,15 @@ public class Dependencies extends FunctionImpl4() { + @Override + public Object perform(ReadGraph graph) throws DatabaseException { + return index.query(graph, query, getBindingPattern(), new Object[] { model }, maxResults); + } + }); } catch (DatabaseException e) { - Logger.defaultLogError(e); + LOGGER.error("Error while performing index query", e); return null; } } diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/genericrelation/DependencyResources.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/genericrelation/DependencyResources.java index 1702af0f3..a2059a6ad 100644 --- a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/genericrelation/DependencyResources.java +++ b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/genericrelation/DependencyResources.java @@ -13,13 +13,14 @@ package org.simantics.db.layer0.genericrelation; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; -import org.simantics.db.common.utils.Logger; +import org.simantics.db.common.request.UniqueRead; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.adapter.GenericRelationIndex; import org.simantics.db.service.QueryControl; import org.simantics.operation.Layer0X; import org.simantics.scl.runtime.function.FunctionImpl4; import org.simantics.scl.runtime.function.UnsaturatedFunction2; +import org.slf4j.LoggerFactory; /** * dependencyResources: @@ -30,6 +31,8 @@ import org.simantics.scl.runtime.function.UnsaturatedFunction2; */ public class DependencyResources extends FunctionImpl4 { + private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(DependencyResources.class); + protected Resource getIndexRelation(ReadGraph graph) { return Layer0X.getInstance(graph).DependenciesRelation; } @@ -61,10 +64,15 @@ public class DependencyResources extends FunctionImpl4() { + @Override + public Object perform(ReadGraph graph) throws DatabaseException { + return index.queryResources(graph, query, getBindingPattern(), new Object[] { model }, maxResults); + } + }); } catch (DatabaseException e) { - Logger.defaultLogError(e); + LOGGER.error("Error while performing index query", e); return null; } } diff --git a/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/QueryControlImpl.java b/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/QueryControlImpl.java index 53a3dc1ad..f5e55deaa 100644 --- a/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/QueryControlImpl.java +++ b/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/QueryControlImpl.java @@ -13,6 +13,7 @@ import org.simantics.db.impl.graph.ReadGraphImpl; import org.simantics.db.procedure.AsyncContextMultiProcedure; import org.simantics.db.procedure.AsyncMultiProcedure; import org.simantics.db.request.ExternalRead; +import org.simantics.db.request.Read; import org.simantics.db.service.QueryControl; import org.simantics.utils.DataContainer; import org.slf4j.Logger; @@ -145,6 +146,17 @@ public class QueryControlImpl implements QueryControl { ReadGraphImpl impl = (ReadGraphImpl)graph; return impl.withParent(null, null, false); } + + @Override + public T syncRequestIndependent(ReadGraph graph, Read request) throws DatabaseException { + ReadGraphImpl independent = ((ReadGraphImpl)graph).withParent(null, null, false); + independent.asyncBarrier.inc(); + try { + return independent.syncRequest(request); + } finally { + independent.asyncBarrier.dec(); + } + } @Override public boolean hasParentRequest(ReadGraph graph) { diff --git a/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/SessionImplSocket.java b/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/SessionImplSocket.java index 22d0f3165..f8fd7d17d 100644 --- a/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/SessionImplSocket.java +++ b/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/SessionImplSocket.java @@ -461,7 +461,7 @@ public abstract class SessionImplSocket implements Session, WriteRequestSchedule }); assert (null != writer); -// writer.state.barrier.inc(); + writer.asyncBarrier.inc(); try { request.perform(writer); @@ -471,7 +471,7 @@ public abstract class SessionImplSocket implements Session, WriteRequestSchedule Logger.defaultLogError("Write transaction caused an unexpected error, see exception.", t); writeState.except(t); } finally { -// writer.state.barrier.dec(); + writer.asyncBarrier.dec(); // writer.waitAsync(request); } @@ -571,52 +571,21 @@ public abstract class SessionImplSocket implements Session, WriteRequestSchedule VirtualGraph vg = getProvider(request.getProvider()); WriteGraphImpl writer = WriteGraphImpl.create(getQueryProvider2(), writeSupport, vg); - try { - WriteState writeStateT = new WriteState(writer, request, notify, procedure); - writeState = writeStateT; + WriteState writeStateT = new WriteState(writer, request, notify, procedure); + writeState = writeStateT; + assert (null != writer); - assert (null != writer); -// writer.state.barrier.inc(); + try { + writer.asyncBarrier.inc(); writeStateT.setResult(request.perform(writer)); assert (null != writer); - -// writer.state.barrier.dec(); -// writer.waitAsync(null); - } catch (Throwable e) { - -// writer.state.barrier.dec(); -// writer.waitAsync(null); - writeState.except(e); - -// state.stopWriteTransaction(clusterStream); -// -// } catch (Throwable e) { -// // Log it first, just to be safe that the error is always logged. -// Logger.defaultLogError("Write transaction caused an unexpected error, see exception.", e); -// -// try { -// // Callback is client code, we have to be prepared for it to throw unexpected exceptions. -// // All we can do here is to log those, can't really pass them anywhere. -// if (procedure != null) { -// if(e instanceof DatabaseException) procedure.exception((DatabaseException)e); -// else procedure.exception(new DatabaseException(e)); -// } -// } catch (Throwable e2) { -// Logger.defaultLogError("Write request callback caused an unexpected error, see exception.", e2); -// } -// -// clientChanges = new ClientChangesImpl(SessionImplSocket.this); -// -// state.stopWriteTransaction(clusterStream); - } finally { + writer.asyncBarrier.dec(); fireSessionVariableChange(SessionVariables.QUEUED_WRITES); } -// if(notify != null) notify.release(); - task.finish(); } @@ -1626,6 +1595,7 @@ public abstract class SessionImplSocket implements Session, WriteRequestSchedule ITask task = ThreadLogger.task(request); final ReadGraphImpl newGraph = ReadGraphImpl.create(getQueryProvider2()); + newGraph.asyncBarrier.inc(); try { @@ -1663,6 +1633,8 @@ public abstract class SessionImplSocket implements Session, WriteRequestSchedule } finally { + newGraph.asyncBarrier.dec(); + fireSessionVariableChange(SessionVariables.QUEUED_READS); } @@ -2479,6 +2451,7 @@ public abstract class SessionImplSocket implements Session, WriteRequestSchedule return; WriteGraphImpl reactionGraph = WriteGraphImpl.create(graph.processor, writeSupport, null); + reactionGraph.asyncBarrier.inc(); try { @@ -2493,6 +2466,8 @@ public abstract class SessionImplSocket implements Session, WriteRequestSchedule } finally { + reactionGraph.asyncBarrier.dec(); + } } catch (Throwable t) { diff --git a/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/State.java b/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/State.java index 4c6e77b1a..1e468f2c3 100644 --- a/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/State.java +++ b/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/State.java @@ -24,6 +24,7 @@ import org.simantics.db.common.utils.Logger; import org.simantics.db.exception.DatabaseException; import org.simantics.db.exception.InternalException; import org.simantics.db.exception.RuntimeDatabaseException; +import org.simantics.db.impl.graph.ReadGraphImpl; import org.simantics.db.impl.graph.WriteGraphImpl; import org.simantics.db.impl.query.QueryProcessor; import org.simantics.db.request.WriteOnly; @@ -340,7 +341,10 @@ class State { // start = System.nanoTime(); queryProvider.propagateChangesInQueryCache(graph); - queryProvider.listening.fireListeners(graph); + ReadGraphImpl listenerGraph = graph.forRecompute(null); + listenerGraph.asyncBarrier.inc(); + queryProvider.listening.fireListeners(listenerGraph); + listenerGraph.asyncBarrier.dec(); // duration = System.nanoTime() - start; // System.out.println("performScheduledUpdates " + 1e-9*duration + "s. "); diff --git a/bundles/org.simantics.db/src/org/simantics/db/service/QueryControl.java b/bundles/org.simantics.db/src/org/simantics/db/service/QueryControl.java index 3da3c5aa3..a8c728643 100644 --- a/bundles/org.simantics.db/src/org/simantics/db/service/QueryControl.java +++ b/bundles/org.simantics.db/src/org/simantics/db/service/QueryControl.java @@ -17,9 +17,11 @@ import org.simantics.db.AsyncReadGraph; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.WriteGraph; +import org.simantics.db.exception.DatabaseException; import org.simantics.db.procedure.AsyncContextMultiProcedure; import org.simantics.db.procedure.AsyncMultiProcedure; import org.simantics.db.request.ExternalRead; +import org.simantics.db.request.Read; /** @@ -87,12 +89,25 @@ public interface QueryControl { * performed with the specified ReadGraph. DB listeners are therefore not * triggered by anything that is performed with the returned ReadGraph. * + * @Deprecated In favor of syncRequestIndependent * @param graph read transaction handle to clone for listener-independent * use * @return read transaction handle that is independent of the requests * performed with the parameter */ ReadGraph getIndependentGraph(ReadGraph graph); + + /** + * Performs the given request without accumulating query dependencies. + * DB listeners are therefore not triggered by anything that is performed within the request. + * + * @param graph read transaction handle to clone for listener-independent + * use + * @param request the request to perform + * @return the result of the request evaluation + */ + T syncRequestIndependent(ReadGraph graph, Read request) throws DatabaseException; + boolean hasParentRequest(ReadGraph graph); } -- 2.47.1