1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.db.impl.query;
14 import java.util.concurrent.Semaphore;
15 import java.util.concurrent.atomic.AtomicBoolean;
17 import org.simantics.db.RelationInfo;
18 import org.simantics.db.exception.DatabaseException;
19 import org.simantics.db.impl.graph.ReadGraphImpl;
20 import org.simantics.db.impl.procedure.InternalProcedure;
21 import org.simantics.db.procedure.ListenerBase;
22 import org.simantics.db.request.RequestFlags;
24 final public class RelationInfoQuery extends UnaryQuery<InternalProcedure<RelationInfo>> {
26 private RelationInfoQuery(final int resource) {
30 final static RelationInfo runner(ReadGraphImpl graph, final int r, final QueryProcessor provider, final CacheEntry parent, final ListenerBase listener, final InternalProcedure<RelationInfo> procedure) {
32 RelationInfoQuery entry = (RelationInfoQuery)provider.cache.relationInfoMap.get(r);
35 entry = new RelationInfoQuery(r);
37 entry.clearResult(provider.querySupport);
38 entry.putEntry(provider);
40 provider.performForEach(graph, entry, parent, listener, procedure);
42 return entry.getResult();
46 if(!entry.isReady()) {
48 if(!entry.isReady()) {
49 throw new IllegalStateException();
50 // if(entry.procs == null) entry.procs = new ArrayList<InternalProcedure<RelationInfo>>();
51 // entry.procs.add(procedure);
52 // provider.registerDependencies(graph, entry, parent, listener, procedure, false);
53 // return entry.getResult();
57 provider.performForEach(graph, entry, parent, listener, procedure);
59 return entry.getResult();
65 final public static RelationInfo queryEach(ReadGraphImpl graph, final int r, final QueryProcessor provider, final CacheEntry parent, final ListenerBase listener, final InternalProcedure<RelationInfo> procedure) {
67 RelationInfoQuery entry = (RelationInfoQuery)provider.cache.relationInfoMap.get(r);
68 if(entry != null && entry.isReady()) {
69 entry.performFromCache(graph, provider, procedure);
70 return entry.getResult();
73 return runner(graph, r, provider, parent, listener, procedure);
77 final public static RelationInfoQuery probe(ReadGraphImpl graph, int resource) {
79 final int thread = graph.thread(resource);
80 RelationInfoQuery entry = (RelationInfoQuery)graph.processor.cache.relationInfoMap.get(resource);
81 if(entry != null && entry.isReady()) {
90 public UnaryQuery<InternalProcedure<RelationInfo>> getEntry(QueryProcessor provider) {
91 return provider.cache.relationInfoMap.get(id);
95 public void putEntry(QueryProcessor provider) {
96 provider.cache.relationInfoMap.put(id, this);
100 final public void removeEntry(QueryProcessor provider) {
101 provider.cache.relationInfoMap.remove(id);
104 private void computeAssertions(ReadGraphImpl graph, final boolean isFinal, final boolean isFunctional, final QueryProcessor queryProvider, final InternalProcedure<RelationInfo> proc) {
106 final int isUsedInAssertion = queryProvider.getHasPredicateInverse();
107 assert(isUsedInAssertion != 0);
109 DirectObjects.queryEach(graph, id, isUsedInAssertion, queryProvider, this, null, new IntProcedure() {
111 AtomicBoolean done = new AtomicBoolean(false);
114 public void execute(ReadGraphImpl graph, int i) {
115 if(done.compareAndSet(false, true)) {
116 // System.err.println("Assertions for relation " + id);
117 RelationInfo result = new RelationInfo(id, isFunctional, isFinal, true);
118 addOrSet(graph, result, queryProvider);
119 proc.execute(graph, result);
124 public void finished(ReadGraphImpl graph) {
125 if(done.compareAndSet(false, true)) {
126 // System.err.println("No assertions for relation " + id);
127 RelationInfo result = new RelationInfo(id, isFunctional, isFinal, false);
128 addOrSet(graph, result, queryProvider);
129 proc.execute(graph, result);
134 public void exception(ReadGraphImpl graph, Throwable throwable) {
135 if(done.compareAndSet(false, true)) {
136 DatabaseException e = new DatabaseException("Internal error in RelationInfoQuery");
138 proc.exception(graph, e);
144 // Types.queryEach(callerThread, id, queryProvider, this, null, new InternalProcedure<IntSet>() {
147 // public void execute(int callerThread, IntSet types) {
148 // computeAssertions(callerThread, isFinal, isFunctional, queryProvider, proc);
151 ////// System.out.println("RelationInfoQuery: computeTypes execute " + types);
153 //// RelationInfo result = new RelationInfo(id, types.contains(queryProvider.getFunctionalRelation()), isFinal);
155 //// addOrSet(callerThread, result, queryProvider);
157 //// proc.execute(callerThread, result);
162 // public void exception(int callerThread, Throwable t) {
163 // proc.exception(callerThread, t);
170 private void computeTypes(ReadGraphImpl graph, final boolean isFinal, final QueryProcessor queryProvider, final InternalProcedure<RelationInfo> proc) {
172 // System.out.println("RelationInfoQuery: computeTypes " + id);
174 Types.queryEach(graph, id, queryProvider, this, null, new InternalProcedure<IntSet>() {
177 public void execute(ReadGraphImpl graph, IntSet types) {
178 computeAssertions(graph, isFinal, types.contains(queryProvider.getFunctionalRelation()), queryProvider, proc);
180 //// System.out.println("RelationInfoQuery: computeTypes execute " + types);
182 // RelationInfo result = new RelationInfo(id, types.contains(queryProvider.getFunctionalRelation()), isFinal);
184 // addOrSet(callerThread, result, queryProvider);
186 // proc.execute(callerThread, result);
191 public void exception(ReadGraphImpl graph, Throwable t) {
192 proc.exception(graph, t);
200 public Object computeForEach(ReadGraphImpl graph, final QueryProcessor provider, final InternalProcedure<RelationInfo> procedure, boolean store) {
202 // System.out.println("RelationInfoQuery computeForEach begin " + id + " " + getResult() + " " + statusOrException);
204 final int superRelationOf = provider.getSuperrelationOf();
205 assert(superRelationOf != 0);
207 DirectPredicates.queryEach(graph, id, provider, this, null, new IntProcedure() {
209 boolean found = false;
212 public void execute(ReadGraphImpl graph, int i) {
213 // System.out.println("RelationInfoQuery: execute " + i + " super = " + superRelationOf);
214 if(i == superRelationOf) {
215 computeTypes(graph, false, provider, procedure);
221 public void finished(ReadGraphImpl graph) {
222 // System.out.println("RelationInfoQuery: finished");
224 computeTypes(graph, true, provider, procedure);
229 public void exception(ReadGraphImpl graph, Throwable t) {
230 // System.out.println("RelationInfoQuery: exception");
231 procedure.exception(graph, t);
241 public String toString() {
242 return "RelationInfoQuery[" + id + "]";
245 public void addOrSet(ReadGraphImpl graph, final RelationInfo result, final QueryProcessor provider) {
249 // ArrayList<InternalProcedure<RelationInfo>> p = null;
262 // for(InternalProcedure<RelationInfo> proc : p)
263 // proc.execute(graph, (RelationInfo)result);
269 public Object performFromCache(ReadGraphImpl graph, QueryProcessor provider, InternalProcedure<RelationInfo> procedure) {
273 if(handleException(graph, procedure)) return EXCEPTED;
275 RelationInfo result = getResult();
277 procedure.execute(graph, result);
284 public void recompute(ReadGraphImpl graph, QueryProcessor provider) {
286 final Semaphore s = new Semaphore(0);
288 computeForEach(graph, provider, new InternalProcedure<RelationInfo>() {
291 public void execute(ReadGraphImpl graph, RelationInfo result) {
296 public void exception(ReadGraphImpl graph, Throwable t) {
297 throw new Error("Error in recompute.", t);
302 while(!s.tryAcquire()) {
303 provider.resume(graph);
307 // } catch (InterruptedException e) {
308 // throw new Error(e);
315 return RequestFlags.IMMEDIATE_UPDATE;