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.ArrayList;
15 import java.util.Collection;
16 import java.util.concurrent.Semaphore;
17 import java.util.concurrent.atomic.AtomicBoolean;
19 import org.simantics.db.RelationInfo;
20 import org.simantics.db.common.exception.DebugException;
21 import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
22 import org.simantics.db.impl.graph.ReadGraphImpl;
23 import org.simantics.db.impl.procedure.InternalProcedure;
24 import org.simantics.db.impl.procedure.TripleIntProcedureAdapter;
25 import org.simantics.db.procedure.ListenerBase;
26 import org.simantics.db.request.RequestFlags;
27 import org.simantics.utils.Development;
29 final public class Statements extends CollectionBinaryQuery<TripleIntProcedure> {
31 // public ArrayList<TripleIntProcedure> procs = null;
33 public Statements(final int r1, final int r2) {
37 final static Statements entry(final QueryProcessor processor, final int r1, final int r2) {
39 return (Statements)processor.statementsMap.get(id(r1,r2));
43 final static Collection<Statements> entries(final QueryProcessor processor, final int r1) {
44 return processor.statementsMap.values(r1);
47 final static void runner(ReadGraphImpl graph, final int r1, final int r2, CacheEntry parent, final ListenerBase listener, final TripleIntProcedure procedure) {
49 QueryProcessor processor = graph.processor;
51 Statements entry = (Statements)processor.statementsMap.get(id(r1,r2));
54 entry = new Statements(r1, r2);
56 entry.clearResult(processor.querySupport);
57 entry.putEntry(processor);
59 if(Development.DEVELOPMENT)
60 Development.recordHistogram(entry.toString());
62 processor.performForEach(graph, entry, parent, listener, procedure);
66 if(entry.isPending()) {
68 if(entry.isPending()) {
69 throw new IllegalStateException();
70 // if(entry.procs == null) entry.procs = new ArrayList<TripleIntProcedure>();
71 // entry.procs.add(procedure);
72 // processor.registerDependencies(graph, entry, parent, listener, procedure, false);
78 processor.performForEach(graph, entry, parent, listener, procedure);
84 final public static void queryEach(ReadGraphImpl graph, final int r1, final int r2, final QueryProcessor provider, final CacheEntry parent, final ListenerBase listener, final TripleIntProcedure procedure) {
89 if(parent == null && listener == null) {
90 if(Development.DEVELOPMENT)
91 Development.recordHistogram(new Statements(r1, r2).toString());
92 Statements.computeForEach(graph, r1, r2, null, procedure);
96 runner(graph, r1, r2, parent, listener, procedure);
101 public BinaryQuery<TripleIntProcedure> getEntry(QueryProcessor provider) {
102 return provider.statementsMap.get(id);
106 public void putEntry(QueryProcessor provider) {
107 provider.statementsMap.put(id, this);
111 final public void removeEntry(QueryProcessor provider) {
112 provider.statementsMap.remove(id);
115 final static TripleIntProcedure NOPT = new TripleIntProcedure() {
119 public void exception(ReadGraphImpl graph, Throwable throwable) {
123 public void execute(ReadGraphImpl graph, int s, int p, int o) {
127 public void finished(ReadGraphImpl graph) {
132 final static private IntArray getAssertionMap(ReadGraphImpl graph, final int r1, final int r2, final Statements entry) {
134 class AssertionMapProc implements IntProcedure {
136 boolean first = true;
138 private IntArray result;
140 public void addStatement(int s, int p, int o) {
142 if(result.size() == 0) {
147 for(int i = 0;i < result.sizeOrData ; i+=3) {
148 int existingP = result.data[i+1];
150 int existingO = result.data[i+2];
151 if(existingO == o) return;
162 public void execute(ReadGraphImpl graph, int type) {
163 AssertedStatements stms = AssertedStatements.queryEach(graph, type, r2, graph.processor, entry, null, NOPT);
165 result = stms.getResult();
168 IntArray ia = result;
169 result = new IntArray();
170 if(ia.data != null) {
171 for(int i = 0;i < ia.sizeOrData ; i+=3) addStatement(ia.data[i],ia.data[i+1],ia.data[i+2]);
175 IntArray ia = stms.getResult();
176 if(ia.data != null) {
177 for(int i = 0;i < ia.sizeOrData ; i+=3) addStatement(ia.data[i],ia.data[i+1],ia.data[i+2]);
183 public void finished(ReadGraphImpl graph) {
187 public void exception(ReadGraphImpl graph, Throwable throwable) {
192 AssertionMapProc amp = new AssertionMapProc();
194 // This dependency could be cut
195 PrincipalTypes.queryEach(graph, r1, graph.processor, entry, null, amp);
201 final static private void forSingleAssertion(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final TripleIntProcedure procedure) {
203 IntArray map = getAssertionMap(graph, r1, r2, entry);
205 if(entry != null) entry.finish(graph, procedure);
206 else procedure.finished(graph);
210 int size = map.size();
218 entry.addOrSetFunctional(s,p,o);
219 entry.finish(graph, procedure);
221 procedure.execute(graph, s,p,o);
222 procedure.finished(graph);
225 } else if(size == 0) {
227 if(entry != null) entry.finish(graph, procedure);
228 else procedure.finished(graph);
232 int candidateS = map.data[0];
233 int candidateP = map.data[1];
234 int candidateO = map.data[2];
236 SuperTypes candidate = SuperTypes.queryEach(graph, candidateS, graph.processor, entry, null, NOP);
237 if(candidate.isExcepted()) {
238 if(entry != null) entry.except((Throwable)candidate.getResult());
239 procedure.exception(graph, (Throwable)candidate.getResult());
242 IntSet candidateIs = candidate.getResult();
244 for(int i=3;i<map.size();i+=3) {
246 int nextS = map.data[i];
247 int nextP = map.data[i+1];
248 int nextO = map.data[i+2];
250 if(nextS != candidateS) {
252 if(candidateIs.contains(nextS)) {
254 // Next is a super type of candidate => ignore next
258 SuperTypes next = SuperTypes.queryEach(graph, nextS, graph.processor, entry, null, NOP);
259 if(next.isExcepted()) {
260 if(entry != null) entry.except((Throwable)next.getResult());
261 procedure.exception(graph, (Throwable)next.getResult());
264 IntSet nextIs = next.getResult();
266 if(nextIs.contains(candidateS)) {
268 // Candidate is a super type of next => next is the new candidate
273 candidateIs = nextIs;
277 // candidate and next are unrelated => error
278 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has conflicting assertions.", r1);
280 if(entry != null) entry.except(exception);
281 procedure.exception(graph, exception);
293 entry.addOrSetFunctional(candidateS, candidateP, candidateO);
294 entry.finish(graph, procedure);
296 procedure.execute(graph, candidateS, candidateP, candidateO);
297 procedure.finished(graph);
304 final static InternalProcedure<IntSet> NOP = new InternalProcedure<IntSet>() {
307 public void execute(ReadGraphImpl graph, IntSet result) {
311 public void exception(ReadGraphImpl graph, Throwable throwable) {
316 // Search for one statement
317 final static public void computeFunctionalIndex(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final RelationInfo ri, final TripleIntProcedure procedure) {
321 int result = graph.processor.querySupport.getFunctionalObject(r1, r2);
325 // Check for assertions
326 forSingleAssertion(graph, r1, r2, entry, procedure);
328 } else if(result == -1) {
330 graph.processor.querySupport.getObjects(graph, r1, r2, new IntProcedure() {
333 public void execute(ReadGraphImpl graph, int i) {
334 if(entry != null) entry.addOrSetFunctional(r1, r2, i);
335 else procedure.execute(graph, r1, r2, i);
339 public void exception(ReadGraphImpl graph, Throwable t) {
340 if(DebugException.DEBUG) new DebugException(t).printStackTrace();
344 public void finished(ReadGraphImpl graph) {
349 // Check for assertions
350 forSingleAssertion(graph, r1, r2, entry, procedure);
354 // If functional relation was found there is no need to check assertions
356 entry.addOrSetFunctional(r1, r2, result);
357 entry.finish(graph, procedure);
359 procedure.execute(graph, r1, r2, result);
360 procedure.finished(graph);
368 final AtomicBoolean found = new AtomicBoolean(false);
370 // Note! The dependency is intentionally cut!
371 DirectPredicates.queryEach(graph, r1, graph.processor, null, null, new SyncIntProcedure() {
374 public void run(ReadGraphImpl graph) {
377 if(entry != null) entry.finish(graph, procedure);
378 else procedure.finished(graph);
381 // Check for assertions
382 forSingleAssertion(graph, r1, r2, entry, procedure);
389 public void execute(ReadGraphImpl graph, final int pred) {
391 if(found.get()) return;
397 // Note! The dependency is intentionally cut!
398 DirectObjects.queryEach(graph, r1, pred, graph.processor, null, null, new IntProcedure() {
401 public void execute(ReadGraphImpl graph, int i) {
403 if(found.compareAndSet(false, true)) {
405 if(entry != null) entry.addOrSetFunctional(r1, pred, i);
406 else procedure.execute(graph, r1, pred, i);
410 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has more than one statement.", r1);
411 if(entry != null) entry.except(exception);
412 procedure.exception(graph, exception);
419 public void finished(ReadGraphImpl graph) {
424 public void exception(ReadGraphImpl graph, Throwable t) {
425 procedure.exception(graph, t);
435 SuperRelations.queryEach(graph, pred, graph.processor, entry, null, new InternalProcedure<IntSet>() {
438 public void execute(ReadGraphImpl graph, IntSet result) {
445 if(result.contains(r2)) {
449 // Note! The dependency is intentionally cut!
450 DirectObjects.queryEach(graph, r1, pred, graph.processor, null, null, new IntProcedure() {
453 public void execute(ReadGraphImpl graph, int i) {
455 if(found.compareAndSet(false, true)) {
457 if(entry != null) entry.addOrSetFunctional(r1, pred, i);
458 else procedure.execute(graph, r1, pred, i);
462 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has more than one statement.", r1);
463 if(entry != null) entry.except(exception);
464 procedure.exception(graph, exception);
471 public void finished(ReadGraphImpl graph) {
476 public void exception(ReadGraphImpl graph, Throwable t) {
477 procedure.exception(graph, t);
490 public void exception(ReadGraphImpl graph, Throwable t) {
491 procedure.exception(graph, t);
502 public void finished(ReadGraphImpl graph) {
514 final static private void forAssertions(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final TripleIntProcedure procedure) {
516 PrincipalTypes.queryEach(graph, r1, graph.processor, entry, null, new SyncIntProcedure() {
519 public void run(ReadGraphImpl graph) {
521 if(entry != null) entry.finish(graph, procedure);
522 else procedure.finished(graph);
526 TripleIntProcedure proc = new TripleIntProcedureAdapter() {
529 public void execute(ReadGraphImpl graph, int s, int p, int o) {
530 if(entry != null) entry.addOrSet(s, p, o);
531 else procedure.execute(graph, s, p, o);
535 public void finished(ReadGraphImpl graph) {
540 public void exception(ReadGraphImpl graph, Throwable t) {
542 procedure.exception(graph, t);
548 public void execute(ReadGraphImpl graph, int type) {
552 AssertedStatements.queryEach(graph, type, r2, graph.processor, entry, null, proc);
557 public void finished(ReadGraphImpl graph) {
562 public void exception(ReadGraphImpl graph, Throwable t) {
571 final static public void computeNotFunctionalIndex(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final RelationInfo ri, final TripleIntProcedure procedure) {
575 graph.processor.querySupport.getObjects(graph, r1, r2, new IntProcedure() {
578 public void execute(ReadGraphImpl graph, int i) {
579 if(entry != null) entry.addOrSet(r1, r2, i);
580 else procedure.execute(graph, r1, r2, i);
584 public void exception(ReadGraphImpl graph, Throwable t) {
585 if(DebugException.DEBUG) new DebugException(t).printStackTrace();
586 procedure.exception(graph, t);
590 public void finished(ReadGraphImpl graph) {
596 forAssertions(graph, r1, r2, entry, procedure);
598 if(entry != null) entry.finish(graph, procedure);
599 else procedure.finished(graph);
604 // Note! The dependency is intentionally cut!
605 DirectPredicates.queryEach(graph, r1, graph.processor, null, null, new SyncIntProcedure() {
608 public void run(ReadGraphImpl graph) {
610 forAssertions(graph, r1, r2, entry, procedure);
615 public void execute(ReadGraphImpl graph, final int pred2) {
621 // Note! The dependency is intentionally cut!
622 DirectObjects.queryEach(graph, r1, pred2, graph.processor, null, null, new IntProcedure() {
625 public void execute(ReadGraphImpl graph, int i) {
626 if(entry != null) entry.addOrSet(r1, pred2, i);
627 else procedure.execute(graph, r1, pred2, i);
631 public void finished(ReadGraphImpl graph) {
636 public void exception(ReadGraphImpl graph, Throwable t) {
637 procedure.exception(graph, t);
649 IntSet result = SuperRelations.queryEach2(graph, pred2, graph.processor, entry, null, null);
650 if(result.contains(r2)) {
654 // Note! The dependency is intentionally cut!
655 DirectObjects.queryEach(graph, r1, pred2, graph.processor, null, null, new IntProcedure() {
658 public void execute(ReadGraphImpl graph, int i) {
659 if(entry != null) entry.addOrSet(r1, pred2, i);
660 else procedure.execute(graph, r1, pred2, i);
665 public void finished(ReadGraphImpl graph) {
670 public void exception(ReadGraphImpl graph, Throwable t) {
671 procedure.exception(graph, t);
679 } catch (Throwable e) {
680 procedure.exception(graph, e);
688 public void finished(ReadGraphImpl graph) {
699 public void computeForEach(ReadGraphImpl graph, final QueryProcessor provider, final TripleIntProcedure procedure, final boolean store) {
700 computeForEach(graph, r1(), r2(), this, procedure);
703 public static void computeForEach(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final TripleIntProcedure procedure) {
705 RelationInfoQuery riEntry = RelationInfoQuery.probe(graph, r2);
706 if(riEntry != null) {
707 RelationInfo ri = riEntry.getResult();
708 graph.ensureLoaded(r1, r2);
709 if(ri.isFunctional) {
710 computeFunctionalIndex(graph, r1, r2, entry, ri, procedure);
712 computeNotFunctionalIndex(graph, r1, r2, entry, ri, procedure);
717 RelationInfoQuery.queryEach(graph, r2, graph.processor, entry, null, new InternalProcedure<RelationInfo>() {
720 public void execute(ReadGraphImpl graph, final RelationInfo ri) {
722 graph.ensureLoaded(r1, r2);
723 if(ri.isFunctional) {
724 computeFunctionalIndex(graph, r1, r2, entry, ri, procedure);
726 computeNotFunctionalIndex(graph, r1, r2, entry, ri, procedure);
732 public void exception(ReadGraphImpl graph, Throwable t) {
733 procedure.exception(graph, t);
741 public String toString() {
742 return "Statements[" + r1() + " - " + r2() + "]";
745 final private void finish(ReadGraphImpl graph, TripleIntProcedure procedure) {
747 assert(assertPending());
749 // ArrayList<TripleIntProcedure> p = null;
759 IntArray v = (IntArray)getResult();
760 final IntArray value = (IntArray)getResult();
764 // for(TripleIntProcedure proc : p) {
765 // for(int i=0;i<value.size();i+=3) {
766 // proc.execute(graph, value.data[i], value.data[i+1], value.data[i+2]);
769 // for(int i=0;i<value.size();i+=3) {
770 // procedure.execute(graph, value.data[i], value.data[i+1], value.data[i+2]);
773 // for(TripleIntProcedure proc : p) proc.finished(graph);
777 for(int i=0;i<value.size();i+=3) {
778 procedure.execute(graph, value.data[i], value.data[i+1], value.data[i+2]);
781 procedure.finished(graph);
785 // final private void finish(ReadGraphImpl graph, QueryProcessor provider) {
787 // assert(isPending());
789 // ArrayList<TripleIntProcedure> p = null;
791 // synchronized(this) {
801 // final IntArray value = (IntArray)getResult();
802 // for(TripleIntProcedure proc : p) {
803 // for(int i=0;i<value.size();i+=3) {
804 // proc.execute(graph, value.data[i], value.data[i+1], value.data[i+2]);
808 // for(TripleIntProcedure proc : p) proc.finished(graph);
814 synchronized public void addOrSet(int s, int p, int o) {
816 assert(assertPending());
818 IntArray value = (IntArray)getResult();
825 final static public int r1(long id) {
826 return (int)(id>>>32);
829 final static public int r2(long id) {
833 final public void addOrSetFunctional(int s, long po) {
835 addOrSetFunctional(s, r1(po), r2(po));
839 final public void addOrSetFunctional(int s, int p, int o) {
841 assert(assertPending());
843 IntArray value = (IntArray)getResult();
851 public void performFromCache(ReadGraphImpl graph, QueryProcessor provider, final TripleIntProcedure procedure) {
855 if(handleException(graph, procedure)) return;
857 final IntArray value = (IntArray)getResult();
858 for(int i=0;i<value.size();i+=3) {
859 procedure.execute(graph, value.data[i], value.data[i+1], value.data[i+2]);
862 procedure.finished(graph);
867 public void recompute(ReadGraphImpl graph, QueryProcessor provider) {
869 final Semaphore s = new Semaphore(0);
871 computeForEach(graph, provider, new TripleIntProcedureAdapter() {
874 public void finished(ReadGraphImpl graph) {
879 public void exception(ReadGraphImpl graph, Throwable t) {
880 new Error("Error in recompute.", t).printStackTrace();
886 while(!s.tryAcquire()) {
887 provider.resume(graph);
892 // } catch (InterruptedException e) {
893 // throw new Error(e);
900 return RequestFlags.IMMEDIATE_UPDATE;
905 boolean isImmutable(ReadGraphImpl graph) {
906 return graph.processor.isImmutable(r1());