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 ArrayList<TripleIntProcedure> procs = null;
32 public Statements(final int r1, final int r2) {
36 final static Statements entry(final QueryProcessor processor, final int r1, final int r2) {
38 return (Statements)processor.statementsMap.get(id(r1,r2));
42 final static Collection<Statements> entries(final QueryProcessor processor, final int r1) {
43 return processor.statementsMap.values(r1);
46 final static void runner(ReadGraphImpl graph, final int r1, final int r2, CacheEntry parent, final ListenerBase listener, final TripleIntProcedure procedure) {
48 QueryProcessor processor = graph.processor;
50 Statements entry = (Statements)processor.statementsMap.get(id(r1,r2));
53 entry = new Statements(r1, r2);
55 entry.clearResult(processor.querySupport);
56 entry.putEntry(processor);
58 processor.performForEach(graph, entry, parent, listener, procedure);
62 if(entry.isPending()) {
64 if(entry.isPending()) {
65 throw new IllegalStateException();
66 // if(entry.procs == null) entry.procs = new ArrayList<TripleIntProcedure>();
67 // entry.procs.add(procedure);
68 // processor.registerDependencies(graph, entry, parent, listener, procedure, false);
74 processor.performForEach(graph, entry, parent, listener, procedure);
80 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) {
85 if(parent == null && listener == null) {
86 Statements.computeForEach(graph, r1, r2, null, procedure);
90 runner(graph, r1, r2, parent, listener, procedure);
95 public BinaryQuery<TripleIntProcedure> getEntry(QueryProcessor provider) {
96 return provider.statementsMap.get(id);
100 public void putEntry(QueryProcessor provider) {
101 provider.statementsMap.put(id, this);
105 final public void removeEntry(QueryProcessor provider) {
106 provider.statementsMap.remove(id);
109 final static TripleIntProcedure NOPT = new TripleIntProcedure() {
113 public void exception(ReadGraphImpl graph, Throwable throwable) {
117 public void execute(ReadGraphImpl graph, int s, int p, int o) {
121 public void finished(ReadGraphImpl graph) {
126 final static private IntArray getAssertionMap(ReadGraphImpl graph, final int r1, final int r2, final Statements entry) {
128 class AssertionMapProc implements IntProcedure {
130 boolean first = true;
132 private IntArray result;
134 public void addStatement(int s, int p, int o) {
136 if(result.size() == 0) {
141 for(int i = 0;i < result.sizeOrData ; i+=3) {
142 int existingP = result.data[i+1];
144 int existingO = result.data[i+2];
145 if(existingO == o) return;
156 public void execute(ReadGraphImpl graph, int type) {
157 AssertedStatements stms = AssertedStatements.queryEach(graph, type, r2, graph.processor, entry, null, NOPT);
159 result = stms.getResult();
162 IntArray ia = result;
163 result = new IntArray();
164 if(ia.data != null) {
165 for(int i = 0;i < ia.sizeOrData ; i+=3) addStatement(ia.data[i],ia.data[i+1],ia.data[i+2]);
169 IntArray ia = stms.getResult();
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]);
177 public void finished(ReadGraphImpl graph) {
181 public void exception(ReadGraphImpl graph, Throwable throwable) {
186 AssertionMapProc amp = new AssertionMapProc();
188 // This dependency could be cut
189 PrincipalTypes.queryEach(graph, r1, graph.processor, entry, null, amp);
195 final static private void forSingleAssertion(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final TripleIntProcedure procedure) {
197 IntArray map = getAssertionMap(graph, r1, r2, entry);
199 if(entry != null) entry.finish(graph, procedure);
200 else procedure.finished(graph);
204 int size = map.size();
212 entry.addOrSetFunctional(s,p,o);
213 entry.finish(graph, procedure);
215 procedure.execute(graph, s,p,o);
216 procedure.finished(graph);
219 } else if(size == 0) {
221 if(entry != null) entry.finish(graph, procedure);
222 else procedure.finished(graph);
226 int candidateS = map.data[0];
227 int candidateP = map.data[1];
228 int candidateO = map.data[2];
230 SuperTypes candidate = SuperTypes.queryEach(graph, candidateS, graph.processor, entry, null, NOP);
231 if(candidate.isExcepted()) {
232 if(entry != null) entry.except((Throwable)candidate.getResult());
233 procedure.exception(graph, (Throwable)candidate.getResult());
236 IntSet candidateIs = candidate.getResult();
238 for(int i=3;i<map.size();i+=3) {
240 int nextS = map.data[i];
241 int nextP = map.data[i+1];
242 int nextO = map.data[i+2];
244 if(nextS != candidateS) {
246 if(candidateIs.contains(nextS)) {
248 // Next is a super type of candidate => ignore next
252 SuperTypes next = SuperTypes.queryEach(graph, nextS, graph.processor, entry, null, NOP);
253 if(next.isExcepted()) {
254 if(entry != null) entry.except((Throwable)next.getResult());
255 procedure.exception(graph, (Throwable)next.getResult());
258 IntSet nextIs = next.getResult();
260 if(nextIs.contains(candidateS)) {
262 // Candidate is a super type of next => next is the new candidate
267 candidateIs = nextIs;
271 // candidate and next are unrelated => error
272 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has conflicting assertions.", r1);
274 if(entry != null) entry.except(exception);
275 procedure.exception(graph, exception);
287 entry.addOrSetFunctional(candidateS, candidateP, candidateO);
288 entry.finish(graph, procedure);
290 procedure.execute(graph, candidateS, candidateP, candidateO);
291 procedure.finished(graph);
298 final static InternalProcedure<IntSet> NOP = new InternalProcedure<IntSet>() {
301 public void execute(ReadGraphImpl graph, IntSet result) {
305 public void exception(ReadGraphImpl graph, Throwable throwable) {
310 // Search for one statement
311 final static public void computeFunctionalIndex(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final RelationInfo ri, final TripleIntProcedure procedure) {
315 int result = graph.processor.querySupport.getFunctionalObject(r1, r2);
319 // Check for assertions
320 forSingleAssertion(graph, r1, r2, entry, procedure);
322 } else if(result == -1) {
324 graph.processor.querySupport.getObjects(graph, r1, r2, new IntProcedure() {
327 public void execute(ReadGraphImpl graph, int i) {
328 if(entry != null) entry.addOrSetFunctional(r1, r2, i);
329 else procedure.execute(graph, r1, r2, i);
333 public void exception(ReadGraphImpl graph, Throwable t) {
334 if(DebugException.DEBUG) new DebugException(t).printStackTrace();
338 public void finished(ReadGraphImpl graph) {
343 // Check for assertions
344 forSingleAssertion(graph, r1, r2, entry, procedure);
348 // If functional relation was found there is no need to check assertions
350 entry.addOrSetFunctional(r1, r2, result);
351 entry.finish(graph, procedure);
353 procedure.execute(graph, r1, r2, result);
354 procedure.finished(graph);
362 final AtomicBoolean found = new AtomicBoolean(false);
364 // Note! The dependency is intentionally cut!
365 DirectPredicates.queryEach(graph, r1, graph.processor, null, null, new SyncIntProcedure() {
368 public void run(ReadGraphImpl graph) {
371 if(entry != null) entry.finish(graph, procedure);
372 else procedure.finished(graph);
375 // Check for assertions
376 forSingleAssertion(graph, r1, r2, entry, procedure);
383 public void execute(ReadGraphImpl graph, final int pred) {
385 if(found.get()) return;
391 // Note! The dependency is intentionally cut!
392 DirectObjects.queryEach(graph, r1, pred, graph.processor, null, null, new IntProcedure() {
395 public void execute(ReadGraphImpl graph, int i) {
397 if(found.compareAndSet(false, true)) {
399 if(entry != null) entry.addOrSetFunctional(r1, pred, i);
400 else procedure.execute(graph, r1, pred, i);
404 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has more than one statement.", r1);
405 if(entry != null) entry.except(exception);
406 procedure.exception(graph, exception);
413 public void finished(ReadGraphImpl graph) {
418 public void exception(ReadGraphImpl graph, Throwable t) {
419 procedure.exception(graph, t);
429 SuperRelations.queryEach(graph, pred, graph.processor, entry, null, new InternalProcedure<IntSet>() {
432 public void execute(ReadGraphImpl graph, IntSet result) {
439 if(result.contains(r2)) {
443 // Note! The dependency is intentionally cut!
444 DirectObjects.queryEach(graph, r1, pred, graph.processor, null, null, new IntProcedure() {
447 public void execute(ReadGraphImpl graph, int i) {
449 if(found.compareAndSet(false, true)) {
451 if(entry != null) entry.addOrSetFunctional(r1, pred, i);
452 else procedure.execute(graph, r1, pred, i);
456 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has more than one statement.", r1);
457 if(entry != null) entry.except(exception);
458 procedure.exception(graph, exception);
465 public void finished(ReadGraphImpl graph) {
470 public void exception(ReadGraphImpl graph, Throwable t) {
471 procedure.exception(graph, t);
484 public void exception(ReadGraphImpl graph, Throwable t) {
485 procedure.exception(graph, t);
496 public void finished(ReadGraphImpl graph) {
508 final static private void forAssertions(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final TripleIntProcedure procedure) {
510 PrincipalTypes.queryEach(graph, r1, graph.processor, entry, null, new SyncIntProcedure() {
513 public void run(ReadGraphImpl graph) {
515 if(entry != null) entry.finish(graph, procedure);
516 else procedure.finished(graph);
520 TripleIntProcedure proc = new TripleIntProcedureAdapter() {
523 public void execute(ReadGraphImpl graph, int s, int p, int o) {
524 if(entry != null) entry.addOrSet(s, p, o);
525 else procedure.execute(graph, s, p, o);
529 public void finished(ReadGraphImpl graph) {
534 public void exception(ReadGraphImpl graph, Throwable t) {
536 procedure.exception(graph, t);
542 public void execute(ReadGraphImpl graph, int type) {
546 AssertedStatements.queryEach(graph, type, r2, graph.processor, entry, null, proc);
551 public void finished(ReadGraphImpl graph) {
556 public void exception(ReadGraphImpl graph, Throwable t) {
565 final static public void computeNotFunctionalIndex(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final RelationInfo ri, final TripleIntProcedure procedure) {
569 graph.processor.querySupport.getObjects(graph, r1, r2, new IntProcedure() {
572 public void execute(ReadGraphImpl graph, int i) {
573 if(entry != null) entry.addOrSet(r1, r2, i);
574 else procedure.execute(graph, r1, r2, i);
578 public void exception(ReadGraphImpl graph, Throwable t) {
579 if(DebugException.DEBUG) new DebugException(t).printStackTrace();
580 procedure.exception(graph, t);
584 public void finished(ReadGraphImpl graph) {
590 forAssertions(graph, r1, r2, entry, procedure);
592 if(entry != null) entry.finish(graph, procedure);
593 else procedure.finished(graph);
598 // Note! The dependency is intentionally cut!
599 DirectPredicates.queryEach(graph, r1, graph.processor, null, null, new SyncIntProcedure() {
602 public void run(ReadGraphImpl graph) {
604 forAssertions(graph, r1, r2, entry, procedure);
609 public void execute(ReadGraphImpl graph, final int pred2) {
615 // Note! The dependency is intentionally cut!
616 DirectObjects.queryEach(graph, r1, pred2, graph.processor, null, null, new IntProcedure() {
619 public void execute(ReadGraphImpl graph, int i) {
620 if(entry != null) entry.addOrSet(r1, pred2, i);
621 else procedure.execute(graph, r1, pred2, i);
625 public void finished(ReadGraphImpl graph) {
630 public void exception(ReadGraphImpl graph, Throwable t) {
631 procedure.exception(graph, t);
643 IntSet result = SuperRelations.queryEach2(graph, pred2, graph.processor, entry, null, null);
644 if(result.contains(r2)) {
648 // Note! The dependency is intentionally cut!
649 DirectObjects.queryEach(graph, r1, pred2, graph.processor, null, null, new IntProcedure() {
652 public void execute(ReadGraphImpl graph, int i) {
653 if(entry != null) entry.addOrSet(r1, pred2, i);
654 else procedure.execute(graph, r1, pred2, i);
659 public void finished(ReadGraphImpl graph) {
664 public void exception(ReadGraphImpl graph, Throwable t) {
665 procedure.exception(graph, t);
673 } catch (Throwable e) {
674 procedure.exception(graph, e);
682 public void finished(ReadGraphImpl graph) {
693 public void computeForEach(ReadGraphImpl graph, final QueryProcessor provider, final TripleIntProcedure procedure, final boolean store) {
694 computeForEach(graph, r1(), r2(), this, procedure);
697 public static void computeForEach(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final TripleIntProcedure procedure) {
699 RelationInfoQuery riEntry = RelationInfoQuery.probe(graph, r2);
700 if(riEntry != null) {
701 RelationInfo ri = riEntry.getResult();
702 graph.ensureLoaded(r1, r2);
703 if(ri.isFunctional) {
704 computeFunctionalIndex(graph, r1, r2, entry, ri, procedure);
706 computeNotFunctionalIndex(graph, r1, r2, entry, ri, procedure);
711 RelationInfoQuery.queryEach(graph, r2, graph.processor, entry, null, new InternalProcedure<RelationInfo>() {
714 public void execute(ReadGraphImpl graph, final RelationInfo ri) {
716 graph.ensureLoaded(r1, r2);
717 if(ri.isFunctional) {
718 computeFunctionalIndex(graph, r1, r2, entry, ri, procedure);
720 computeNotFunctionalIndex(graph, r1, r2, entry, ri, procedure);
726 public void exception(ReadGraphImpl graph, Throwable t) {
727 procedure.exception(graph, t);
735 public String toString() {
736 return "Statements[" + r1() + " - " + r2() + "]";
739 final private void finish(ReadGraphImpl graph, TripleIntProcedure procedure) {
741 assert(assertPending());
743 // ArrayList<TripleIntProcedure> p = null;
753 IntArray v = (IntArray)getResult();
754 final IntArray value = (IntArray)getResult();
758 // for(TripleIntProcedure proc : p) {
759 // for(int i=0;i<value.size();i+=3) {
760 // proc.execute(graph, value.data[i], value.data[i+1], value.data[i+2]);
763 // for(int i=0;i<value.size();i+=3) {
764 // procedure.execute(graph, value.data[i], value.data[i+1], value.data[i+2]);
767 // for(TripleIntProcedure proc : p) proc.finished(graph);
771 for(int i=0;i<value.size();i+=3) {
772 procedure.execute(graph, value.data[i], value.data[i+1], value.data[i+2]);
775 procedure.finished(graph);
779 // final private void finish(ReadGraphImpl graph, QueryProcessor provider) {
781 // assert(isPending());
783 // ArrayList<TripleIntProcedure> p = null;
785 // synchronized(this) {
795 // final IntArray value = (IntArray)getResult();
796 // for(TripleIntProcedure proc : p) {
797 // for(int i=0;i<value.size();i+=3) {
798 // proc.execute(graph, value.data[i], value.data[i+1], value.data[i+2]);
802 // for(TripleIntProcedure proc : p) proc.finished(graph);
808 synchronized public void addOrSet(int s, int p, int o) {
810 assert(assertPending());
812 IntArray value = (IntArray)getResult();
819 final static public int r1(long id) {
820 return (int)(id>>>32);
823 final static public int r2(long id) {
827 final public void addOrSetFunctional(int s, long po) {
829 addOrSetFunctional(s, r1(po), r2(po));
833 final public void addOrSetFunctional(int s, int p, int o) {
835 assert(assertPending());
837 IntArray value = (IntArray)getResult();
845 public void performFromCache(ReadGraphImpl graph, QueryProcessor provider, final TripleIntProcedure procedure) {
849 if(handleException(graph, procedure)) return;
851 final IntArray value = (IntArray)getResult();
852 for(int i=0;i<value.size();i+=3) {
853 procedure.execute(graph, value.data[i], value.data[i+1], value.data[i+2]);
856 procedure.finished(graph);
861 public void recompute(ReadGraphImpl graph, QueryProcessor provider) {
863 final Semaphore s = new Semaphore(0);
865 computeForEach(graph, provider, new TripleIntProcedureAdapter() {
868 public void finished(ReadGraphImpl graph) {
873 public void exception(ReadGraphImpl graph, Throwable t) {
874 new Error("Error in recompute.", t).printStackTrace();
880 while(!s.tryAcquire()) {
881 provider.resume(graph);
886 // } catch (InterruptedException e) {
887 // throw new Error(e);
894 return RequestFlags.IMMEDIATE_UPDATE;
899 boolean isImmutable(ReadGraphImpl graph) {
900 return graph.processor.isImmutable(r1());