Added transient caching for BrowseContext construction
authorTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Wed, 10 Jun 2020 18:36:36 +0000 (21:36 +0300)
committerTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Wed, 17 Jun 2020 21:51:45 +0000 (00:51 +0300)
This helps avoid some cost of repetitive recomputation of BrowseContext
ChildContribution and VisualsContribution structures.

gitlab #557

Change-Id: I1281c89a7f1b9563e3bf36cc4b51650a7ee9af84
(cherry picked from commit 7ff29c2c126d7f7cd4ca45f216acca7290d9409a)

bundles/org.simantics.browsing.ui.model/src/org/simantics/browsing/ui/model/browsecontexts/BrowseContext.java
bundles/org.simantics.browsing.ui.model/src/org/simantics/browsing/ui/model/children/ChildContribution.java
bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/util/HierarchyMultiMap.java

index c4f8c26829081fa290a6df3cd35549817f6d3439..3a185f5850bf62de7b0d9af14058ae3192b54ae0 100644 (file)
@@ -57,11 +57,13 @@ import org.simantics.browsing.ui.model.visuals.VisualsContribution;
 import org.simantics.db.ReadGraph;
 import org.simantics.db.RequestProcessor;
 import org.simantics.db.Resource;
+import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
+import org.simantics.db.common.request.ResourceRead;
+import org.simantics.db.common.request.UnaryRead;
 import org.simantics.db.common.utils.NameUtils;
 import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.exception.ResourceNotFoundException;
 import org.simantics.db.layer0.variable.Variable;
-import org.simantics.db.request.Read;
 import org.simantics.scl.reflection.OntologyVersions;
 import org.simantics.viewpoint.ontology.ViewpointResource;
 import org.slf4j.Logger;
