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.objectsMap.get(r1,r2);
55 final static Collection<Objects> entries(final QueryProcessor processor, final int r1) {
56 return processor.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 if(Development.DEVELOPMENT)
63 Development.recordHistogram(new Objects(r1, r2).toString());
65 Objects.computeForEach(graph, r1, r2, null, procedure);
69 QueryProcessor processor = graph.processor;
71 Objects entry = (Objects)processor.objectsMap.get(r1,r2);
74 entry = new Objects(r1, r2);
76 entry.clearResult(processor.querySupport);
77 entry.putEntry(processor);
79 if(Development.DEVELOPMENT)
80 Development.recordHistogram(entry.toString());
82 processor.performForEach(graph, entry, parent, listener, procedure);
86 if(entry.isPending()) {
88 if(entry.isPending()) {
89 processor.registerDependencies(graph, entry, parent, listener, procedure, false);
90 computeForEach(graph, r1, r2, null, procedure);
96 processor.performForEach(graph, entry, parent, listener, procedure);
102 static class Runner2Procedure implements IntProcedure {
104 public int single = 0;
105 public Throwable t = null;
107 public void clear() {
113 public void execute(ReadGraphImpl graph, int i) {
114 if(single == 0) single = i;
119 public void finished(ReadGraphImpl graph) {
120 if(single == -1) single = 0;
124 public void exception(ReadGraphImpl graph, Throwable throwable) {
129 public int get() throws DatabaseException {
131 if(t instanceof DatabaseException) throw (DatabaseException)t;
132 else throw new DatabaseException(t);
139 static final Runner2Procedure runner2Procedure = new Runner2Procedure();
141 public final static int runner2(ReadGraphImpl graph, final int r1, final int r2, CacheEntry parent) throws DatabaseException {
143 runner2Procedure.clear();
146 Objects.computeForEach(graph, r1, r2, null, runner2Procedure);
147 return runner2Procedure.get();
150 QueryProcessor processor = graph.processor;
152 Objects entry = (Objects)processor.objectsMap.get(r1,r2);
155 entry = new Objects(r1, r2);
157 entry.clearResult(processor.querySupport);
158 entry.putEntry(processor);
160 processor.performForEach(graph, entry, parent, null, runner2Procedure);
161 return runner2Procedure.get();
165 if(entry.isPending()) throw new IllegalStateException();
167 processor.performForEach(graph, entry, parent, null, runner2Procedure);
168 return runner2Procedure.get();
175 public BinaryQuery<IntProcedure> getEntry(QueryProcessor provider) {
176 return provider.objectsMap.get(id);
180 public void putEntry(QueryProcessor provider) {
181 if(Development.DEVELOPMENT) {
182 if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_PUT, Bindings.BOOLEAN)) {
183 System.err.println("put " + this);
186 provider.objectsMap.put(id, this);
190 final public void removeEntry(QueryProcessor provider) {
191 provider.objectsMap.remove(id);
194 final static private IntArray getAssertionMap(ReadGraphImpl graph, final int r1, final int r2, final Objects entry) {
196 class AssertionMapProc implements IntProcedure {
198 boolean first = true;
200 private IntArray result;
202 public void addStatement(int s, int p, int o) {
204 if(result.size() == 0) {
209 for(int i = 0;i < result.sizeOrData ; i+=3) {
210 int existingP = result.data[i+1];
212 int existingO = result.data[i+2];
213 if(existingO == o) return;
224 public void execute(ReadGraphImpl graph, int type) {
225 AssertedStatements stms = AssertedStatements.queryEach(graph, type, r2, graph.processor, entry, null, NOPT);
227 result = stms.getResult();
230 IntArray ia = result;
231 result = new IntArray();
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]);
237 IntArray ia = stms.getResult();
238 if(ia.data != null) {
239 for(int i = 0;i < ia.sizeOrData ; i+=3) addStatement(ia.data[i],ia.data[i+1],ia.data[i+2]);
245 public void finished(ReadGraphImpl graph) {
249 public void exception(ReadGraphImpl graph, Throwable throwable) {
254 AssertionMapProc amp = new AssertionMapProc();
256 // This dependency could be cut
257 PrincipalTypes.queryEach(graph, r1, graph.processor, entry, null, amp);
263 final static private void forSingleAssertion(ReadGraphImpl graph, final int r1, final int r2, final Objects entry, final IntProcedure procedure) {
265 IntArray map = getAssertionMap(graph, r1, r2, entry);
267 if(entry != null) entry.finish(graph, procedure);
268 else procedure.finished(graph);
272 int size = map.size();
275 int value = map.data[2];
278 entry.addOrSetFunctional(value);
279 entry.finish(graph, procedure);
281 procedure.execute(graph, value);
282 procedure.finished(graph);
285 } else if(size == 0) {
287 if(entry != null) entry.finish(graph, procedure);
288 else procedure.finished(graph);
292 int candidateS = map.data[0];
293 int candidateO = map.data[2];
295 SuperTypes candidate = SuperTypes.queryEach(graph, candidateS, graph.processor, entry, null, NOP);
296 if(candidate.isExcepted()) {
297 if(entry != null) entry.except((Throwable)candidate.getResult());
298 procedure.exception(graph, (Throwable)candidate.getResult());
301 IntSet candidateIs = candidate.getResult();
303 for(int i=3;i<map.size();i+=3) {
305 int nextS = map.data[i];
306 int nextO = map.data[i+2];
308 if(nextS != candidateS) {
310 if(candidateIs.contains(nextS)) {
312 // Next is a super type of candidate => ignore next
316 SuperTypes next = SuperTypes.queryEach(graph, nextS, graph.processor, entry, null, NOP);
317 if(next.isExcepted()) {
318 if(entry != null) entry.except((Throwable)next.getResult());
319 procedure.exception(graph, (Throwable)next.getResult());
322 IntSet nextIs = next.getResult();
324 if(nextIs.contains(candidateS)) {
326 // Candidate is a super type of next => next is the new candidate
330 candidateIs = nextIs;
334 // candidate and next are unrelated => error
335 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has conflicting assertions " + r1 + ", " + r2 + " " + map , r1);
337 if(entry != null) entry.except(exception);
338 procedure.exception(graph, exception);
350 entry.addOrSetFunctional(candidateO);
351 entry.finish(graph, procedure);
353 procedure.execute(graph, candidateO);
354 procedure.finished(graph);
361 final static InternalProcedure<IntSet> NOP = new InternalProcedure<IntSet>() {
364 public void execute(ReadGraphImpl graph, IntSet result) {
368 public void exception(ReadGraphImpl graph, Throwable throwable) {
373 final static TripleIntProcedure NOPT = new TripleIntProcedure() {
377 public void exception(ReadGraphImpl graph, Throwable throwable) {
381 public void execute(ReadGraphImpl graph, int s, int p, int o) {
385 public void finished(ReadGraphImpl graph) {
390 // Search for one statement
391 final public void computeFunctionalIndex(ReadGraphImpl graph, final QueryProcessor provider, final RelationInfo ri, final IntProcedure procedure) {
392 computeFunctionalIndex(graph, r1(), r2(), this, ri, procedure);
395 // Search for one statement
396 final static public void computeFunctionalIndex(ReadGraphImpl graph, final int r1, final int r2, final Objects entry, final RelationInfo ri, final IntProcedure procedure) {
400 int result = graph.processor.querySupport.getFunctionalObject(r1, r2);
404 // Check for assertions
405 forSingleAssertion(graph, r1, r2, entry, procedure);
407 } else if (result == -1) {
409 graph.processor.querySupport.getObjects(graph, r1, r2, new IntProcedure() {
412 public void execute(ReadGraphImpl graph, int i) {
413 if(entry != null) entry.addOrSetFunctional(i);
414 else procedure.execute(graph, i);
418 public void exception(ReadGraphImpl graph, Throwable t) {
419 if(DebugException.DEBUG) new DebugException(t).printStackTrace();
423 public void finished(ReadGraphImpl graph) {
428 // Check for assertions
429 forSingleAssertion(graph, r1, r2, entry, procedure);
433 // If functional relation was found there is no need to check assertions
435 entry.addOrSetFunctional(result);
436 entry.finish(graph, procedure);
438 procedure.execute(graph, result);
439 procedure.finished(graph);
447 // Note! The dependency is intentionally cut!
448 DirectPredicates.queryEach(graph, r1, graph.processor, null, null, new SyncIntProcedure() {
450 boolean found = false;
453 public void run(ReadGraphImpl graph) {
456 if(entry != null) entry.finish(graph, procedure);
457 else procedure.finished(graph);
460 // Check for assertions
461 forSingleAssertion(graph, r1, r2, entry, procedure);
468 public void execute(ReadGraphImpl graph, final int pred) {
474 // Note! The dependency is intentionally cut!
475 DirectObjects.queryEach(graph, r1, pred, graph.processor, null, null, new IntProcedure() {
478 public void execute(ReadGraphImpl graph, int i) {
482 if(entry != null) entry.addOrSetFunctional(i);
483 else procedure.execute(graph, i);
489 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has more than one statement (r1=" + r1 + ", r2=" + r2 + ").", r1);
490 if(entry != null) entry.except(exception);
491 procedure.exception(graph, exception);
498 public void finished(ReadGraphImpl graph) {
502 public void exception(ReadGraphImpl graph, Throwable t) {
503 procedure.exception(graph, t);
510 SuperRelations.queryEach(graph, pred, graph.processor, entry, null, new InternalProcedure<IntSet>() {
513 public void execute(ReadGraphImpl graph, IntSet result) {
517 if(result.contains(r2)) {
519 // Note! The dependency is intentionally cut!
520 DirectObjects.queryEach(graph, r1, pred, graph.processor, null, null, new IntProcedure() {
523 public void execute(ReadGraphImpl graph, int i) {
527 if(entry != null) entry.addOrSetFunctional(i);
528 else procedure.execute(graph, i);
534 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has more than one statement (r1=" + r1 + ", r2=" + r2 + ").", r1);
535 if(entry != null) entry.except(exception);
536 procedure.exception(graph, exception);
543 public void finished(ReadGraphImpl graph) {
547 public void exception(ReadGraphImpl graph, Throwable t) {
548 procedure.exception(graph, t);
558 public void exception(ReadGraphImpl graph, Throwable t) {
559 procedure.exception(graph, t);
569 public void finished(ReadGraphImpl graph) {
582 final static private void forAssertions(ReadGraphImpl graph, final int r1, final int r2, final Objects entry, final IntProcedure procedure) {
584 // Note! The dependency is intentionally cut!
585 PrincipalTypes.queryEach(graph, r1, graph.processor, null, null, new SyncIntProcedure() {
588 public void run(ReadGraphImpl graph) {
590 if(entry != null) entry.finish(graph, procedure);
591 else procedure.finished(graph);
595 TripleIntProcedure proc = new TripleIntProcedure() {
598 public void execute(ReadGraphImpl graph, int s, int p, int o) {
599 if(entry != null) entry.addOrSet(o);
600 else procedure.execute(graph, o);
604 public void finished(ReadGraphImpl graph) {
609 public void exception(ReadGraphImpl graph, Throwable t) {
610 if(DebugException.DEBUG) new DebugException(t).printStackTrace();
611 procedure.exception(graph, t);
618 public void execute(ReadGraphImpl graph, int type) {
622 AssertedStatements.queryEach(graph, type, r2, graph.processor, entry, null, proc);
627 public void finished(ReadGraphImpl graph) {
636 final public static void computeNotFunctionalFinalIndex(ReadGraphImpl graph, final int r1, final int r2, final QueryProcessor provider, RelationInfo ri, AsyncMultiProcedure<Resource> procedure) {
642 final public void computeNotFunctionalIndex(ReadGraphImpl graph, RelationInfo ri, final IntProcedure procedure) {
643 computeNotFunctionalIndex(graph, r1(), r2(), this, ri, procedure);
646 final static public void computeNotFunctionalIndex(ReadGraphImpl graph, final int r1, final int r2, final Objects entry, RelationInfo ri, final IntProcedure procedure) {
650 graph.processor.querySupport.getObjects(graph, r1, r2, new IntProcedure() {
653 public void execute(ReadGraphImpl graph, int i) {
654 if(entry != null) entry.addOrSet(i);
655 else procedure.execute(graph, i);
659 public void exception(ReadGraphImpl graph, Throwable t) {
660 if(DebugException.DEBUG) new DebugException(t).printStackTrace();
661 procedure.exception(graph, t);
665 public void finished(ReadGraphImpl graph) {
671 forAssertions(graph, r1, r2, entry, procedure);
673 if(entry != null) entry.finish(graph, procedure);
674 else procedure.finished(graph);
679 // Note! The dependency is intentionally cut!
680 DirectPredicates.queryEach(graph, r1, graph.processor, null, null, new SyncIntProcedure() {
683 public void run(ReadGraphImpl graph) {
685 forAssertions(graph, r1, r2, entry, procedure);
690 public void execute(ReadGraphImpl graph, final int pred) {
696 // Note! The dependency is intentionally cut!
697 DirectObjects.queryEach(graph, r1, pred, graph.processor, null, null, new IntProcedure() {
700 public void execute(ReadGraphImpl graph, int i) {
701 if(entry != null) entry.addOrSet(i);
702 else procedure.execute(graph, i);
706 public void finished(ReadGraphImpl graph) {
711 public void exception(ReadGraphImpl graph, Throwable t) {
712 procedure.exception(graph, t);
722 SuperRelations.queryEach(graph, pred, graph.processor, entry, null, new InternalProcedure<IntSet>() {
725 public void execute(ReadGraphImpl graph, IntSet result) {
727 if(result.contains(r2)) {
731 // Note! The dependency is intentionally cut!
732 DirectObjects.queryEach(graph, r1, pred, graph.processor, null, null, new IntProcedure() {
735 public void execute(ReadGraphImpl graph, int i) {
736 if(entry != null) entry.addOrSet(i);
737 else procedure.execute(graph, i);
741 public void finished(ReadGraphImpl graph) {
746 public void exception(ReadGraphImpl graph, Throwable t) {
747 if(DebugException.DEBUG) new DebugException(t).printStackTrace();
748 procedure.exception(graph, t);
761 public void exception(ReadGraphImpl graph, Throwable t) {
762 procedure.exception(graph, t);
773 public void finished(ReadGraphImpl graph) {
784 public void computeForEach(ReadGraphImpl graph, final QueryProcessor provider, final IntProcedure procedure, final boolean store) {
785 computeForEach(graph, r1(), r2(), this, procedure);
788 public static void computeForEach(ReadGraphImpl graph, final int r1, final int r2, final Objects entry, final IntProcedure procedure) {
790 RelationInfo ri = RelationInfoQuery.queryEach(graph, r2, graph.processor, entry, null, ip);
791 graph.ensureLoaded(r1, r2);
792 if(ri.isFunctional) {
793 computeFunctionalIndex(graph, r1, r2, entry, ri, procedure);
795 computeNotFunctionalIndex(graph, r1, r2, entry, ri, procedure);
800 final static InternalProcedure<RelationInfo> ip = new InternalProcedure<RelationInfo>() {
803 public void execute(ReadGraphImpl graph, RelationInfo result) {
807 public void exception(ReadGraphImpl graph, Throwable throwable) {
813 public String toString() {
814 return "Objects[" + r1() + " - " + r2() + "]";
817 final private void finish(ReadGraphImpl graph, IntProcedure procedure) {
819 assert(assertPending());
825 IntArray v = (IntArray)getResult();
828 if(v.sizeOrData != IntArray.NO_DATA) {
829 procedure.execute(graph, v.sizeOrData);
832 for(int i = 0;i < v.sizeOrData ; i++) {
833 procedure.execute(graph, v.data[i]);
837 procedure.finished(graph);
841 final public void addOrSet(int add) {
843 assert(assertPending());
845 IntArray value = (IntArray)getResult();
846 synchronized(value) {
852 final public void addOrSetFunctional(int add) {
856 IntArray value = (IntArray)getResult();
862 public void performFromCache(ReadGraphImpl graph, QueryProcessor provider, final IntProcedure procedure) {
866 if(handleException(graph, procedure)) return;
868 final IntArray value = (IntArray)getResult();
869 if(value.data == null) {
870 if(value.sizeOrData != IntArray.NO_DATA) procedure.execute(graph, value.sizeOrData);
872 for(int i = 0;i < value.sizeOrData ; i++) procedure.execute(graph, value.data[i]);
875 procedure.finished(graph);
880 public void recompute(ReadGraphImpl graph, QueryProcessor provider) {
882 final Semaphore s = new Semaphore(0);
884 computeForEach(graph, provider, new IntProcedureAdapter() {
887 public void finished(ReadGraphImpl graph) {
892 public void exception(ReadGraphImpl graph, Throwable t) {
894 new Error("Error in recompute.", t).printStackTrace();
899 while(!s.tryAcquire()) {
900 provider.resume(graph);
907 return RequestFlags.IMMEDIATE_UPDATE;
911 boolean isImmutable(ReadGraphImpl graph) {
912 return graph.processor.isImmutable(r1());