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.Collection;
15 import java.util.concurrent.Semaphore;
17 import org.simantics.databoard.Bindings;
18 import org.simantics.db.DevelopmentKeys;
19 import org.simantics.db.RelationInfo;
20 import org.simantics.db.Resource;
21 import org.simantics.db.common.exception.DebugException;
22 import org.simantics.db.exception.DatabaseException;
23 import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
24 import org.simantics.db.impl.graph.ReadGraphImpl;
25 import org.simantics.db.impl.procedure.IntProcedureAdapter;
26 import org.simantics.db.impl.procedure.InternalProcedure;
27 import org.simantics.db.procedure.AsyncMultiProcedure;
28 import org.simantics.db.procedure.ListenerBase;
29 import org.simantics.db.request.RequestFlags;
30 import org.simantics.utils.Development;
36 * statusOrException 4 byte
38 * p2OrParents = 4 byte
45 final public class Objects extends CollectionBinaryQuery<IntProcedure> {
47 public Objects(final int r1, final int r2) {
51 final static Objects entry(final QueryProcessor provider, final int r1, final int r2) {
52 return (Objects)provider.cache.objectsMap.get(r1,r2);
55 final static Collection<Objects> entries(final QueryProcessor processor, final int r1) {
56 return processor.cache.objectsMap.values(r1);
59 public final static void runner(ReadGraphImpl graph, final int r1, final int r2, CacheEntry parent, ListenerBase listener, final IntProcedure procedure) {
61 if(parent == null && listener == null) {
62 Objects.computeForEach(graph, r1, r2, null, procedure);
66 QueryProcessor processor = graph.processor;
68 Objects entry = (Objects)processor.cache.objectsMap.get(r1,r2);
71 entry = new Objects(r1, r2);
73 entry.clearResult(processor.querySupport);
74 entry.putEntry(processor);
76 processor.performForEach(graph, entry, parent, listener, procedure);
80 if(entry.isPending()) {
82 if(entry.isPending()) {
83 processor.registerDependencies(graph, entry, parent, listener, procedure, false);
84 computeForEach(graph, r1, r2, null, procedure);
90 processor.performForEach(graph, entry, parent, listener, procedure);
96 static class Runner2Procedure implements IntProcedure {
98 public int single = 0;
99 public Throwable t = null;
101 public void clear() {
107 public void execute(ReadGraphImpl graph, int i) {
108 if(single == 0) single = i;
113 public void finished(ReadGraphImpl graph) {
114 if(single == -1) single = 0;
118 public void exception(ReadGraphImpl graph, Throwable throwable) {
123 public int get() throws DatabaseException {
125 if(t instanceof DatabaseException) throw (DatabaseException)t;
126 else throw new DatabaseException(t);
133 static final Runner2Procedure runner2Procedure = new Runner2Procedure();
135 public final static int runner2(ReadGraphImpl graph, final int r1, final int r2, CacheEntry parent) throws DatabaseException {
137 runner2Procedure.clear();
140 Objects.computeForEach(graph, r1, r2, null, runner2Procedure);
141 return runner2Procedure.get();
144 QueryProcessor processor = graph.processor;
146 Objects entry = (Objects)processor.cache.objectsMap.get(r1,r2);
149 entry = new Objects(r1, r2);
151 entry.clearResult(processor.querySupport);
152 entry.putEntry(processor);
154 processor.performForEach(graph, entry, parent, null, runner2Procedure);
155 return runner2Procedure.get();
159 if(entry.isPending()) throw new IllegalStateException();
161 processor.performForEach(graph, entry, parent, null, runner2Procedure);
162 return runner2Procedure.get();
169 public BinaryQuery<IntProcedure> getEntry(QueryProcessor provider) {
170 return provider.cache.objectsMap.get(id);
174 public void putEntry(QueryProcessor provider) {
175 if(Development.DEVELOPMENT) {
176 if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_PUT, Bindings.BOOLEAN)) {
177 System.err.println("put " + this);
180 provider.cache.objectsMap.put(id, this);
184 final public void removeEntry(QueryProcessor provider) {
185 provider.cache.objectsMap.remove(id);
188 final static private IntArray getAssertionMap(ReadGraphImpl graph, final int r1, final int r2, final Objects entry) {
190 class AssertionMapProc implements IntProcedure {
192 boolean first = true;
194 private IntArray result;
196 public void addStatement(int s, int p, int o) {
198 if(result.size() == 0) {
203 for(int i = 0;i < result.sizeOrData ; i+=3) {
204 int existingP = result.data[i+1];
206 int existingO = result.data[i+2];
207 if(existingO == o) return;
218 public void execute(ReadGraphImpl graph, int type) {
219 AssertedStatements stms = AssertedStatements.queryEach(graph, type, r2, graph.processor, entry, null, NOPT);
221 result = stms.getResult();
224 IntArray ia = result;
225 result = new IntArray();
226 if(ia.data != null) {
227 for(int i = 0;i < ia.sizeOrData ; i+=3) addStatement(ia.data[i],ia.data[i+1],ia.data[i+2]);
231 IntArray ia = stms.getResult();
232 if(ia.data != null) {
233 for(int i = 0;i < ia.sizeOrData ; i+=3) addStatement(ia.data[i],ia.data[i+1],ia.data[i+2]);
239 public void finished(ReadGraphImpl graph) {
243 public void exception(ReadGraphImpl graph, Throwable throwable) {
248 AssertionMapProc amp = new AssertionMapProc();
250 // This dependency could be cut
251 PrincipalTypes.queryEach(graph, r1, graph.processor, entry, null, amp);
257 final static private void forSingleAssertion(ReadGraphImpl graph, final int r1, final int r2, final Objects entry, final IntProcedure procedure) {
259 IntArray map = getAssertionMap(graph, r1, r2, entry);
261 if(entry != null) entry.finish(graph, procedure);
262 else procedure.finished(graph);
266 int size = map.size();
269 int value = map.data[2];
272 entry.addOrSetFunctional(value);
273 entry.finish(graph, procedure);
275 procedure.execute(graph, value);
276 procedure.finished(graph);
279 } else if(size == 0) {
281 if(entry != null) entry.finish(graph, procedure);
282 else procedure.finished(graph);
286 int candidateS = map.data[0];
287 int candidateO = map.data[2];
289 SuperTypes candidate = SuperTypes.queryEach(graph, candidateS, graph.processor, entry, null, NOP);
290 if(candidate.isExcepted()) {
291 if(entry != null) entry.except((Throwable)candidate.getResult());
292 procedure.exception(graph, (Throwable)candidate.getResult());
295 IntSet candidateIs = candidate.getResult();
297 for(int i=3;i<map.size();i+=3) {
299 int nextS = map.data[i];
300 int nextO = map.data[i+2];
302 if(nextS != candidateS) {
304 if(candidateIs.contains(nextS)) {
306 // Next is a super type of candidate => ignore next
310 SuperTypes next = SuperTypes.queryEach(graph, nextS, graph.processor, entry, null, NOP);
311 if(next.isExcepted()) {
312 if(entry != null) entry.except((Throwable)next.getResult());
313 procedure.exception(graph, (Throwable)next.getResult());
316 IntSet nextIs = next.getResult();
318 if(nextIs.contains(candidateS)) {
320 // Candidate is a super type of next => next is the new candidate
324 candidateIs = nextIs;
328 // candidate and next are unrelated => error
329 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has conflicting assertions " + r1 + ", " + r2 + " " + map , r1);
331 if(entry != null) entry.except(exception);
332 procedure.exception(graph, exception);
344 entry.addOrSetFunctional(candidateO);
345 entry.finish(graph, procedure);
347 procedure.execute(graph, candidateO);
348 procedure.finished(graph);
355 final static InternalProcedure<IntSet> NOP = new InternalProcedure<IntSet>() {
358 public void execute(ReadGraphImpl graph, IntSet result) {
362 public void exception(ReadGraphImpl graph, Throwable throwable) {
367 final static TripleIntProcedure NOPT = new TripleIntProcedure() {
371 public void exception(ReadGraphImpl graph, Throwable throwable) {
375 public void execute(ReadGraphImpl graph, int s, int p, int o) {
379 public void finished(ReadGraphImpl graph) {
384 // Search for one statement
385 final public void computeFunctionalIndex(ReadGraphImpl graph, final QueryProcessor provider, final RelationInfo ri, final IntProcedure procedure) {
386 computeFunctionalIndex(graph, r1(), r2(), this, ri, procedure);
389 // Search for one statement
390 final static public void computeFunctionalIndex(ReadGraphImpl graph, final int r1, final int r2, final Objects entry, final RelationInfo ri, final IntProcedure procedure) {
394 int result = graph.processor.querySupport.getFunctionalObject(r1, r2);
398 // Check for assertions
399 forSingleAssertion(graph, r1, r2, entry, procedure);
401 } else if (result == -1) {
403 graph.processor.querySupport.getObjects(graph, r1, r2, new IntProcedure() {
406 public void execute(ReadGraphImpl graph, int i) {
407 if(entry != null) entry.addOrSetFunctional(i);
408 else procedure.execute(graph, i);
412 public void exception(ReadGraphImpl graph, Throwable t) {
413 if(DebugException.DEBUG) new DebugException(t).printStackTrace();
417 public void finished(ReadGraphImpl graph) {
422 // Check for assertions
423 forSingleAssertion(graph, r1, r2, entry, procedure);
427 // If functional relation was found there is no need to check assertions
429 entry.addOrSetFunctional(result);
430 entry.finish(graph, procedure);
432 procedure.execute(graph, result);
433 procedure.finished(graph);
441 // Note! The dependency is intentionally cut!
442 DirectPredicates.queryEach(graph, r1, graph.processor, null, null, new SyncIntProcedure() {
444 boolean found = false;
447 public void run(ReadGraphImpl graph) {
450 if(entry != null) entry.finish(graph, procedure);
451 else procedure.finished(graph);
454 // Check for assertions
455 forSingleAssertion(graph, r1, r2, entry, procedure);
462 public void execute(ReadGraphImpl graph, final int pred) {
468 // Note! The dependency is intentionally cut!
469 DirectObjects.queryEach(graph, r1, pred, graph.processor, null, null, new IntProcedure() {
472 public void execute(ReadGraphImpl graph, int i) {
476 if(entry != null) entry.addOrSetFunctional(i);
477 else procedure.execute(graph, i);
483 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has more than one statement (r1=" + r1 + ", r2=" + r2 + ").", r1);
484 if(entry != null) entry.except(exception);
485 procedure.exception(graph, exception);
492 public void finished(ReadGraphImpl graph) {
496 public void exception(ReadGraphImpl graph, Throwable t) {
497 procedure.exception(graph, t);
504 SuperRelations.queryEach(graph, pred, graph.processor, entry, null, new InternalProcedure<IntSet>() {
507 public void execute(ReadGraphImpl graph, IntSet result) {
511 if(result.contains(r2)) {
513 // Note! The dependency is intentionally cut!
514 DirectObjects.queryEach(graph, r1, pred, graph.processor, null, null, new IntProcedure() {
517 public void execute(ReadGraphImpl graph, int i) {
521 if(entry != null) entry.addOrSetFunctional(i);
522 else procedure.execute(graph, i);
528 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has more than one statement (r1=" + r1 + ", r2=" + r2 + ").", r1);
529 if(entry != null) entry.except(exception);
530 procedure.exception(graph, exception);
537 public void finished(ReadGraphImpl graph) {
541 public void exception(ReadGraphImpl graph, Throwable t) {
542 procedure.exception(graph, t);
552 public void exception(ReadGraphImpl graph, Throwable t) {
553 procedure.exception(graph, t);
563 public void finished(ReadGraphImpl graph) {
576 final static private void forAssertions(ReadGraphImpl graph, final int r1, final int r2, final Objects entry, final IntProcedure procedure) {
578 // Note! The dependency is intentionally cut!
579 PrincipalTypes.queryEach(graph, r1, graph.processor, null, null, new SyncIntProcedure() {
582 public void run(ReadGraphImpl graph) {
584 if(entry != null) entry.finish(graph, procedure);
585 else procedure.finished(graph);
589 TripleIntProcedure proc = new TripleIntProcedure() {
592 public void execute(ReadGraphImpl graph, int s, int p, int o) {
593 if(entry != null) entry.addOrSet(o);
594 else procedure.execute(graph, o);
598 public void finished(ReadGraphImpl graph) {
603 public void exception(ReadGraphImpl graph, Throwable t) {
604 if(DebugException.DEBUG) new DebugException(t).printStackTrace();
605 procedure.exception(graph, t);
612 public void execute(ReadGraphImpl graph, int type) {
616 AssertedStatements.queryEach(graph, type, r2, graph.processor, entry, null, proc);
621 public void finished(ReadGraphImpl graph) {
630 final public static void computeNotFunctionalFinalIndex(ReadGraphImpl graph, final int r1, final int r2, final QueryProcessor provider, RelationInfo ri, AsyncMultiProcedure<Resource> procedure) {
636 final public void computeNotFunctionalIndex(ReadGraphImpl graph, RelationInfo ri, final IntProcedure procedure) {
637 computeNotFunctionalIndex(graph, r1(), r2(), this, ri, procedure);
640 final static public void computeNotFunctionalIndex(ReadGraphImpl graph, final int r1, final int r2, final Objects entry, RelationInfo ri, final IntProcedure procedure) {
644 graph.processor.querySupport.getObjects(graph, r1, r2, new IntProcedure() {
647 public void execute(ReadGraphImpl graph, int i) {
648 if(entry != null) entry.addOrSet(i);
649 else procedure.execute(graph, i);
653 public void exception(ReadGraphImpl graph, Throwable t) {
654 if(DebugException.DEBUG) new DebugException(t).printStackTrace();
655 procedure.exception(graph, t);
659 public void finished(ReadGraphImpl graph) {
665 forAssertions(graph, r1, r2, entry, procedure);
667 if(entry != null) entry.finish(graph, procedure);
668 else procedure.finished(graph);
673 // Note! The dependency is intentionally cut!
674 DirectPredicates.queryEach(graph, r1, graph.processor, null, null, new SyncIntProcedure() {
677 public void run(ReadGraphImpl graph) {
679 forAssertions(graph, r1, r2, entry, procedure);
684 public void execute(ReadGraphImpl graph, final int pred) {
690 // Note! The dependency is intentionally cut!
691 DirectObjects.queryEach(graph, r1, pred, graph.processor, null, null, new IntProcedure() {
694 public void execute(ReadGraphImpl graph, int i) {
695 if(entry != null) entry.addOrSet(i);
696 else procedure.execute(graph, i);
700 public void finished(ReadGraphImpl graph) {
705 public void exception(ReadGraphImpl graph, Throwable t) {
706 procedure.exception(graph, t);
716 SuperRelations.queryEach(graph, pred, graph.processor, entry, null, new InternalProcedure<IntSet>() {
719 public void execute(ReadGraphImpl graph, IntSet result) {
721 if(result.contains(r2)) {
725 // Note! The dependency is intentionally cut!
726 DirectObjects.queryEach(graph, r1, pred, graph.processor, null, null, new IntProcedure() {
729 public void execute(ReadGraphImpl graph, int i) {
730 if(entry != null) entry.addOrSet(i);
731 else procedure.execute(graph, i);
735 public void finished(ReadGraphImpl graph) {
740 public void exception(ReadGraphImpl graph, Throwable t) {
741 if(DebugException.DEBUG) new DebugException(t).printStackTrace();
742 procedure.exception(graph, t);
755 public void exception(ReadGraphImpl graph, Throwable t) {
756 procedure.exception(graph, t);
767 public void finished(ReadGraphImpl graph) {
778 public void computeForEach(ReadGraphImpl graph, final QueryProcessor provider, final IntProcedure procedure, final boolean store) {
779 computeForEach(graph, r1(), r2(), this, procedure);
782 public static void computeForEach(ReadGraphImpl graph, final int r1, final int r2, final Objects entry, final IntProcedure procedure) {
784 RelationInfo ri = RelationInfoQuery.queryEach(graph, r2, graph.processor, entry, null, ip);
785 graph.ensureLoaded(r1, r2);
786 if(ri.isFunctional) {
787 computeFunctionalIndex(graph, r1, r2, entry, ri, procedure);
789 computeNotFunctionalIndex(graph, r1, r2, entry, ri, procedure);
794 final static InternalProcedure<RelationInfo> ip = new InternalProcedure<RelationInfo>() {
797 public void execute(ReadGraphImpl graph, RelationInfo result) {
801 public void exception(ReadGraphImpl graph, Throwable throwable) {
807 public String toString() {
808 return "Objects[" + r1() + " - " + r2() + "]";
811 final private void finish(ReadGraphImpl graph, IntProcedure procedure) {
813 assert(assertPending());
819 IntArray v = (IntArray)getResult();
822 if(v.sizeOrData != IntArray.NO_DATA) {
823 procedure.execute(graph, v.sizeOrData);
826 for(int i = 0;i < v.sizeOrData ; i++) {
827 procedure.execute(graph, v.data[i]);
831 procedure.finished(graph);
835 final public void addOrSet(int add) {
837 assert(assertPending());
839 IntArray value = (IntArray)getResult();
840 synchronized(value) {
846 final public void addOrSetFunctional(int add) {
850 IntArray value = (IntArray)getResult();
856 public Object performFromCache(ReadGraphImpl graph, QueryProcessor provider, final IntProcedure procedure) {
860 if(handleException(graph, procedure)) return getResult();
862 final IntArray value = (IntArray)getResult();
863 if(value.data == null) {
864 if(value.sizeOrData != IntArray.NO_DATA) procedure.execute(graph, value.sizeOrData);
866 for(int i = 0;i < value.sizeOrData ; i++) procedure.execute(graph, value.data[i]);
869 procedure.finished(graph);
876 public void recompute(ReadGraphImpl graph, QueryProcessor provider) {
878 final Semaphore s = new Semaphore(0);
880 computeForEach(graph, provider, new IntProcedureAdapter() {
883 public void finished(ReadGraphImpl graph) {
888 public void exception(ReadGraphImpl graph, Throwable t) {
890 new Error("Error in recompute.", t).printStackTrace();
895 while(!s.tryAcquire()) {
896 provider.resume(graph);
903 return RequestFlags.IMMEDIATE_UPDATE;
907 boolean isImmutable(ReadGraphImpl graph) {
908 return graph.processor.isImmutable(r1());