X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.modeling%2Fsrc%2Forg%2Fsimantics%2Fmodeling%2Futils%2FBatchValidations.java;fp=bundles%2Forg.simantics.modeling%2Fsrc%2Forg%2Fsimantics%2Fmodeling%2Futils%2FBatchValidations.java;h=3a033ef58760b12d88eb8b7b3d13faf31bee1e43;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/utils/BatchValidations.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/utils/BatchValidations.java new file mode 100644 index 000000000..3a033ef58 --- /dev/null +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/utils/BatchValidations.java @@ -0,0 +1,216 @@ +package org.simantics.modeling.utils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +import org.eclipse.core.runtime.ILog; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; +import org.simantics.Simantics; +import org.simantics.db.Issue; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.db.VirtualGraph; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.WriteRequest; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.util.ModelTransferableGraphSourceRequest; +import org.simantics.db.layer0.util.RemoverUtil; +import org.simantics.db.service.VirtualGraphSupport; +import org.simantics.issues.common.AllBatchIssueSources; +import org.simantics.issues.common.BatchIssueDescriptions; +import org.simantics.issues.common.BatchIssueSource; +import org.simantics.issues.common.BatchIssueValidationContext; +import org.simantics.issues.common.ComposedValidation; +import org.simantics.issues.common.IssueByList; +import org.simantics.issues.common.IssueConstants; +import org.simantics.issues.ontology.IssueResource; +import org.simantics.issues.preferences.IssuePreferenceUtil; +import org.simantics.layer0.Layer0; +import org.simantics.modeling.internal.Plugin; +import org.simantics.modeling.requests.CollectionRequest; +import org.simantics.modeling.requests.CollectionResult; +import org.simantics.modeling.requests.Node; +import org.simantics.utils.page.PageDesc; + +import gnu.trove.set.hash.THashSet; + +public class BatchValidations { + + private static final boolean PERF = false; + + public static Collection fillConfig(IProgressMonitor monitor, Collection models) throws DatabaseException { + final CollectionResult result = Simantics.getSession().syncRequest(new CollectionRequest(monitor, PageDesc.DEFAULT, models.toArray(Resource.NONE))); + if (result == null) + return Collections.emptyList(); + return toComposites(result.breadthFirstFlatten()); + } + + private static Collection toComposites(Collection nodes) { + Collection result = new ArrayList(nodes.size()); + for (Node n : nodes) { + Resource composite = n.getDefiningResources().resources[0]; + Resource diagram = n.getDiagramResource(); + if (composite != null && diagram != null) + result.add(composite); + } + return result; + } + + public static Map> validate(IProgressMonitor monitor, BatchIssueSource source, BatchIssueValidationContext context) throws DatabaseException { + Session session = Simantics.getSession(); + return session.syncRequest(new ComposedValidation(monitor, source, context)); + } + + /** + * @param monitor + * @param source + * @param issues + * @return + * @throws DatabaseException + */ + public static int store(final IProgressMonitor monitor, + final Resource source, final Map> issues) + throws DatabaseException { + return store(monitor, source, issues, Integer.MAX_VALUE); + } + + /** + * @param monitor + * @param source + * @param issues + * @param maxIssuesToWrite + * @return number of issues written (added) + * @throws DatabaseException + */ + public static int store(final IProgressMonitor monitor, + final Resource source, final Map> issues, + final int maxIssuesToWrite) throws DatabaseException { + + if (issues.isEmpty() || maxIssuesToWrite <= 0) + return 0; + + Session session = Simantics.getSession(); + VirtualGraphSupport support = session.getService(VirtualGraphSupport.class); + VirtualGraph vg = support.getWorkspacePersistent(IssueConstants.ISSUE_VG); + final int[] writtenIssues = { 0 }; + + session.syncRequest(new WriteRequest(vg) { + + @Override + public void perform(WriteGraph graph) throws DatabaseException { + + for(Map.Entry> entry : issues.entrySet()) { + + if (monitor.isCanceled()) + return; + + Resource context = entry.getKey(); + + Set current = entry.getValue(); + Set existing = graph.sync(new BatchIssueDescriptions(source, context)); + + if(!existing.equals(current)) { + + Set added = new THashSet(current); + Set removed = new THashSet(existing); + added.removeAll(existing); + removed.removeAll(current); + + for(Issue add : added) { + add.write(graph, source); + // Stop if write limit is reached. + if (++writtenIssues[0] >= maxIssuesToWrite) + return; + } + for(Issue remove : removed) { + Resource issue = graph.sync(new IssueByList(source, remove)); + if (issue == null) + // FIXME: when can this happen and what should be done in this case? + continue; + graph.deny(issue, Layer0.getInstance(graph).PartOf); + graph.deny(source, IssueResource.getInstance(graph).IssueSource_Manages, issue); + RemoverUtil.remove(graph, issue); + } + + } + + } + + } + }); + + return writtenIssues[0]; + + } + + public static void runAll(IProgressMonitor monitor, Resource model) throws DatabaseException { + runAll(monitor, model, model); + } + + public static void runAll(IProgressMonitor monitor, Resource model, Resource resource) throws DatabaseException { + final Session session = Simantics.getSession(); + final Collection validations = session.sync( new AllBatchIssueSources(model) ); + SubMonitor progress = SubMonitor.convert(monitor, "Validate Model", 100*validations.size()); + BatchIssueValidationContext context = new BatchIssueValidationContext(); + context.domain = ModelTransferableGraphSourceRequest.getDomainOnly(session, monitor, resource); + context.contexts = fillConfig(progress, Collections.singletonList(resource)); + int maxWrittenIssues = IssuePreferenceUtil.getPreferences().maxBatchIssuesToWrite; + int totalIssueCount = 0; + int writtenIssueCount = 0; + if (!context.contexts.isEmpty()) { + long t0 = System.nanoTime(); + for(BatchIssueSource bis : validations) { + if (monitor.isCanceled()) + return; + long startTime = System.nanoTime(); + if (PERF) + System.out.println("validate " + bis); + Map> is = validate(progress.newChild(90, SubMonitor.SUPPRESS_NONE), bis, context); + int issueCount = count(is); + long validationTime = System.nanoTime(); + if (PERF) + System.out.println("store " + issueCount + " issues"); + int wroteIssues = store(progress.newChild(10, SubMonitor.SUPPRESS_NONE), bis.getResource(), is, Math.max(0, maxWrittenIssues - writtenIssueCount)); + totalIssueCount += issueCount; + writtenIssueCount += wroteIssues; + long writeTime = System.nanoTime(); + if (PERF) { + System.out.println("validation time: " + ((validationTime-startTime)*1e-9) + " s"); + System.out.println("issue store time: " + ((writeTime-validationTime)*1e-9) + " s"); + } + } + long tf = System.nanoTime(); + if (PERF) { + System.out.println("total validation time: " + ((tf-t0)*1e-9) + " s"); + } + } + if (totalIssueCount > maxWrittenIssues) { + ILog log = Platform.getLog(Platform.getBundle(Plugin.PLUGIN_ID)); + log.log(new Status(IStatus.WARNING, Plugin.PLUGIN_ID, "Batch issue validation produced " + totalIssueCount + " issues which is more than it was allowed to write into the database. The write limit was " + maxWrittenIssues + ".")); + } + } + + /** + * @param map + * @return + */ + @SuppressWarnings("rawtypes") + private static int count(Map map) { + int result = 0; + for (Object obj : map.values()) { + if (obj instanceof Set) { + Set set = (Set) obj; + result += set.size(); + } + } + return result; + } + +}