From: Jussi Koskela Date: Wed, 2 Sep 2020 09:17:31 +0000 (+0300) Subject: Fixed multiple issues causing dangling references to discarded queries X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=commitdiff_plain;h=HEAD;hp=6c6f34dda4dfa90bc403e1c525a84e17c17c0cde Fixed multiple issues causing dangling references to discarded queries gitlab #594 Change-Id: Iaa6b12f60d7dfa2bbcbc9614ef837973885586cc --- diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/CacheEntry.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/CacheEntry.java index edb087025..a650f32ce 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/CacheEntry.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/CacheEntry.java @@ -42,6 +42,7 @@ public abstract class CacheEntry { abstract Query getQuery(); abstract CacheEntry pruneFirstParents(); + abstract void pruneParentSet(); abstract void removeParent(CacheEntry entry); abstract void addParent(CacheEntry entry); abstract boolean hasParents(); diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/CacheEntryBase.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/CacheEntryBase.java index 56da11ace..98e7f0d00 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/CacheEntryBase.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/CacheEntryBase.java @@ -278,7 +278,31 @@ public abstract class CacheEntryBase extends CacheEntry { } } - + + @Override + void pruneParentSet() { + // First parent is discarded => look for more parents + if(p2OrParents instanceof QueryIdentityHashSet) { + + QueryIdentityHashSet set = (QueryIdentityHashSet)p2OrParents; + set.removeDiscardedReally(); + if(set.isEmpty()) p2OrParents = null; + + } else if(p2OrParents instanceof CacheEntry) { + + CacheEntry entry = (CacheEntry)p2OrParents; + if(entry.isDiscarded()) { + // Second entry is also discarded => all empty + p2OrParents = null; + } + + } else { + + // Nothing left + + } + } + @Override final public void removeParent(CacheEntry entry) { diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/ExternalReadEntry.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/ExternalReadEntry.java index 6253744bb..2980b9b15 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/ExternalReadEntry.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/ExternalReadEntry.java @@ -28,7 +28,7 @@ final public class ExternalReadEntry extends CacheEntryBase final LinkedList items = new LinkedList(); protected ExternalRead id; - protected ReadGraphImpl graph; + protected QueryProcessor processor; protected boolean registered = false; @Override @@ -49,7 +49,7 @@ final public class ExternalReadEntry extends CacheEntryBase public void discard() { id.unregistered(); id = null; - graph = null; + processor = null; super.discard(); } @@ -65,7 +65,7 @@ final public class ExternalReadEntry extends CacheEntryBase public ExternalReadEntry(ExternalRead request, ReadGraphImpl graph) { assert request != null; this.id = request; - this.graph = graph; + this.processor = graph.processor; } @Override @@ -213,7 +213,7 @@ final public class ExternalReadEntry extends CacheEntryBase synchronized(items) { items.addLast(result); - graph.processor.updatePrimitive(id); + processor.updatePrimitive(id); // TODO: implement flags/logic in ExternalRead to state that all but the latest request result can be evaporated // In some cases where data is produced really fast this might be necessary but currently this queueing will do. } @@ -229,7 +229,7 @@ final public class ExternalReadEntry extends CacheEntryBase @Override public boolean isDisposed() { - return registered && (isDiscarded() || !graph.processor.isBound(this)); + return registered && (isDiscarded() || !processor.isBound(this)); } @Override diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCollectorImpl.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCollectorImpl.java index 0b6f6ef83..e6dc252c4 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCollectorImpl.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCollectorImpl.java @@ -148,6 +148,7 @@ class QueryCollectorImpl implements QueryProcessor.QueryCollector { } else { + entry.pruneParentSet(); support.setLevel(entry, parent.getLevel() + 1); } diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryIdentityHash.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryIdentityHash.java index ffbf4b2a9..2db67c679 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryIdentityHash.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryIdentityHash.java @@ -229,7 +229,11 @@ abstract public class QueryIdentityHash extends THash { // TODO Auto-generated method stub return null; } - + + @Override + void pruneParentSet() { + } + }; /** diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryIdentityHashSet.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryIdentityHashSet.java index 3a7eb6182..ac2602fcb 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryIdentityHashSet.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryIdentityHashSet.java @@ -147,7 +147,25 @@ final public class QueryIdentityHashSet extends QueryIdentityHash implements Ite } } - + + final public void removeDiscardedReally() { + + tempDisableAutoCompaction(); + try { + + for(int i=0;i<_set.length;i++) { + CacheEntry entry = _set[i]; + if(entry != null && REMOVED != entry) { + if(entry.isDiscarded()) removeAt(i); + } + } + + } finally { + reenableAutoCompaction(false); + } + + } + /** * Creates an iterator over the values of the set. The iterator * supports element deletion. 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 91200f1fc..e0b39d651 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 @@ -415,7 +415,7 @@ public class QueryListening { @Override public void run() { - ListenerEntry entry = addedEntries.get(base); + ListenerEntry entry = addedEntries.remove(base); if(entry != null) entry.setLastKnown(result); } diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/scl/AbstractExpressionCompilationRequest.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/scl/AbstractExpressionCompilationRequest.java index 1bcd91877..16f88a340 100644 --- a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/scl/AbstractExpressionCompilationRequest.java +++ b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/scl/AbstractExpressionCompilationRequest.java @@ -179,7 +179,6 @@ implements Read> { b2.append('\n'); } SCLDatabaseException exception = new SCLDatabaseException(b.toString()+b2.toString(), b2.toString(), e.getErrors()); - LOGGER.info(exception.getMessage(), exception); throw exception; } catch(Throwable e) { // Should not happen! diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/NodeStructureRequest.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/NodeStructureRequest.java index 5d21ca56b..707fdbd0e 100644 --- a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/NodeStructureRequest.java +++ b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/NodeStructureRequest.java @@ -7,174 +7,177 @@ import java.util.Map; import org.simantics.databoard.util.ObjectUtils; import org.simantics.db.ReadGraph; import org.simantics.db.common.request.ParametrizedPrimitiveRead; -import org.simantics.db.common.utils.Logger; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.variable.Variables.NodeStructure; import org.simantics.db.procedure.Listener; import org.simantics.simulator.variable.exceptions.NodeManagerException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import gnu.trove.map.hash.THashMap; @SuppressWarnings("rawtypes") class NodeStructureRequest extends ParametrizedPrimitiveRead implements VariableNodeReadRunnable { - private Listener listener = null; - private NodeStructure value = Variables.PENDING_NODE_STRUCTURE; - private boolean wasRun = false; - - static class Probe implements Runnable { - - private VariableNode node; - public NodeStructure result; - - public Probe(VariableNode node) { - this.node = node; - } - - @SuppressWarnings("unchecked") - @Override - public void run() { - try { - result = NodeStructureRequest.get(node); - node.support.structureCache.put(node.node, result, 1000000000L); - } catch (NodeManagerException e) { - e.printStackTrace(); - } - } - - } - - public NodeStructureRequest(VariableNode node) { - super(node); - } - - @SuppressWarnings("unchecked") - @Override - public void register(ReadGraph graph, final Listener procedure) { - - if(procedure.isDisposed()) { - - // We are not listening - NodeStructure result = (NodeStructure)parameter.support.structureCache.get(parameter.node); - - if(result != null) { - // Return cached value immediately - procedure.execute(result); - } else { - NodeStructureRequest.Probe probe = new Probe(parameter); - parameter.support.manager.getRealm().asyncExec(probe); - if(probe.result != null) { - procedure.execute(probe.result); - } else { - procedure.execute(Variables.PENDING_NODE_STRUCTURE); - } - } - - return; - - } - - // We need to listen - listener = procedure; - // Register listening - parameter.support.manager.addNodeListener(parameter.node, this); - synchronized(this) { - if(wasRun) { - procedure.execute(value); - } else { - NodeStructure result = (NodeStructure)parameter.support.structureCache.get(parameter.node); - if(result != null) { - procedure.execute(result); - } else { - procedure.execute(Variables.PENDING_NODE_STRUCTURE); - } - } - } - - } - - static class NodeListener implements VariableNodeReadRunnable { - - private VariableNode node; - private NodeStructureRequest request; - - public NodeListener(VariableNode node, NodeStructureRequest request) { - this.node = node; - this.request = request; - } - - @SuppressWarnings("unchecked") - @Override - public void run() { - node.support.manager.addNodeListener(node.node, request); - } - - } - - @SuppressWarnings("unchecked") - @Override - public void unregistered() { - parameter.support.manager.removeNodeListener(parameter.node, this); - parameter.support.structureCache.removeListening(parameter.node); - listener = null; - } - - @SuppressWarnings("unchecked") - public static NodeStructure get(VariableNode parameter) throws NodeManagerException { - List children = parameter.support.manager.getChildren(parameter.node); - List properties = parameter.support.manager.getProperties(parameter.node); - Map childMap = Collections.emptyMap(); - Map propertyMap = childMap; - if(!children.isEmpty()) { - childMap = new THashMap<>(children.size()); - for(Object o : children) { - String name = parameter.support.manager.getName(o); - childMap.put(name, o); - } - } - if(!properties.isEmpty()) { - propertyMap = new THashMap<>(properties.size()); - for(Object o : properties) { - String name = parameter.support.manager.getName(o); - propertyMap.put(name, o); - } - } - return new NodeStructure(childMap, propertyMap); - } - - @SuppressWarnings("unchecked") - @Override - public synchronized void run() { - try { - // Cache this value with infinite cache time since we are listening - NodeStructure newValue = get(parameter); - if (wasRun && ObjectUtils.objectEquals(value, newValue)) { - //System.out.println("CACHE VALUE MATCH (" + newValue + ") for " + node.node); - return; - } - value = newValue; - parameter.support.structureCache.put(parameter.node, value); - } catch (Throwable e) { - // Must catch everything to prevent DB client from getting stuck. - Logger.defaultLogError(e); - // Invoke the exception method of the listener - Listener listener = this.listener; - if (listener != null) listener.exception(new DatabaseException("External data access error", e)); - wasRun = true; - return; - } - - // Must always invoke an existing listener, regardless of earlier errors. - Listener listener = this.listener; - if (listener != null) { - listener.execute(value); - } - wasRun = true; - } - - @Override - public String toString() { - return "NodeStructureRequest.run @ " + System.identityHashCode(this); - } + private static final Logger LOGGER = LoggerFactory.getLogger(NodeStructureRequest.class); + + private Listener listener = null; + private NodeStructure value = Variables.PENDING_NODE_STRUCTURE; + private boolean wasRun = false; + + static class Probe implements Runnable { + + private VariableNode node; + public NodeStructure result; + + public Probe(VariableNode node) { + this.node = node; + } + + @SuppressWarnings("unchecked") + @Override + public void run() { + try { + result = NodeStructureRequest.get(node); + node.support.structureCache.put(node.node, result, 1000000000L); + } catch (NodeManagerException e) { + e.printStackTrace(); + } + } + + } + + public NodeStructureRequest(VariableNode node) { + super(node); + } + + @SuppressWarnings("unchecked") + @Override + public void register(ReadGraph graph, final Listener procedure) { + + if(procedure.isDisposed()) { + + // We are not listening + NodeStructure result = (NodeStructure)parameter.support.structureCache.get(parameter.node); + + if(result != null) { + // Return cached value immediately + procedure.execute(result); + } else { + NodeStructureRequest.Probe probe = new Probe(parameter); + parameter.support.manager.getRealm().asyncExec(probe); + if(probe.result != null) { + procedure.execute(probe.result); + } else { + procedure.execute(Variables.PENDING_NODE_STRUCTURE); + } + } + + return; + + } + + // We need to listen + listener = procedure; + // Register listening + parameter.support.manager.addNodeListener(parameter.node, this); + synchronized(this) { + if(!wasRun) { + NodeStructure result = (NodeStructure)parameter.support.structureCache.get(parameter.node); + if(result != null) { + procedure.execute(result); + } else { + procedure.execute(Variables.PENDING_NODE_STRUCTURE); + } + } + } + + } + + static class NodeListener implements VariableNodeReadRunnable { + + private VariableNode node; + private NodeStructureRequest request; + + public NodeListener(VariableNode node, NodeStructureRequest request) { + this.node = node; + this.request = request; + } + + @SuppressWarnings("unchecked") + @Override + public void run() { + node.support.manager.addNodeListener(node.node, request); + } + + } + + @SuppressWarnings("unchecked") + @Override + public void unregistered() { + parameter.support.manager.removeNodeListener(parameter.node, this); + parameter.support.structureCache.removeListening(parameter.node); + listener = null; + } + + @SuppressWarnings("unchecked") + public static NodeStructure get(VariableNode parameter) throws NodeManagerException { + List children = parameter.support.manager.getChildren(parameter.node); + List properties = parameter.support.manager.getProperties(parameter.node); + Map childMap = Collections.emptyMap(); + Map propertyMap = childMap; + if(!children.isEmpty()) { + childMap = new THashMap<>(children.size()); + for(Object o : children) { + String name = parameter.support.manager.getName(o); + childMap.put(name, o); + } + } + if(!properties.isEmpty()) { + propertyMap = new THashMap<>(properties.size()); + for(Object o : properties) { + String name = parameter.support.manager.getName(o); + propertyMap.put(name, o); + } + } + return new NodeStructure(childMap, propertyMap); + } + + @SuppressWarnings("unchecked") + @Override + public synchronized void run() { + try { + // Cache this value with infinite cache time since we are listening + NodeStructure newValue = get(parameter); + if (wasRun && ObjectUtils.objectEquals(value, newValue)) { + //System.out.println("CACHE VALUE MATCH (" + newValue + ") for " + node.node); + return; + } + value = newValue; + parameter.support.structureCache.put(parameter.node, value); + } catch (Throwable e) { + // Must catch everything to prevent DB client from getting stuck. + LOGGER.error("Error while computing node structure", e); + // Invoke the exception method of the listener + Listener listener = this.listener; + if (listener != null) { + listener.exception(new DatabaseException("External data access error", e)); + wasRun = true; + } + return; + } + + // Must always invoke an existing listener, regardless of earlier errors. + Listener listener = this.listener; + if (listener != null) { + listener.execute(value); + wasRun = true; + } + } + + @Override + public String toString() { + return "NodeStructureRequest.run @ " + System.identityHashCode(this); + } } \ No newline at end of file diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/NodeValueRequest.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/NodeValueRequest.java index 140ee8fa0..b44f16b30 100644 --- a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/NodeValueRequest.java +++ b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/NodeValueRequest.java @@ -110,9 +110,7 @@ class NodeValueRequest extends ParametrizedPrimitiveRead listener = this.listener; - if (listener != null) listener.exception(new DatabaseException("External data access error", e)); - wasRun = true; + if (listener != null) { + listener.exception(new DatabaseException("External data access error", e)); + wasRun = true; + } return; } // Must always invoke an existing listener, regardless of earlier errors. @@ -228,8 +228,8 @@ class NodeValueRequest extends ParametrizedPrimitiveRead 0) json.append(","); - Object r = res[i]; - if(r instanceof IdentifiedObject) { - Object id = ((IdentifiedObject) r).getId(); - if(id instanceof IAdaptable) { - Object resource = ((IAdaptable) id).getAdapter(Resource.class); - if(resource != null) { - long rid = ((Resource)resource).getResourceId(); - json.append(Long.toString(rid)); - pos++; - } - } - } + if(pos > 0) json.append(","); + Object r = res[i]; + if(r instanceof IAdaptable) { + Resource resource = ((IAdaptable) r).getAdapter(Resource.class); + if(resource != null) { + long rid = resource.getResourceId(); + json.append(Long.toString(rid)); + pos++; + } + } } json.append("] }"); - StringSelection text = new StringSelection(json.toString()); - PlaintextTransfer plainText = new PlaintextTransfer(json.toString()); + String jsonText = json.toString(); + StringSelection text = new StringSelection(jsonText); + PlaintextTransfer plainText = new PlaintextTransfer(jsonText); return new MultiTransferable(local, text, plainText); diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/synchronization/graph/CopyAdvisorUtil.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/synchronization/graph/CopyAdvisorUtil.java index ab28463e8..bbf9a8e5b 100644 --- a/bundles/org.simantics.diagram/src/org/simantics/diagram/synchronization/graph/CopyAdvisorUtil.java +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/synchronization/graph/CopyAdvisorUtil.java @@ -11,8 +11,6 @@ *******************************************************************************/ package org.simantics.diagram.synchronization.graph; -import gnu.trove.map.hash.THashMap; - import java.util.Map; import java.util.Set; import java.util.function.BiFunction; @@ -46,6 +44,10 @@ import org.simantics.diagram.synchronization.SynchronizationHints; import org.simantics.graph.db.TransferableGraphs; import org.simantics.graph.representation.TransferableGraph1; import org.simantics.layer0.Layer0; +import org.simantics.utils.datastructures.BinaryFunction; + +import gnu.trove.map.hash.THashMap; +import gnu.trove.set.hash.THashSet; /** * This class contains utility methods for the basic cut/copy operations @@ -82,6 +84,15 @@ public class CopyAdvisorUtil { public static final boolean DEBUG_COPY = DebugPolicy.DEBUG_COPY_PASTE; + private static class Statement4 { + public final Statement stm; + public final Resource inverse; + public Statement4(Statement stm, Resource inverse) { + this.stm = stm; + this.inverse = inverse; + } + } + /** * @param context a synchronization context instance, such as * {@link GraphToDiagramSynchronizer} @@ -364,8 +375,10 @@ public class CopyAdvisorUtil { * @throws DatabaseException */ public static Resource copy2(WriteGraph graph, Resource source, - BiFunction advisor) throws DatabaseException { - return copy2(graph, source, 0, advisor, new THashMap()); + BiFunction advisor) + throws DatabaseException + { + return copy2(graph, source, advisor, new THashMap<>()); } /** @@ -380,13 +393,52 @@ public class CopyAdvisorUtil { * @throws DatabaseException */ public static Resource copy2(WriteGraph graph, Resource source, - BiFunction advisor, Map copyMap) - throws DatabaseException { - return copy2(graph, source, 0, advisor, copyMap); + BiFunction advisor, + Map copyMap) + throws DatabaseException + { + Set pendingStatements = new THashSet<>(); + Resource result = copy2(graph, source, 0, advisor, copyMap, pendingStatements); + postProcessStatements(graph, copyMap, pendingStatements); + return result; + } + + /** + * Post-process pending statement + * + * Rule: If both the subject and object of a pending source statement have + * been copied, then the pending statement should also be copied. + */ + private static void postProcessStatements( + WriteGraph graph, + Map copyMap, + Set pendingStatements) + throws DatabaseException + { + if (pendingStatements.isEmpty()) + return; + + if (DEBUG_COPY) + System.out.println("post processing " + pendingStatements.size() + " pending statements"); + for (Statement4 srcStm : pendingStatements) { + // At this point, it is certain that srcStm subject has been copied + // but test it anyway. + Resource subjectCopy = (Resource) copyMap.get(srcStm.stm.getSubject()); + Resource objectCopy = (Resource) copyMap.get(srcStm.stm.getObject()); + if (subjectCopy == null || objectCopy == null) { + if (DEBUG_COPY) + System.out.println("skipping pending statement: " + NameUtils.toString(graph, srcStm.stm)); + continue; + } + if (DEBUG_COPY) + System.out.println("copying pending statement: " + NameUtils.toString(graph, srcStm.stm)); + graph.claim(subjectCopy, srcStm.stm.getPredicate(), srcStm.inverse, objectCopy); + } } private static Resource copy2(final WriteGraph graph, final Resource source, final int level, - BiFunction advisor, Map copyMap) + BiFunction advisor, Map copyMap, + Set pendingSourceStatements) throws DatabaseException { if (DEBUG_COPY) System.out.println("[" + level + "] CopyAdvisorUtil.copy(" + NameUtils.getSafeName(graph, source) + ", advisor=" + advisor + ")"); @@ -497,12 +549,18 @@ public class CopyAdvisorUtil { if (DEBUG_COPY) System.out.println("[" + level + "]\t\tcopy whole object"); - Resource clone = copy2(graph, obj, level + 1, advisor, copyMap); + Resource clone = copy2(graph, obj, level + 1, advisor, copyMap, pendingSourceStatements); graph.claim(copy, relation, inverse, clone); } } else { - if (DEBUG_COPY) - System.out.println("[" + level + "]\t\tskipping statement"); + if (graph.isSubrelationOf(relation, L0.IsRelatedTo)) { + if (DEBUG_COPY) + System.out.println("[" + level + "]\t\tmarking statement as pending for post-processing"); + pendingSourceStatements.add(new Statement4(stm, inverse)); + } else { + if (DEBUG_COPY) + System.out.println("[" + level + "]\t\tskipping weak statement"); + } } } } diff --git a/bundles/org.simantics.document.server/src/org/simantics/document/server/request/DocumentRequest.java b/bundles/org.simantics.document.server/src/org/simantics/document/server/request/DocumentRequest.java index 8acc2f0d1..5b76cd344 100644 --- a/bundles/org.simantics.document.server/src/org/simantics/document/server/request/DocumentRequest.java +++ b/bundles/org.simantics.document.server/src/org/simantics/document/server/request/DocumentRequest.java @@ -1,6 +1,7 @@ package org.simantics.document.server.request; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; @@ -10,7 +11,7 @@ import java.util.Set; import org.simantics.db.AsyncReadGraph; import org.simantics.db.ReadGraph; import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener; -import org.simantics.db.common.request.AsyncReadRequest; +import org.simantics.db.common.request.UnaryAsyncRead; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.request.VariableRead; import org.simantics.db.layer0.variable.Variable; @@ -28,49 +29,55 @@ public class DocumentRequest extends VariableRead> { super(var); } - @Override - public List perform(ReadGraph graph) throws DatabaseException { - - long s = System.nanoTime(); - - Set nodes = graph.syncRequest(new NodesRequest(variable), TransientCacheAsyncListener.>instance()); - HashSet rs = new HashSet(); // result - if(nodes.isEmpty()) { - return Collections.emptyList(); - } + static class CollectNodesRequest extends UnaryAsyncRead, Collection> { - if(PROFILE) { - long dura = System.nanoTime()-s; - System.err.println("DocumentRequest1 " + System.identityHashCode(this) + " in " + 1e-6*dura + "ms. " + variable.getURI(graph)); + public CollectNodesRequest(Collection nodes) { + super(nodes); } - graph.syncRequest(new AsyncReadRequest() { + @Override + public void perform(AsyncReadGraph graph, AsyncProcedure> procedure) { + HashSet rs = new HashSet(); // result - @Override - public void run(AsyncReadGraph graph) throws DatabaseException { + for(Variable node : parameter) { + graph.asyncRequest(new NodeRequest(node), new AsyncProcedure () { - for(Variable node : nodes) { - graph.asyncRequest(new NodeRequest(node), new AsyncProcedure () { - - @Override - public void execute(AsyncReadGraph graph, JSONObject result) { - synchronized (rs) { - rs.add(result); - } + @Override + public void execute(AsyncReadGraph graph, JSONObject result) { + synchronized(rs) { + rs.add(result); } + } - @Override - public void exception(AsyncReadGraph graph, Throwable throwable) { - } + @Override + public void exception(AsyncReadGraph graph, Throwable throwable) { + } + + }); - }); - - } - } - - }); + procedure.execute(graph, rs); + + } + + } + + @Override + public List perform(ReadGraph graph) throws DatabaseException { + + long s = System.nanoTime(); + + Set nodes = graph.syncRequest(new NodesRequest(variable), TransientCacheAsyncListener.>instance()); + if(nodes.isEmpty()) { + return Collections.emptyList(); + } + + if(PROFILE) { + long dura = System.nanoTime()-s; + System.err.println("DocumentRequest1 " + System.identityHashCode(this) + " in " + 1e-6*dura + "ms. " + variable.getURI(graph)); + } + Collection rs = graph.syncRequest(new CollectNodesRequest(nodes)); if(PROFILE) { long dura = System.nanoTime()-s; diff --git a/bundles/org.simantics.document.server/src/org/simantics/document/server/request/NodesRequest.java b/bundles/org.simantics.document.server/src/org/simantics/document/server/request/NodesRequest.java index 99526368e..133264e29 100644 --- a/bundles/org.simantics.document.server/src/org/simantics/document/server/request/NodesRequest.java +++ b/bundles/org.simantics.document.server/src/org/simantics/document/server/request/NodesRequest.java @@ -2,11 +2,12 @@ package org.simantics.document.server.request; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.Set; import org.simantics.db.AsyncReadGraph; import org.simantics.db.ReadGraph; -import org.simantics.db.common.request.AsyncReadRequest; +import org.simantics.db.common.request.UnaryAsyncRead; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.request.VariableChildren; import org.simantics.db.layer0.request.VariableRead; @@ -16,52 +17,57 @@ import org.simantics.structural.stubs.StructuralResource2; import org.simantics.utils.threads.logger.ITask; import org.simantics.utils.threads.logger.ThreadLogger; -import gnu.trove.set.hash.THashSet; - public class NodesRequest extends VariableRead> { public NodesRequest(Variable var) { super(var); } - @Override - public Set perform(ReadGraph graph) throws DatabaseException { + static class CollectNodesRequest2 extends UnaryAsyncRead, Set> { - ITask task = DocumentRequest.PROFILE ? ThreadLogger.task(this) : null; + public CollectNodesRequest2(Collection nodes) { + super(nodes); + } - StructuralResource2.getInstance(graph); - if(variable == null) - return Collections.emptySet(); + @Override + public void perform(AsyncReadGraph graph, AsyncProcedure> procedure) { + HashSet rs = new HashSet(); // result - Set nodes = new THashSet(); + for(Variable node : parameter) { + graph.asyncRequest(new NodesRequest2(node), new AsyncProcedure> () { - Collection children = graph.syncRequest(new VariableChildren(variable)); + @Override + public void execute(AsyncReadGraph graph, Set result) { + synchronized(rs) { + rs.addAll(result); + } + } - graph.syncRequest(new AsyncReadRequest() { + @Override + public void exception(AsyncReadGraph graph, Throwable throwable) { + } - @Override - public void run(AsyncReadGraph graph) throws DatabaseException { + }); - for(Variable child : children) { - graph.asyncRequest(new NodesRequest2(child), new AsyncProcedure>() { + } + procedure.execute(graph, rs); - @Override - public void execute(AsyncReadGraph graph, Set result) { - synchronized(nodes) { - nodes.addAll(result); - } - } + } - @Override - public void exception(AsyncReadGraph graph, Throwable throwable) { - } - - }); - } + } - } + @Override + public Set perform(ReadGraph graph) throws DatabaseException { + + ITask task = DocumentRequest.PROFILE ? ThreadLogger.task(this) : null; + + StructuralResource2.getInstance(graph); + if(variable == null) + return Collections.emptySet(); + + Collection children = graph.syncRequest(new VariableChildren(variable)); - }); + Set nodes = graph.syncRequest(new CollectNodesRequest2(children)); if(DocumentRequest.PROFILE) task.finish(); diff --git a/bundles/org.simantics.g2d/src/org/simantics/g2d/gallery/GalleryViewer.java b/bundles/org.simantics.g2d/src/org/simantics/g2d/gallery/GalleryViewer.java index 5bbe9f26e..d09ecf4a6 100644 --- a/bundles/org.simantics.g2d/src/org/simantics/g2d/gallery/GalleryViewer.java +++ b/bundles/org.simantics.g2d/src/org/simantics/g2d/gallery/GalleryViewer.java @@ -631,8 +631,10 @@ public class GalleryViewer extends ContentViewer { ctx.getThreadAccess().asyncExec(() -> { //System.out.println(Thread.currentThread() + ": update scene graph(" + el + ")"); // Update scene graph and repaint. - el.getElementClass().getSingleItem(GalleryItemSGNode.class).update(el); - ctx.getContentContext().setDirty(); + if (!ctx.isDisposed()) { + el.getElementClass().getSingleItem(GalleryItemSGNode.class).update(el); + ctx.getContentContext().setDirty(); + } }); break; } diff --git a/bundles/org.simantics.graph/src/org/simantics/graph/refactoring/FixExportedOntology.java b/bundles/org.simantics.graph/src/org/simantics/graph/refactoring/FixExportedOntology.java index 17aa3ed26..33291cdf1 100644 --- a/bundles/org.simantics.graph/src/org/simantics/graph/refactoring/FixExportedOntology.java +++ b/bundles/org.simantics.graph/src/org/simantics/graph/refactoring/FixExportedOntology.java @@ -41,8 +41,9 @@ public class FixExportedOntology { private static Path replaceExtension(Path p, String newExtension) { String newName = p.getFileName().toString(); - if (newName.contains(".")) - newName = newName.split("\\.")[0]; + int lastDot = newName.lastIndexOf('.'); + if (lastDot > -1) + newName = newName.substring(0, lastDot); return p.resolveSibling(newName + newExtension); } diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/mapping/ComponentCopyAdvisor.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/mapping/ComponentCopyAdvisor.java index 3e6e9c1b9..021ecc436 100644 --- a/bundles/org.simantics.modeling/src/org/simantics/modeling/mapping/ComponentCopyAdvisor.java +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/mapping/ComponentCopyAdvisor.java @@ -32,7 +32,6 @@ import org.simantics.modeling.ModelingUtils; import org.simantics.modeling.services.ComponentNamingUtil; import org.simantics.modeling.services.NamingException; import org.simantics.project.IProject; -import org.simantics.structural.stubs.StructuralResource2; import gnu.trove.map.hash.THashMap; @@ -58,7 +57,6 @@ public class ComponentCopyAdvisor extends GraphCopyAdvisor { @Override public Object copy(ISynchronizationContext context, WriteGraph graph, Resource source, Resource sourceContainer, Resource targetContainer, Map map) throws DatabaseException { - StructuralResource2 STR = StructuralResource2.getInstance(graph); Resource copy = CopyAdvisorUtil.copy2(graph, source, null, map); Layer0 L0 = Layer0.getInstance(graph); diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/scl/GraphModuleSourceRepository.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/scl/GraphModuleSourceRepository.java index 8eed51aca..a70844cd3 100644 --- a/bundles/org.simantics.modeling/src/org/simantics/modeling/scl/GraphModuleSourceRepository.java +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/scl/GraphModuleSourceRepository.java @@ -12,6 +12,8 @@ import org.simantics.db.common.request.WriteRequest; import org.simantics.db.exception.DatabaseException; import org.simantics.db.procedure.SyncListener; import org.simantics.db.request.Read; +import org.simantics.db.request.ReadExt; +import org.simantics.db.request.RequestFlags; import org.simantics.layer0.Layer0; import org.simantics.modeling.ModelingUtils; import org.simantics.modeling.internal.Activator; @@ -137,6 +139,29 @@ public enum GraphModuleSourceRepository implements ModuleSourceRepository { } } + static class PossibleResourceIU extends UnaryRead implements ReadExt { + + public PossibleResourceIU(String parameter) { + super(parameter); + } + + @Override + public Resource perform(ReadGraph graph) throws DatabaseException { + return graph.getPossibleResource(parameter); + } + + @Override + public boolean isImmutable(ReadGraph graph) throws DatabaseException { + return false; + } + + @Override + public int getType() { + return RequestFlags.IMMEDIATE_UPDATE; + } + + } + static class ReadModuleSource extends UnaryRead { public ReadModuleSource(String moduleName) { super(moduleName); @@ -144,7 +169,7 @@ public enum GraphModuleSourceRepository implements ModuleSourceRepository { @Override public ModuleSource perform(ReadGraph graph) throws DatabaseException { - Resource moduleResource = graph.getPossibleResource(parameter); + Resource moduleResource = graph.syncRequest(new PossibleResourceIU(parameter)); if(moduleResource == null) return null; Layer0 L0 = Layer0.getInstance(graph); diff --git a/bundles/org.simantics.scenegraph.profile/src/org/simantics/scenegraph/profile/common/ObserverGroupListener.java b/bundles/org.simantics.scenegraph.profile/src/org/simantics/scenegraph/profile/common/ObserverGroupListener.java index 31295b9b6..10e2abe67 100644 --- a/bundles/org.simantics.scenegraph.profile/src/org/simantics/scenegraph/profile/common/ObserverGroupListener.java +++ b/bundles/org.simantics.scenegraph.profile/src/org/simantics/scenegraph/profile/common/ObserverGroupListener.java @@ -44,7 +44,7 @@ public class ObserverGroupListener implements SetListener { public void add(Resource item) { //System.out.println("Add to group(" + this + "): " + item); items.put(item, item); - observer.update(); + observer.update(style, item); } @Override @@ -52,7 +52,7 @@ public class ObserverGroupListener implements SetListener { // new Exception().printStackTrace(); //System.out.println("Remove from group(" + this + "): " + item); items.remove(item); - observer.update(); + observer.update(style, item); } @Override