X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.browsing.ui.common%2Fsrc%2Forg%2Fsimantics%2Fbrowsing%2Fui%2Fcommon%2Finternal%2FGENodeQueryManager.java;fp=bundles%2Forg.simantics.browsing.ui.common%2Fsrc%2Forg%2Fsimantics%2Fbrowsing%2Fui%2Fcommon%2Finternal%2FGENodeQueryManager.java;h=bcbe40f9e2c2d4be9c3ac7336230d351dc628350;hp=0000000000000000000000000000000000000000;hb=969bd23cab98a79ca9101af33334000879fb60c5;hpb=866dba5cd5a3929bbeae85991796acb212338a08 diff --git a/bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/internal/GENodeQueryManager.java b/bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/internal/GENodeQueryManager.java new file mode 100644 index 000000000..bcbe40f9e --- /dev/null +++ b/bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/internal/GENodeQueryManager.java @@ -0,0 +1,512 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.browsing.ui.common.internal; + +import java.util.ArrayList; +import java.util.Deque; +import java.util.List; +import java.util.Set; + +import org.simantics.browsing.ui.DataSource; +import org.simantics.browsing.ui.NodeContext; +import org.simantics.browsing.ui.NodeContext.CacheKey; +import org.simantics.browsing.ui.NodeContext.PrimitiveQueryKey; +import org.simantics.browsing.ui.NodeContext.QueryKey; +import org.simantics.browsing.ui.NodeQueryManager; +import org.simantics.browsing.ui.NodeQueryProcessor; +import org.simantics.browsing.ui.PrimitiveQueryProcessor; +import org.simantics.browsing.ui.PrimitiveQueryUpdater; +import org.simantics.browsing.ui.common.internal.IGECache.IGECacheEntry; +import org.simantics.browsing.ui.exception.NoDataSourceException; +import org.simantics.browsing.ui.exception.NoQueryProcessorException; + +public class GENodeQueryManager implements NodeQueryManager, PrimitiveQueryUpdater { + + private static final boolean DEBUG = false; + + protected IGraphExplorerContext ge; + protected NodeContext parentContext; + protected CacheKey parentKey; + protected UIElementReference treeReference; + protected boolean disposed = false; + List children = new ArrayList(); + + void indent() { + ge.queryIndent(1); + } + + void unindent() { + ge.queryIndent(-1); + } + + void queryDebug(String s) { + for (int i = 0; i < ge.queryIndent(); ++i) + System.err.append(" "); + System.err.println(s); + } + + String toString(UIElementReference ref) { + return ref == null ? "" : ref.toString(); + } + + String toString(Set refs) { + if (refs == null || refs.isEmpty()) + return "{}"; + StringBuilder b = new StringBuilder(); + for (UIElementReference ref : refs) { + b.append(toString(ref)); + } + return b.toString(); + } + + String toString(NodeContext ctx, CacheKey key) { + if (ctx == null) + return "null"; + Set refs = ge.getCache().getTreeReference(ctx, key); + //return String.valueOf(System.identityHashCode(ctx)) + toString(ref); + //return String.valueOf(ctx.hashCode()) + ":" + String.valueOf(System.identityHashCode(ctx)) + toString(ref); + return ctx + toString(refs); + } + + + public GENodeQueryManager(GENodeQueryManager parent, NodeContext parentContext, CacheKey parentKey, UIElementReference treeReference) { + this.ge = parent.ge; + this.parentContext = parentContext; + this.parentKey = parentKey; + this.treeReference = treeReference; + parent.children.add(this); + } + public GENodeQueryManager(IGraphExplorerContext ge, NodeContext parentContext, CacheKey parentKey, UIElementReference treeReference) { + this.ge = ge; + this.parentContext = parentContext; + this.parentKey = parentKey; + this.treeReference = treeReference; + } + + @Override + public Object getExplorerContext() { + return ge; + } + + public void dispose() { + if (disposed) + return; + disposed = true; + if (ge != null && parentContext != null && parentKey != null) { + ge.getCache().remove(parentContext, parentKey); + } + ge = null; + parentContext = null; + parentKey = null; + treeReference = null; + for (GENodeQueryManager m : children) + m.dispose(); + children.clear(); + children = null; + } + +// @Override +// public String toString() { +// return "GENodeQueryManager[parentKey=" + parentKey + ", parentContext=" + "]"; +// } +// +// @Override +// public CacheKey getParentKey() { +// return parentKey; +// } +// +// @Override +// public INodeContext getParentContext() { +// return parentContext; +// } + +// static int koss = 0; + +// @Override + public void replaceResult(NodeContext context, PrimitiveQueryKey key, T newResult, int indent) { + + IGraphExplorerContext ge = this.ge; + if (isDisposed()) + return; + + if(DEBUG) { + queryDebug("replaceResult[" + ge.getCache().hashCode() + "] " + key + " -> " + newResult); + indent(); + } + +// if((koss++ % 5000) == 0) { +// System.out.println("R" + koss); +// } + + IGECache cache = ge.getCache(); + IGECacheEntry oldEntry = cache.getEntry(context, key); + if (oldEntry != null) { + cache.put(context, key, newResult); + propagate(context, key, oldEntry, indent); + + Set refs = cache.removeTreeReference(context, key); + + if (refs != null) { + //queryDebug("(replaceResult) found tree references " + toString(refs)); + for (UIElementReference ref : refs) + ge.update(ref); + } + } else { + // TODO: explain why this check is here or remove it! + + // Consistency checking, no TreeReference should ever exist in this case! + Set ref = cache.getTreeReference(context, key); + assert ref == null; + } + } + +// @Override + public void clearResult(NodeContext context, CacheKey key, int indent) { +// if (key == BuiltinKeys.FINAL_CHILDREN) { +// queryDebug("Clear final children for " + context); +// } + if(DEBUG) queryDebug("clearResult[" + ge.getCache().hashCode() + "] " + key + " " + context); + + IGraphExplorerContext ge = this.ge; + if (isDisposed()) + return; + + IGECache cache = ge.getCache(); + IGECacheEntry entry = cache.getEntry(context, key); + if (entry != null) { + cache.remove(context, key); + propagate(context, key, entry, indent); + } + + Set refs = cache.removeTreeReference(context, key); + if (refs != null) { + //queryDebug("(clearResult) found tree reference " + toString(refs)); + for (UIElementReference ref : refs) + ge.update(ref); + } + } + + public void propagate(NodeContext context, CacheKey key, IGECacheEntry entry, int indent) { + + if (isDisposed()) + return; + + if(DEBUG) queryDebug("propagate[" + ge.getCache().hashCode() + "] " + key + " - " + context); + + assert entry != null; + + for(IGECacheEntry dependency : entry.getDependencies()) { + clearResult(dependency.getContext(), dependency.getKey(), indent + 3); + } + + entry.reset(); + } + + @SuppressWarnings("unchecked") + @Override + public T query(NodeContext context, QueryKey key) throws NoQueryProcessorException { + + assert(!ge.isDisposed()); + + if(DEBUG) { + queryDebug("Query[" + ge.getCache().hashCode() + "] " + key + " " + toString(context, key) + " - " + parentKey + " " + toString(parentContext, parentKey)); + indent(); + } + + assert(!(context == parentContext && key == parentKey)); + + assert(context != null); + assert(key != null); + + T result = null; + IGECache cache = ge.getCache(); + + synchronized(ge.getPropagateLock()) { + + IGECacheEntry entry = cache.getEntry(context, key); + //queryDebug(" CACHED RESULT: " + entry); + if(entry == null) { + entry = cache.put(context, key, null); + NodeQueryProcessor processor = ge.getProcessor(key); + if(processor == null) { + throw new NoQueryProcessorException(key); + } +// queryDebug("PERFORMING QUERY..."); + T value = processor.query(new GENodeQueryManager(this, context, key, null), context); +// queryDebug("RESULT: " + value); + entry.setValue(value); + } + + if(treeReference != null) { + UIElementReference cachedTreeReference = treeReference; + + Set oldRefs = cache.getTreeReference(context, key); + if (oldRefs != null) { + if (cachedTreeReference.isDisposed()) { + oldRefs.remove(cachedTreeReference); + } else { + cache.putTreeReference(context, key, cachedTreeReference); + } + } else { + cache.putTreeReference(context, key, cachedTreeReference); + } + } + + if(parentContext != null) { + assert(parentKey != null); + IGECacheEntry parentEntry = cache.getEntry(parentContext, parentKey); + if(parentEntry != null) + entry.addDependency(parentEntry); + } + + result = (T) entry.getValue(); + } + + unindent(); + return result; + } + + @SuppressWarnings("unchecked") + @Override + public T query(NodeContext context, PrimitiveQueryKey key) throws NoQueryProcessorException { + + assert(!ge.isDisposed()); + + if(DEBUG) { + queryDebug("Primitive Query[" + ge.getCache().hashCode() + "] " + key + " " + toString(context, key) + " - " + parentKey + " " + toString(parentContext, key) + " " + Thread.currentThread().getName()); + indent(); + } + + assert(!(context == parentContext && key == parentKey)); + + // Primitive queries must be leaf queries! + assert(!(parentKey instanceof PrimitiveQueryKey)); + + assert(context != null); + assert(key != null); + + T result = null; + + IGECache cache = ge.getCache(); + + synchronized(ge.getPropagateLock()) { + IGECacheEntry entry = cache.getEntry(context, key); + if(DEBUG) queryDebug(" CACHED PRIMITIVE RESULT[" + cache.hashCode() + "]: " + ((entry != null) ? (entry.hashCode() + "|" + System.identityHashCode(entry)) : 0)); + if(entry == null) { + entry = cache.put(context, key, null); + PrimitiveQueryProcessor processor = ge.getPrimitiveProcessor(key.processorIdenfitier()); + if(processor == null) { + throw new NoQueryProcessorException(key); + } +// queryDebug("PERFORMING PRIMITIVE QUERY..."); + T value = processor.query(new GENodeQueryManager(this, context, key, null), context, key); +// queryDebug("PRIMITIVE RESULT: " + value); + entry.setValue(value); + } + + if(treeReference != null) { + UIElementReference cachedTreeReference = treeReference; + + Set oldRefs = cache.getTreeReference(context, key); + if (oldRefs != null) { + if (cachedTreeReference.isDisposed()) { + oldRefs.remove(cachedTreeReference); + } else { + cache.putTreeReference(context, key, cachedTreeReference); + } + } else { + cache.putTreeReference(context, key, cachedTreeReference); + } + } + + if(parentContext != null) { + assert(parentKey != null); + IGECacheEntry parentEntry = cache.getEntry(parentContext, parentKey); + if(parentEntry != null) { + entry.addDependency(parentEntry); + } + } + + result = (T) entry.getValue(); + } + + unindent(); + return result; + } + + @Override + public DataSource tryGetDataSource(Class clazz) { + return ge.getDataSource(clazz); + } + + @Override + public DataSource getDataSource(Class clazz) { + DataSource dsp = ge.getDataSource(clazz); + if (dsp == null) + throw new NoDataSourceException(clazz); + return dsp; + } + +// @Override +// public void scheduleClear(final INodeContext context, final PrimitiveQueryKey key) { +// ge.scheduler.execute(new Runnable() { +// @Override +// public void run() { +// synchronized(ge.propagate) { +// clearResult(context, key, 0); +// } +// } +// }); +// } + + +// @Override +// public void create(final INodeContext context, final PrimitiveQueryKey key, final T newResult) { +// ge.cache.put(context, key, newResult); +// } + + @Override + public void scheduleReplace(final NodeContext context, final PrimitiveQueryKey key, final T newResult) { + + if(DEBUG) queryDebug("scheduleReplace[" + ge.getCache().hashCode() + "] context=" + context + " key=" + key); + + IGraphExplorerContext ge = this.ge; + if (isDisposed()) + return; + + class PropagateRunner implements Runnable { + + @Override + public void run() { + IGraphExplorerContext ge = GENodeQueryManager.this.ge; + if (isDisposed()) + return; + + int delay = 0; + + List todo = null; + + synchronized(ge.getPropagateListLock()) { + + ge.setPropagating(true); + + List scheduleList = ge.getScheduleList(); + Deque activity = ge.getActivity(); + + activity.addFirst(scheduleList.size()); + activity.pollLast(); + + int activityInt = 0; + for(int i : activity) { + activityInt += i; + } + ge.setActivityInt(activityInt); + + if(activityInt < 100) { + delay = 10; + //System.out.println("Scheduling propagate after 10ms."); + } else if (activityInt < 1000) { + delay = 500; + //System.out.println("Scheduling propagate after 500ms."); + } else { + delay = 3000; + //System.out.println("Scheduling propagate after 3000ms."); + } + + todo = ge.getScheduleList(); + ge.setScheduleList(new ArrayList()); + + } + + try { + if(delay > 0) + Thread.sleep(delay); + } catch (InterruptedException e) { + e.printStackTrace(); + } + if (isDisposed()) + return; + + synchronized(ge.getPropagateLock()) { + + for(Runnable r : todo) r.run(); + + } + if (isDisposed()) + return; + + synchronized(ge.getPropagateListLock()) { + + ge.setPropagating(false); + + if(!ge.getScheduleList().isEmpty()) + ge.scheduleQueryUpdate(new PropagateRunner()); + + } + + } + + } + + synchronized(ge.getPropagateListLock()) { +// System.out.println("Schedule Replace: " + key + " - " + context); +// new Exception().printStackTrace(); + List scheduleList = ge.getScheduleList(); + scheduleList.add(new Runnable() { + @Override + public void run() { + replaceResult(context, key, newResult, 0); + } + }); + + if(ge.isPropagating()) return; + + ge.scheduleQueryUpdate(new PropagateRunner()); + } + } + + @Override + public boolean isDisposed() { + if (disposed) + return true; + if (ge.isDisposed()) { + dispose(); + return true; + } + return false; + } + + @Override + public boolean isShown(NodeContext context) { + IGraphExplorerContext ge = this.ge; + if (isDisposed()) + return false; + return ge.getCache().isShown(context); + } + + @Override + public void incRef(NodeContext context) { + IGraphExplorerContext ge = this.ge; + if (isDisposed()) + return; + ge.getCache().incRef(context); + } + + @Override + public void decRef(NodeContext context) { + IGraphExplorerContext ge = this.ge; + if (isDisposed()) + return; + ge.getCache().decRef(context); + } + +}