@@ -77,21 +79,21 @@ public class BrowseContext {
     private static final Logger LOGGER = LoggerFactory.getLogger(BrowseContext.class);
        public static final boolean DEBUG = false;
        
-    NodeTypeMultiMap<ChildContribution> childContributions = new NodeTypeMultiMap<ChildContribution>();
-    NodeTypeMultiMap<ChildContribution> parentContributions = new NodeTypeMultiMap<ChildContribution>();
-    OrderedNodeTypeMultiMap<LabelContribution> labelContributions = new OrderedNodeTypeMultiMap<LabelContribution>();
-    OrderedNodeTypeMultiMap<ImageContribution> imageContributions = new OrderedNodeTypeMultiMap<ImageContribution>();
-    OrderedNodeTypeMultiMap<CheckedStateContribution> checkedStateContributions = new OrderedNodeTypeMultiMap<CheckedStateContribution>();
-    OrderedNodeTypeMultiMap<LabelDecorationContribution> labelDecorationContributions = new OrderedNodeTypeMultiMap<LabelDecorationContribution>();
-    OrderedNodeTypeMultiMap<ImageDecorationContribution> imageDecorationContributions = new OrderedNodeTypeMultiMap<ImageDecorationContribution>();
-    OrderedNodeTypeMultiMap<ModifierContribution> modifierContributions = new OrderedNodeTypeMultiMap<ModifierContribution>();
-    OrderedNodeTypeMultiMap<SorterContribution> sorterContributions = new OrderedNodeTypeMultiMap<SorterContribution>();
-    OrderedNodeTypeMultiMap<FlatNodeContribution> flatNodeContributions = new OrderedNodeTypeMultiMap<FlatNodeContribution>();
+    NodeTypeMultiMap<ChildContribution> childContributions = new NodeTypeMultiMap<>();
+    NodeTypeMultiMap<ChildContribution> parentContributions = new NodeTypeMultiMap<>();
+    OrderedNodeTypeMultiMap<LabelContribution> labelContributions = new OrderedNodeTypeMultiMap<>();
+    OrderedNodeTypeMultiMap<ImageContribution> imageContributions = new OrderedNodeTypeMultiMap<>();
+    OrderedNodeTypeMultiMap<CheckedStateContribution> checkedStateContributions = new OrderedNodeTypeMultiMap<>();
+    OrderedNodeTypeMultiMap<LabelDecorationContribution> labelDecorationContributions = new OrderedNodeTypeMultiMap<>();
+    OrderedNodeTypeMultiMap<ImageDecorationContribution> imageDecorationContributions = new OrderedNodeTypeMultiMap<>();
+    OrderedNodeTypeMultiMap<ModifierContribution> modifierContributions = new OrderedNodeTypeMultiMap<>();
+    OrderedNodeTypeMultiMap<SorterContribution> sorterContributions = new OrderedNodeTypeMultiMap<>();
+    OrderedNodeTypeMultiMap<FlatNodeContribution> flatNodeContributions = new OrderedNodeTypeMultiMap<>();
     OrderedNodeTypeMultiMap<TooltipContribution> tooltipContributions = new OrderedNodeTypeMultiMap<>();
 
     private final String[] uris; 
 
-    private BrowseContext(String[] uris) {
+    private BrowseContext(String... uris) {
         if (uris == null)
             throw new NullPointerException("null URIs");
         this.uris = uris;
@@ -110,6 +112,38 @@ public class BrowseContext {
         return defaultContext;
     }
 
+    private static BrowseContext loadCachedVisuals(ReadGraph g, Resource visualsContributionResource) throws DatabaseException, InvalidContribution {
+        try {
+            return g.syncRequest(new ResourceRead<BrowseContext>(visualsContributionResource) {
+                @Override
+                public BrowseContext perform(ReadGraph graph) throws DatabaseException {
+                    try {
+                        BrowseContext bc = new BrowseContext();
+                        VisualsContribution.load(g, visualsContributionResource,
+                                bc.labelContributions,
+                                bc.imageContributions,
+                                bc.checkedStateContributions,
+                                bc.labelDecorationContributions,
+                                bc.imageDecorationContributions,
+                                bc.modifierContributions,
+                                bc.sorterContributions,
+                                bc.flatNodeContributions,
+                                bc.tooltipContributions
+                                );
+                        return bc;
+                    } catch (InvalidContribution e) {
+                        throw new DatabaseException(e);
+                    }
+                }
+            }, TransientCacheAsyncListener.instance());
+        } catch (DatabaseException e) {
+            Throwable c = e.getCause();
+            if (c instanceof InvalidContribution)
+                throw (InvalidContribution) c;
+            throw e;
+        }
+    }
+
     /**
      * Creates a new BrowseContext for the given Collection of {@link Resource}s.
      * 
@@ -127,7 +161,7 @@ public class BrowseContext {
             for(Resource childContributionResource : 
                 g.getObjects(browseContextResource, vr.BrowseContext_HasChildContribution)) {
                 try {
-                    ChildContribution contribution = ChildContribution.create(g, childContributionResource);
+                    ChildContribution contribution = ChildContribution.createCached(g, childContributionResource);
                     browseContext.childContributions.put(contribution.getParentNodeType(), contribution);
                     browseContext.parentContributions.put(contribution.getChildNodeType(), contribution);
                 } catch (DatabaseException e) {
@@ -138,17 +172,16 @@ public class BrowseContext {
             for(Resource visualsContributionResource : 
                 g.getObjects(browseContextResource, vr.BrowseContext_HasVisualsContribution)) {
                 try {
-                    VisualsContribution.load(g, visualsContributionResource,
-                            browseContext.labelContributions,
-                            browseContext.imageContributions,
-                            browseContext.checkedStateContributions,
-                            browseContext.labelDecorationContributions,
-                            browseContext.imageDecorationContributions,
-                            browseContext.modifierContributions,
-                            browseContext.sorterContributions,
-                            browseContext.flatNodeContributions,
-                            browseContext.tooltipContributions
-                        );
+                    BrowseContext visuals = loadCachedVisuals(g, visualsContributionResource);
+                    visuals.labelContributions.appendTo(browseContext.labelContributions);
+                    visuals.imageContributions.appendTo(browseContext.imageContributions);
+                    visuals.checkedStateContributions.appendTo(browseContext.checkedStateContributions);
+                    visuals.labelDecorationContributions.appendTo(browseContext.labelDecorationContributions);
+                    visuals.imageDecorationContributions.appendTo(browseContext.imageDecorationContributions);
+                    visuals.modifierContributions.appendTo(browseContext.modifierContributions);
+                    visuals.sorterContributions.appendTo(browseContext.sorterContributions);
+                    visuals.flatNodeContributions.appendTo(browseContext.flatNodeContributions);
+                    visuals.tooltipContributions.appendTo(browseContext.tooltipContributions);
                 } catch (DatabaseException e) {
                     LOGGER.error("Failed to load visuals contribution " + NameUtils.getSafeName(g, visualsContributionResource), e);
                 }
@@ -159,11 +192,11 @@ public class BrowseContext {
     }
 
     public static Set<String> getBrowseContextClosure(RequestProcessor processor, final Set<String> browseContexts) throws DatabaseException {
-        return processor.syncRequest(new Read<Set<String>>() {
+        return processor.syncRequest(new UnaryRead<Set<String>, Set<String>>(browseContexts) {
             @Override
             public Set<String> perform(ReadGraph graph) throws DatabaseException {
-                Collection<Resource> browseContextResources = new ArrayList<Resource>(browseContexts.size());
-                for (String browseContext : browseContexts) {
+                Collection<Resource> browseContextResources = new ArrayList<>(parameter.size());
+                for (String browseContext : parameter) {
                     try {
                         browseContextResources.add(graph.getResource(browseContext));
                     } catch (ResourceNotFoundException e) {
@@ -171,19 +204,29 @@ public class BrowseContext {
                     }
                 }
                 Collection<Resource> allBrowseContextResources = BrowseContext.findSubcontexts(graph, browseContextResources);
-                Set<String> result = new HashSet<String>();
+                Set<String> result = new HashSet<>();
                 for (Resource r : allBrowseContextResources)
                     result.add(graph.getURI(r));
-                        return result;
+                return result;
             }
-        });
+        }, TransientCacheAsyncListener.instance());
     }
 
-    public static Collection<Resource> findSubcontexts(ReadGraph g,
+    public static Collection<Resource> findSubcontexts(ReadGraph g, Collection<Resource> browseContexts)
+            throws DatabaseException {
+        return g.syncRequest(new UnaryRead<Collection<Resource>, Collection<Resource>>(browseContexts) {
+            @Override
+            public Collection<Resource> perform(ReadGraph graph) throws DatabaseException {
+                return findSubcontexts0(graph, parameter);
+            }
+        }, TransientCacheAsyncListener.instance());
+    }
+
+    private static Collection<Resource> findSubcontexts0(ReadGraph g,
             Collection<Resource> browseContexts) throws DatabaseException {
         ViewpointResource vr = ViewpointResource.getInstance(g);
-        HashSet<Resource> result = new HashSet<Resource>(browseContexts);
-        ArrayList<Resource> stack = new ArrayList<Resource>(browseContexts);
+        HashSet<Resource> result = new HashSet<>(browseContexts);
+        ArrayList<Resource> stack = new ArrayList<>(browseContexts);
         while(!stack.isEmpty()) {
             Resource cur = stack.remove(stack.size()-1);
             for(Resource sc : g.getObjects(cur, vr.BrowseContext_Includes))
@@ -192,7 +235,7 @@ public class BrowseContext {
         }
         return result;
     }
-    
+
     /**
      * Finds the possible children of the given {@link NodeContext} parameter.
      * 
index ca9f59da0cd89e7f5bd34474b28d07288527bcab..09a15fefcb6bd5a4235fd2a4433130057c54b170 100644 (file)
@@ -22,6 +22,8 @@ import org.simantics.browsing.ui.model.nodetypes.NodeType;
 import org.simantics.databoard.Bindings;
 import org.simantics.db.ReadGraph;
 import org.simantics.db.Resource;
+import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
+import org.simantics.db.common.request.ResourceRead;
 import org.simantics.db.common.utils.NameUtils;
 import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.layer0.exception.PendingVariableException;
@@ -52,6 +54,26 @@ public class ChildContribution {
         this.priority = priority;
     }
 
+    public static ChildContribution createCached(ReadGraph g, Resource childContributionResource) throws DatabaseException, InvalidContribution {
+        try {
+            return g.syncRequest(new ResourceRead<ChildContribution>(childContributionResource) {
+                @Override
+                public ChildContribution perform(ReadGraph graph) throws DatabaseException {
+                    try {
+                        return create(g, resource);
+                    } catch (InvalidContribution e) {
+                        throw new DatabaseException(e);
+                    }
+                }
+            }, TransientCacheAsyncListener.instance());
+        } catch (DatabaseException e) {
+            Throwable c = e.getCause();
+            if (c instanceof InvalidContribution)
+                throw (InvalidContribution) c;
+            throw e;
+        }
+    }
+
     public static ChildContribution create(ReadGraph g, Resource childContributionResource) throws DatabaseException, InvalidContribution {
         ViewpointResource vr = ViewpointResource.getInstance(g);
         
index a4ac87b50d1472d02626647145e6c412905aa7b6..b12d5ad2b9b4ab9d2f7d74733a2ebfe1fae21b71 100644 (file)
@@ -37,7 +37,28 @@ public abstract class HierarchyMultiMap<A,B> {
         bs.add(b);
         cache = null;
     }
-    
+
+    /**
+     * Appends the contents of the specified map to this map.
+     * 
+     * @param from the map to append contents from
+     */
+    public void append(HierarchyMultiMap<A,B> from) {
+        from.appendTo(this);
+    }
+
+    /**
+     * Appends the contents of this map to the specified map.
+     * 
+     * @param to the map to append to
+     */
+    public void appendTo(HierarchyMultiMap<A,B> to) {
+        map.forEachEntry((a, bl) -> {
+            bl.forEach(b -> to.put(a, b));
+            return true;
+        });
+    }
+
     /**
      * Gets the values stored into the map for the key {@code a} or
      * its superelements.