X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.db.common%2Fsrc%2Forg%2Fsimantics%2Fdb%2Fcommon%2Futils%2FCommonDBUtils.java;h=919f06b6847a51d876469bec47a5043ab65a6f77;hp=ed09abb54cf7266afd95d6c1dfd158164bf80b24;hb=HEAD;hpb=c744918d55c304854e4fd316ccf04ce38d6071ff diff --git a/bundles/org.simantics.db.common/src/org/simantics/db/common/utils/CommonDBUtils.java b/bundles/org.simantics.db.common/src/org/simantics/db/common/utils/CommonDBUtils.java index ed09abb54..919f06b68 100644 --- a/bundles/org.simantics.db.common/src/org/simantics/db/common/utils/CommonDBUtils.java +++ b/bundles/org.simantics.db.common/src/org/simantics/db/common/utils/CommonDBUtils.java @@ -4,7 +4,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Set; @@ -13,17 +12,40 @@ import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.Statement; import org.simantics.db.WriteGraph; +import org.simantics.db.common.procedure.adapter.DirectStatementProcedure; import org.simantics.db.common.request.IsParent; import org.simantics.db.common.request.ObjectsWithType; +import org.simantics.db.common.request.PossibleChild; import org.simantics.db.common.request.PossibleObjectWithType; import org.simantics.db.common.request.PossibleOwner; +import org.simantics.db.common.request.ResourceRead; +import org.simantics.db.common.request.RuntimeEnvironmentRequest; +import org.simantics.db.exception.AdaptionException; import org.simantics.db.exception.DatabaseException; +import org.simantics.db.exception.InvalidResourceReferenceException; +import org.simantics.db.service.ClusterUID; import org.simantics.db.service.ClusteringSupport; +import org.simantics.db.service.DirectQuerySupport; +import org.simantics.db.service.SerialisationSupport; +import org.simantics.db.service.XSupport; import org.simantics.layer0.Layer0; +import org.simantics.scl.compiler.environment.Environments; +import org.simantics.scl.compiler.runtime.RuntimeEnvironment; +import org.simantics.scl.compiler.top.SCLExpressionCompilationException; +import org.simantics.scl.compiler.types.Type; import org.simantics.utils.datastructures.collections.CollectionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import gnu.trove.list.array.TIntArrayList; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.set.hash.THashSet; +import gnu.trove.set.hash.TIntHashSet; public class CommonDBUtils { + private static final Logger LOGGER = LoggerFactory.getLogger(CommonDBUtils.class); + public static boolean isParent(ReadGraph graph, Resource possibleParent, Resource possibleChild) throws DatabaseException { return graph.sync(new IsParent(possibleParent, possibleChild)); } @@ -44,96 +66,83 @@ public class CommonDBUtils { return graph.syncRequest(new PossibleOwner(resource)); } + /** + * Finds a resource that is reachable from both input resources by as short as possible IsOwnedBy chain + */ public static Resource commonAncestor(ReadGraph graph, Resource r1, Resource r2) throws DatabaseException { + if(r1.equals(r2)) + return r1; + Layer0 L0 = Layer0.getInstance(graph); - if(r1.equals(r2)) return r1; - HashSet visited = new HashSet(); - visited.add(r1); - visited.add(r2); - while(true) { - if(r1 != null) { - r1 = graph.getPossibleObject(r1, L0.IsOwnedBy); - if(r1 != null) - if(!visited.add(r1)) return r1; - } - else if(r2 == null) return null; - if(r2 != null) { - r2 = graph.getPossibleObject(r2, L0.IsOwnedBy); - if(r2 != null) - if(!visited.add(r2)) return r2; - } - } + HashSet visited = new HashSet(); + visited.add(r1); + visited.add(r2); + while(true) { + if(r1 != null) { + r1 = graph.getPossibleObject(r1, L0.IsOwnedBy); + if(r1 != null && !visited.add(r1)) + return r1; + } + else if(r2 == null) + return null; + if(r2 != null) { + r2 = graph.getPossibleObject(r2, L0.IsOwnedBy); + if(r2 != null && !visited.add(r2)) + return r2; + } + } } - - public static Resource getNearestOwner(ReadGraph graph, Collection resources) throws DatabaseException { - - Layer0 L0 = Layer0.getInstance(graph); - + + private static Collection getDirectOwners(ReadGraph graph, Resource resource) throws DatabaseException { + // TODO is necessary? + if(resource.equals(graph.getRootLibrary())) + return Collections.emptyList(); - Set direct = new HashSet(); - Set owners = new HashSet(); + Layer0 L0 = Layer0.getInstance(graph); - for(Resource r : resources) { - - Collection objects = graph.getObjects(r, L0.IsOwnedBy); - // FIXME: - // TODO: getObjects returns duplicate entries (https://www.simantics.org/redmine/issues/4885) and therefore direct is Set. Fix getObjects to not return duplicate entries - if (objects.size() > 1) objects = new HashSet(objects); + Collection owners = graph.getObjects(resource, L0.IsOwnedBy); + if(owners.isEmpty()) { + owners = new THashSet(); - if (objects.size() == 1) - direct.addAll(objects); - else if (objects.isEmpty()) { - for(Statement stm : graph.getStatements(r, L0.IsWeaklyRelatedTo)) { - Resource inverse = graph.getPossibleInverse(stm.getPredicate()); - if(inverse != null) { - if(graph.isSubrelationOf(inverse, L0.IsRelatedTo)) { - // Filter away tags - if(!r.equals(stm.getObject())) - owners.add(stm.getObject()); - } + // If there are no owners, collect resources referring to this resource by IsRelatedTo + for(Statement statement : graph.getStatements(resource, L0.IsWeaklyRelatedTo)) { + Resource inverse = graph.getPossibleInverse(statement.getPredicate()); + if(inverse != null) { + if(graph.isSubrelationOf(inverse, L0.IsRelatedTo)) { + // Filter away tags + if(resource.equals(statement.getObject())) + continue; + owners.add(statement.getObject()); } } - } else { - System.err.println("Multiple owners for " + graph.getPossibleURI(r) + " id : " + r); - for (Resource r2 : objects) - System.err.println("owner : " + graph.getPossibleURI(r2) + " id " + r2); - return null; } } - - if(!direct.isEmpty()) { - Iterator iter = direct.iterator(); - Resource common = iter.next(); - while (iter.hasNext()) { - Resource other = iter.next(); - common = commonAncestor(graph, common, other); - if (common == null) break; - } - if(common != null) - owners.add(common); + else if(owners.size() > 1) { + // TODO: getObjects returns duplicate entries (https://www.simantics.org/redmine/issues/4885) and therefore direct is Set. + // Fix getObjects to not return duplicate entries + owners = new HashSet(owners); } - - if(!Collections.disjoint(owners, resources)) { - System.err.println("Overlapping owners:"); - for(Resource r : resources) - System.err.println("-resource " + NameUtils.getSafeName(graph, r, true)); - for(Resource r : owners) - System.err.println("-owner " + NameUtils.getSafeName(graph, r, true)); - return null; - } - - if(owners.size() == 1) return owners.iterator().next(); - if(owners.size() == 0) return null; - - return getNearestOwner(graph, owners); - + + return owners; + } + + /** + * This method didn't have a clear specification and therefore should not be used. Use instead + * the methods in the class {@link NearestOwnerFinder}. + */ + @Deprecated + public static Resource getNearestOwner(ReadGraph graph, Collection resources) throws DatabaseException { + if(resources.size() == 1) + return NearestOwnerFinder.getNearestOwner(graph, resources.iterator().next()); + else + return NearestOwnerFinder.getNearestOwnerFromDirectOwners(graph, resources); } public static Resource getClusterSetForNewResource(ReadGraph graph, Resource ... resources) throws DatabaseException { if(resources.length == 1) return getClusterSetForNewResource(graph, resources[0]); - Resource owner = getNearestOwner(graph, CollectionUtils.toList(resources)); + Resource owner = NearestOwnerFinder.getNearestOwnerFromDirectOwners(graph, CollectionUtils.toList(resources)); if(owner == null) return null; return getClusterSetForNewResource(graph, owner, new HashSet()); @@ -143,7 +152,7 @@ public class CommonDBUtils { if(resources.size() == 1) return getClusterSetForNewResource(graph, resources.iterator().next()); - Resource owner = getNearestOwner(graph, resources); + Resource owner = NearestOwnerFinder.getNearestOwnerFromDirectOwners(graph, resources); return getClusterSetForNewResource(graph, owner, new HashSet()); } @@ -193,4 +202,181 @@ public class CommonDBUtils { return graph.syncRequest(new PossibleObjectWithType(subject, relation, type)); } + public static List listClusters(ReadGraph graph) throws DatabaseException { + XSupport xs = graph.getService(XSupport.class); + ClusterUID uids[] = xs.listClusters(); + ArrayList result = new ArrayList<>(uids.length); + for(ClusterUID uid : uids) result.add(uid); + return result; + } + + public static List resourcesByCluster(ReadGraph graph, ClusterUID uid) throws DatabaseException { + SerialisationSupport ss = graph.getService(SerialisationSupport.class); + ArrayList result = new ArrayList(); + // Index 0 is illegal + for(int i=1;i<1<<12;i++) { + try { + result.add(ss.getResource(uid.toRID(i))); + } catch (InvalidResourceReferenceException e) { + } + } + return result; + } + + public static List directStatements(ReadGraph graph, Resource resource, boolean ignoreVirtual) throws DatabaseException { + + DirectQuerySupport dqs = graph.getService(DirectQuerySupport.class); + DirectStatementProcedure proc = new DirectStatementProcedure(); + + if (ignoreVirtual) { + return dqs.getDirectPersistentStatements(graph, resource); + } else { + return dqs.getDirectStatements(graph, resource); + } + + } + + public static List garbageResources(ReadGraph graph) throws DatabaseException { + + SerialisationSupport ss = graph.getService(SerialisationSupport.class); + + TIntArrayList refs = new TIntArrayList(); + TIntArrayList res = new TIntArrayList(); + + // Find all statements in the database + for(ClusterUID uid : listClusters(graph)) { + for(Resource r : resourcesByCluster(graph, uid)) { + int sid = ss.getTransientId(r); + for(Statement stm : directStatements(graph, r, true)) { + int oid = ss.getTransientId(stm.getObject()); + refs.add(sid); + refs.add(oid); + } + res.add(sid); + } + } + + TIntHashSet reached = new TIntHashSet(); + + // Initialize root + int root = ss.getTransientId(graph.getRootLibrary()); + reached.add(root); + + int[] refArray = refs.toArray(); + + boolean changes = true; + + while(changes) { + changes = false; + for(int i=0;i { + public StringAdapterRequest(Resource resource) { + super(resource); + } + @Override + public String perform(ReadGraph graph) throws DatabaseException { + try { + return graph.adapt(resource, String.class); + } catch (AdaptionException e) { + return NameUtils.getSafeName(graph, resource); + } + } + } + }