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;
28 final public class Statements extends CollectionBinaryQuery<TripleIntProcedure> {
30 public Statements(final int r1, final int r2) {
34 final static Statements entry(final QueryProcessor processor, final int r1, final int r2) {
36 return (Statements)processor.cache.statementsMap.get(id(r1,r2));
40 final static Collection<Statements> entries(final QueryProcessor processor, final int r1) {
41 return processor.cache.statementsMap.values(r1);
44 final static void runner(ReadGraphImpl graph, final int r1, final int r2, CacheEntry parent, final ListenerBase listener, final TripleIntProcedure procedure) {
46 QueryProcessor processor = graph.processor;
48 Statements entry = (Statements)processor.cache.statementsMap.get(id(r1,r2));
51 entry = new Statements(r1, r2);
53 entry.clearResult(processor.querySupport);
54 entry.putEntry(processor);
56 processor.performForEach(graph, entry, parent, listener, procedure);
60 if(entry.isPending()) {
62 if(entry.isPending()) {
63 throw new IllegalStateException();
64 // if(entry.procs == null) entry.procs = new ArrayList<TripleIntProcedure>();
65 // entry.procs.add(procedure);
66 // processor.registerDependencies(graph, entry, parent, listener, procedure, false);
72 processor.performForEach(graph, entry, parent, listener, procedure);
78 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) {
83 if(parent == null && listener == null) {
84 Statements.computeForEach(graph, r1, r2, null, procedure);
88 runner(graph, r1, r2, parent, listener, procedure);
93 public BinaryQuery<TripleIntProcedure> getEntry(QueryProcessor provider) {
94 return provider.cache.statementsMap.get(id);
98 public void putEntry(QueryProcessor provider) {
99 provider.cache.statementsMap.put(id, this);
103 final public void removeEntry(QueryProcessor provider) {
104 provider.cache.statementsMap.remove(id);
107 final static TripleIntProcedure NOPT = new TripleIntProcedure() {
111 public void exception(ReadGraphImpl graph, Throwable throwable) {
115 public void execute(ReadGraphImpl graph, int s, int p, int o) {
119 public void finished(ReadGraphImpl graph) {
124 final static private IntArray getAssertionMap(ReadGraphImpl graph, final int r1, final int r2, final Statements entry) {
126 class AssertionMapProc implements IntProcedure {
128 boolean first = true;
130 private IntArray result;
132 public void addStatement(int s, int p, int o) {
134 if(result.size() == 0) {
139 for(int i = 0;i < result.sizeOrData ; i+=3) {
140 int existingP = result.data[i+1];
142 int existingO = result.data[i+2];
143 if(existingO == o) return;
154 public void execute(ReadGraphImpl graph, int type) {
155 AssertedStatements stms = AssertedStatements.queryEach(graph, type, r2, graph.processor, entry, null, NOPT);
157 result = stms.getResult();
160 IntArray ia = result;
161 result = new IntArray();
162 if(ia.data != null) {
163 for(int i = 0;i < ia.sizeOrData ; i+=3) addStatement(ia.data[i],ia.data[i+1],ia.data[i+2]);
167 IntArray ia = stms.getResult();
168 if(ia.data != null) {
169 for(int i = 0;i < ia.sizeOrData ; i+=3) addStatement(ia.data[i],ia.data[i+1],ia.data[i+2]);
175 public void finished(ReadGraphImpl graph) {
179 public void exception(ReadGraphImpl graph, Throwable throwable) {
184 AssertionMapProc amp = new AssertionMapProc();
186 // This dependency could be cut
187 PrincipalTypes.queryEach(graph, r1, graph.processor, entry, null, amp);
193 final static private void forSingleAssertion(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final TripleIntProcedure procedure) {
195 IntArray map = getAssertionMap(graph, r1, r2, entry);
197 if(entry != null) entry.finish(graph, procedure);
198 else procedure.finished(graph);
202 int size = map.size();
210 entry.addOrSetFunctional(s,p,o);
211 entry.finish(graph, procedure);
213 procedure.execute(graph, s,p,o);
214 procedure.finished(graph);
217 } else if(size == 0) {
219 if(entry != null) entry.finish(graph, procedure);
220 else procedure.finished(graph);
224 int candidateS = map.data[0];
225 int candidateP = map.data[1];
226 int candidateO = map.data[2];
228 SuperTypes candidate = SuperTypes.queryEach(graph, candidateS, graph.processor, entry, null, NOP);
229 if(candidate.isExcepted()) {
230 if(entry != null) entry.except((Throwable)candidate.getResult());
231 procedure.exception(graph, (Throwable)candidate.getResult());
234 IntSet candidateIs = candidate.getResult();
236 for(int i=3;i<map.size();i+=3) {
238 int nextS = map.data[i];
239 int nextP = map.data[i+1];
240 int nextO = map.data[i+2];
242 if(nextS != candidateS) {
244 if(candidateIs.contains(nextS)) {
246 // Next is a super type of candidate => ignore next
250 SuperTypes next = SuperTypes.queryEach(graph, nextS, graph.processor, entry, null, NOP);
251 if(next.isExcepted()) {
252 if(entry != null) entry.except((Throwable)next.getResult());
253 procedure.exception(graph, (Throwable)next.getResult());
256 IntSet nextIs = next.getResult();
258 if(nextIs.contains(candidateS)) {
260 // Candidate is a super type of next => next is the new candidate
265 candidateIs = nextIs;
269 // candidate and next are unrelated => error
270 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has conflicting assertions.", r1);
272 if(entry != null) entry.except(exception);
273 procedure.exception(graph, exception);
285 entry.addOrSetFunctional(candidateS, candidateP, candidateO);
286 entry.finish(graph, procedure);
288 procedure.execute(graph, candidateS, candidateP, candidateO);
289 procedure.finished(graph);
296 final static InternalProcedure<IntSet> NOP = new InternalProcedure<IntSet>() {
299 public void execute(ReadGraphImpl graph, IntSet result) {
303 public void exception(ReadGraphImpl graph, Throwable throwable) {
308 // Search for one statement
309 final static public void computeFunctionalIndex(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final RelationInfo ri, final TripleIntProcedure procedure) {
313 int result = graph.processor.querySupport.getFunctionalObject(r1, r2);
317 // Check for assertions
318 forSingleAssertion(graph, r1, r2, entry, procedure);
320 } else if(result == -1) {
322 graph.processor.querySupport.getObjects(graph, r1, r2, new IntProcedure() {
325 public void execute(ReadGraphImpl graph, int i) {
326 if(entry != null) entry.addOrSetFunctional(r1, r2, i);
327 else procedure.execute(graph, r1, r2, i);
331 public void exception(ReadGraphImpl graph, Throwable t) {
332 if(DebugException.DEBUG) new DebugException(t).printStackTrace();
336 public void finished(ReadGraphImpl graph) {
341 // Check for assertions
342 forSingleAssertion(graph, r1, r2, entry, procedure);
346 // If functional relation was found there is no need to check assertions
348 entry.addOrSetFunctional(r1, r2, result);
349 entry.finish(graph, procedure);
351 procedure.execute(graph, r1, r2, result);
352 procedure.finished(graph);
360 final AtomicBoolean found = new AtomicBoolean(false);
362 // Note! The dependency is intentionally cut!
363 DirectPredicates.queryEach(graph, r1, graph.processor, null, null, new SyncIntProcedure() {
366 public void run(ReadGraphImpl graph) {
369 if(entry != null) entry.finish(graph, procedure);
370 else procedure.finished(graph);
373 // Check for assertions
374 forSingleAssertion(graph, r1, r2, entry, procedure);
381 public void execute(ReadGraphImpl graph, final int pred) {
383 if(found.get()) return;
389 // Note! The dependency is intentionally cut!
390 DirectObjects.queryEach(graph, r1, pred, graph.processor, null, null, new IntProcedure() {
393 public void execute(ReadGraphImpl graph, int i) {
395 if(found.compareAndSet(false, true)) {
397 if(entry != null) entry.addOrSetFunctional(r1, pred, i);
398 else procedure.execute(graph, r1, pred, i);
402 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has more than one statement.", r1);
403 if(entry != null) entry.except(exception);
404 procedure.exception(graph, exception);
411 public void finished(ReadGraphImpl graph) {
416 public void exception(ReadGraphImpl graph, Throwable t) {
417 procedure.exception(graph, t);
427 SuperRelations.queryEach(graph, pred, graph.processor, entry, null, new InternalProcedure<IntSet>() {
430 public void execute(ReadGraphImpl graph, IntSet result) {
437 if(result.contains(r2)) {
441 // Note! The dependency is intentionally cut!
442 DirectObjects.queryEach(graph, r1, pred, graph.processor, null, null, new IntProcedure() {
445 public void execute(ReadGraphImpl graph, int i) {
447 if(found.compareAndSet(false, true)) {
449 if(entry != null) entry.addOrSetFunctional(r1, pred, i);
450 else procedure.execute(graph, r1, pred, i);
454 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has more than one statement.", r1);
455 if(entry != null) entry.except(exception);
456 procedure.exception(graph, exception);
463 public void finished(ReadGraphImpl graph) {
468 public void exception(ReadGraphImpl graph, Throwable t) {
469 procedure.exception(graph, t);
482 public void exception(ReadGraphImpl graph, Throwable t) {
483 procedure.exception(graph, t);
494 public void finished(ReadGraphImpl graph) {
506 final static private void forAssertions(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final TripleIntProcedure procedure) {
508 PrincipalTypes.queryEach(graph, r1, graph.processor, entry, null, new SyncIntProcedure() {
511 public void run(ReadGraphImpl graph) {
513 if(entry != null) entry.finish(graph, procedure);
514 else procedure.finished(graph);
518 TripleIntProcedure proc = new TripleIntProcedureAdapter() {
521 public void execute(ReadGraphImpl graph, int s, int p, int o) {
522 if(entry != null) entry.addOrSet(s, p, o);
523 else procedure.execute(graph, s, p, o);
527 public void finished(ReadGraphImpl graph) {
532 public void exception(ReadGraphImpl graph, Throwable t) {
534 procedure.exception(graph, t);
540 public void execute(ReadGraphImpl graph, int type) {
544 AssertedStatements.queryEach(graph, type, r2, graph.processor, entry, null, proc);
549 public void finished(ReadGraphImpl graph) {
554 public void exception(ReadGraphImpl graph, Throwable t) {
563 final static public void computeNotFunctionalIndex(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final RelationInfo ri, final TripleIntProcedure procedure) {
567 graph.processor.querySupport.getObjects(graph, r1, r2, new IntProcedure() {
570 public void execute(ReadGraphImpl graph, int i) {
571 if(entry != null) entry.addOrSet(r1, r2, i);
572 else procedure.execute(graph, r1, r2, i);
576 public void exception(ReadGraphImpl graph, Throwable t) {
577 if(DebugException.DEBUG) new DebugException(t).printStackTrace();
578 procedure.exception(graph, t);
582 public void finished(ReadGraphImpl graph) {
588 forAssertions(graph, r1, r2, entry, procedure);
590 if(entry != null) entry.finish(graph, procedure);
591 else procedure.finished(graph);
596 // Note! The dependency is intentionally cut!
597 DirectPredicates.queryEach(graph, r1, graph.processor, null, null, new SyncIntProcedure() {
600 public void run(ReadGraphImpl graph) {
602 forAssertions(graph, r1, r2, entry, procedure);
607 public void execute(ReadGraphImpl graph, final int pred2) {
613 // Note! The dependency is intentionally cut!
614 DirectObjects.queryEach(graph, r1, pred2, graph.processor, null, null, new IntProcedure() {
617 public void execute(ReadGraphImpl graph, int i) {
618 if(entry != null) entry.addOrSet(r1, pred2, i);
619 else procedure.execute(graph, r1, pred2, i);
623 public void finished(ReadGraphImpl graph) {
628 public void exception(ReadGraphImpl graph, Throwable t) {
629 procedure.exception(graph, t);
641 IntSet result = SuperRelations.queryEach2(graph, pred2, graph.processor, entry, null, null);
642 if(result.contains(r2)) {
646 // Note! The dependency is intentionally cut!
647 DirectObjects.queryEach(graph, r1, pred2, graph.processor, null, null, new IntProcedure() {
650 public void execute(ReadGraphImpl graph, int i) {
651 if(entry != null) entry.addOrSet(r1, pred2, i);
652 else procedure.execute(graph, r1, pred2, i);
657 public void finished(ReadGraphImpl graph) {
662 public void exception(ReadGraphImpl graph, Throwable t) {
663 procedure.exception(graph, t);
671 } catch (Throwable e) {
672 procedure.exception(graph, e);
680 public void finished(ReadGraphImpl graph) {
691 public void computeForEach(ReadGraphImpl graph, final QueryProcessor provider, final TripleIntProcedure procedure, final boolean store) {
692 computeForEach(graph, r1(), r2(), this, procedure);
695 public static void computeForEach(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final TripleIntProcedure procedure) {
697 RelationInfoQuery riEntry = RelationInfoQuery.probe(graph, r2);
698 if(riEntry != null) {
699 RelationInfo ri = riEntry.getResult();
700 graph.ensureLoaded(r1, r2);
701 if(ri.isFunctional) {
702 computeFunctionalIndex(graph, r1, r2, entry, ri, procedure);
704 computeNotFunctionalIndex(graph, r1, r2, entry, ri, procedure);
709 RelationInfoQuery.queryEach(graph, r2, graph.processor, entry, null, new InternalProcedure<RelationInfo>() {
712 public void execute(ReadGraphImpl graph, final RelationInfo ri) {
714 graph.ensureLoaded(r1, r2);
715 if(ri.isFunctional) {
716 computeFunctionalIndex(graph, r1, r2, entry, ri, procedure);
718 computeNotFunctionalIndex(graph, r1, r2, entry, ri, procedure);
724 public void exception(ReadGraphImpl graph, Throwable t) {
725 procedure.exception(graph, t);
733 public String toString() {
734 return "Statements[" + r1() + " - " + r2() + "]";
737 final private void finish(ReadGraphImpl graph, TripleIntProcedure procedure) {
739 assert(assertPending());
741 // ArrayList<TripleIntProcedure> p = null;
751 IntArray v = (IntArray)getResult();
752 final IntArray value = (IntArray)getResult();
756 // for(TripleIntProcedure proc : p) {
757 // for(int i=0;i<value.size();i+=3) {
758 // proc.execute(graph, value.data[i], value.data[i+1], value.data[i+2]);
761 // for(int i=0;i<value.size();i+=3) {
762 // procedure.execute(graph, value.data[i], value.data[i+1], value.data[i+2]);
765 // for(TripleIntProcedure proc : p) proc.finished(graph);
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 procedure.finished(graph);
777 // final private void finish(ReadGraphImpl graph, QueryProcessor provider) {
779 // assert(isPending());
781 // ArrayList<TripleIntProcedure> p = null;
783 // synchronized(this) {
793 // final IntArray value = (IntArray)getResult();
794 // for(TripleIntProcedure proc : p) {
795 // for(int i=0;i<value.size();i+=3) {
796 // proc.execute(graph, value.data[i], value.data[i+1], value.data[i+2]);
800 // for(TripleIntProcedure proc : p) proc.finished(graph);
806 synchronized public void addOrSet(int s, int p, int o) {
808 assert(assertPending());
810 IntArray value = (IntArray)getResult();
817 final static public int r1(long id) {
818 return (int)(id>>>32);
821 final static public int r2(long id) {
825 final public void addOrSetFunctional(int s, long po) {
827 addOrSetFunctional(s, r1(po), r2(po));
831 final public void addOrSetFunctional(int s, int p, int o) {
833 assert(assertPending());
835 IntArray value = (IntArray)getResult();
843 public Object performFromCache(ReadGraphImpl graph, QueryProcessor provider, final TripleIntProcedure procedure) {
847 final IntArray value = (IntArray)getResult();
849 if(handleException(graph, procedure)) return value;
851 for(int i=0;i<value.size();i+=3) {
852 procedure.execute(graph, value.data[i], value.data[i+1], value.data[i+2]);
855 procedure.finished(graph);
862 public void recompute(ReadGraphImpl graph, QueryProcessor provider) {
864 final Semaphore s = new Semaphore(0);
866 computeForEach(graph, provider, new TripleIntProcedureAdapter() {
869 public void finished(ReadGraphImpl graph) {
874 public void exception(ReadGraphImpl graph, Throwable t) {
875 new Error("Error in recompute.", t).printStackTrace();
881 while(!s.tryAcquire()) {
882 provider.resume(graph);
887 // } catch (InterruptedException e) {
888 // throw new Error(e);
895 return RequestFlags.IMMEDIATE_UPDATE;
900 boolean isImmutable(ReadGraphImpl graph) {
901 return graph.processor.isImmutable(r1());