]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/Statements.java
Still working for multiple readers
[simantics/platform.git] / bundles / org.simantics.db.impl / src / org / simantics / db / impl / query / Statements.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
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
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.db.impl.query;
13
14 import java.util.concurrent.atomic.AtomicBoolean;
15
16 import org.simantics.db.RelationInfo;
17 import org.simantics.db.common.exception.DebugException;
18 import org.simantics.db.exception.DatabaseException;
19 import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
20 import org.simantics.db.impl.graph.ReadGraphImpl;
21 import org.simantics.db.impl.procedure.InternalProcedure;
22 import org.simantics.db.impl.procedure.TripleIntProcedureAdapter;
23 import org.simantics.db.procedure.ListenerBase;
24 import org.simantics.db.request.RequestFlags;
25
26 final public class Statements extends CollectionBinaryQuery<TripleIntProcedure> {
27         
28     public Statements(final int r1, final int r2) {
29         super(r1, r2);
30     }
31     
32     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) throws DatabaseException {
33         
34         assert(r1 != 0);
35         assert(r2 != 0);
36         
37         if(parent == null && listener == null) {
38                 Statements.computeForEach(graph, r1, r2, null, procedure);
39                 return;
40         }
41         
42         QueryCache.runnerStatements(graph, r1, r2, parent, listener, procedure);
43          
44     }
45
46         @Override
47         final public void removeEntry(QueryProcessor provider) {
48         provider.cache.remove(this);
49         }
50         
51     final static TripleIntProcedure NOPT = new TripleIntProcedure() {
52
53
54                 @Override
55                 public void exception(ReadGraphImpl graph, Throwable throwable) {
56                 }
57
58                 @Override
59                 public void execute(ReadGraphImpl graph, int s, int p, int o) {
60                 }
61
62                 @Override
63                 public void finished(ReadGraphImpl graph) {
64                 }
65         
66     };
67         
68     final static private IntArray getAssertionMap(ReadGraphImpl graph, final int r1, final int r2, final Statements entry) throws DatabaseException {
69         
70         class AssertionMapProc implements IntProcedure {
71                 
72                 boolean first = true;
73
74                 private IntArray result;
75
76                 public void addStatement(int s, int p, int o) {
77                         
78                         if(result.size() == 0) {
79                                 result.add(s);
80                                 result.add(p);
81                                 result.add(o);
82                         } else {
83                                 for(int i = 0;i < result.sizeOrData ; i+=3) {
84                                         int existingP = result.data[i+1];
85                                         if(p == existingP) {
86                                                 int existingO = result.data[i+2];
87                                                 if(existingO == o) return;
88                                         }
89                                 }
90                                 result.add(s);
91                                 result.add(p);
92                                 result.add(o);
93                         }
94                         
95                 }
96                 
97             @Override
98             public void execute(ReadGraphImpl graph, int type) throws DatabaseException {
99                 if(result == null) {
100                         result = QueryCache.resultAssertedStatements(graph, type, r2, entry, null);
101                 } else {
102                         if (first) {
103                                 IntArray ia = result;
104                                 result = new IntArray();
105                                 if(ia.data != null) {
106                                         for(int i = 0;i < ia.sizeOrData ; i+=3) addStatement(ia.data[i],ia.data[i+1],ia.data[i+2]);
107                                 }
108                                 first = false;
109                         }
110                         IntArray ia = QueryCache.resultAssertedStatements(graph, type, r2, entry, null);
111                         if(ia.data != null) {
112                                 for(int i = 0;i < ia.sizeOrData ; i+=3) addStatement(ia.data[i],ia.data[i+1],ia.data[i+2]);
113                         }
114                 }
115             }
116
117             @Override
118             public void finished(ReadGraphImpl graph) {
119             }
120
121                 @Override
122                 public void exception(ReadGraphImpl graph, Throwable throwable) {
123                 }
124
125         }
126         
127         AssertionMapProc amp = new AssertionMapProc();
128
129         // This dependency could be cut
130         QueryCache.runnerPrincipalTypes(graph, r1, entry, null, amp);
131         
132         return amp.result;
133         
134     }
135         
136     final static private void forSingleAssertion(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final TripleIntProcedure procedure) throws DatabaseException {
137         
138         if(entry != null) {
139                 assert(entry.isPending());
140         }
141         
142         IntArray map = getAssertionMap(graph, r1, r2, entry);
143         if(map == null) {
144             if(entry != null) entry.finish(graph, procedure);
145                 else procedure.finished(graph);
146             return;
147         }
148         
149         int size = map.size();
150         if(size == 3) {
151
152                 int s = map.data[0];
153                 int p = map.data[1];
154                 int o = map.data[2];
155                 
156             if(entry != null) {
157                 entry.addOrSetFunctional(s,p,o);
158                 entry.finish(graph, procedure);
159             } else {
160                         procedure.execute(graph, s,p,o);
161                         procedure.finished(graph);
162                 }
163
164         } else if(size == 0) {
165
166             if(entry != null) entry.finish(graph, procedure);
167                 else procedure.finished(graph);
168                 
169         } else {
170
171                 int candidateS = map.data[0];
172                 int candidateP = map.data[1];
173                 int candidateO = map.data[2];
174                 
175                         IntSet candidateIs = null;
176                         try {
177                                 candidateIs = QueryCache.resultSuperTypes(graph, candidateS, entry, null);
178                         } catch (DatabaseException e) {
179                                 if(entry != null) entry.except(e);
180                                 procedure.exception(graph, e);
181                                 return;
182                         }
183
184
185 //                      SuperTypes candidate = SuperTypes.queryEach(graph, candidateS, graph.processor, entry, null, NOP);
186 //                      if(candidate.isExcepted()) {
187 //                              if(entry != null) entry.except((Throwable)candidate.getResult());
188 //                              procedure.exception(graph, (Throwable)candidate.getResult());
189 //                              return;
190 //                      }
191 //                      IntSet candidateIs = candidate.getResult();
192                 
193                         for(int i=3;i<map.size();i+=3) {
194
195                                 int nextS = map.data[i];
196                                 int nextP = map.data[i+1];
197                                 int nextO = map.data[i+2];
198                         
199                                 if(nextS != candidateS) {
200
201                                 if(candidateIs.contains(nextS)) {
202                                         
203                                         // Next is a super type of candidate => ignore next
204                                         
205                                 } else {
206                                 
207                                         IntSet nextIs = null;
208                                         try {
209                                                 nextIs = QueryCache.resultSuperTypes(graph, nextS, entry, null);
210                                         } catch (DatabaseException e) {
211                                                 if(entry != null) entry.except(e);
212                                                 procedure.exception(graph, e);
213                                                 return;
214                                         }
215                                         
216 //                                      SuperTypes next = SuperTypes.queryEach(graph, nextS, graph.processor, entry, null, NOP);
217 //                                      if(next.isExcepted()) {
218 //                                              if(entry != null) entry.except((Throwable)next.getResult());
219 //                                              procedure.exception(graph, (Throwable)next.getResult());
220 //                                              return;
221 //                                      }
222 //                                      IntSet nextIs = next.getResult();
223                                         
224                                         if(nextIs.contains(candidateS)) {
225
226                                                 // Candidate is a super type of next => next is the new candidate
227                                                 
228                                                 candidateS = nextS;
229                                                 candidateP = nextP;
230                                                 candidateO = nextO;
231                                                 candidateIs = nextIs;
232                                                 
233                                         } else {
234
235                                                 // candidate and next are unrelated => error
236                                                 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has conflicting assertions.", r1);
237                                                 
238                                                 if(entry != null) entry.except(exception);
239                                                 procedure.exception(graph, exception);
240                                                 return;                                         
241                                                 
242                                         }
243                                 
244                                 }
245                                 
246                         }
247                         
248                 }
249                 
250                 if(entry != null) {
251                 entry.addOrSetFunctional(candidateS, candidateP, candidateO);
252                 entry.finish(graph, procedure);
253             } else {
254                         procedure.execute(graph, candidateS, candidateP, candidateO);
255                         procedure.finished(graph);
256                 }
257                 
258         }
259         
260     }
261     
262     final static InternalProcedure<IntSet> NOP = new InternalProcedure<IntSet>() {
263
264                 @Override
265                 public void execute(ReadGraphImpl graph, IntSet result) {
266                 }
267
268                 @Override
269                 public void exception(ReadGraphImpl graph, Throwable throwable) {
270                 }
271         
272     };
273         
274         // Search for one statement
275         final static public void computeFunctionalIndex(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final RelationInfo ri, final TripleIntProcedure procedure) throws DatabaseException {
276         
277         if(ri.isFinal) {
278             
279                 int result = graph.processor.querySupport.getFunctionalObject(r1, r2);
280
281                 if(result == 0) {
282
283                 // Check for assertions
284                 forSingleAssertion(graph, r1, r2, entry, procedure);
285
286                 } else if(result == -1) {
287
288                 graph.processor.querySupport.getObjects(graph, r1, r2, new IntProcedure() {
289
290                         @Override
291                         public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
292                                 if(entry != null) entry.addOrSetFunctional(r1, r2, i);
293                                 else procedure.execute(graph, r1, r2, i);
294                         }
295
296                         @Override
297                         public void exception(ReadGraphImpl graph, Throwable t) {
298                                 if(DebugException.DEBUG) new DebugException(t).printStackTrace();
299                         }
300
301                         @Override
302                         public void finished(ReadGraphImpl graph) {
303                         }
304
305                 });
306
307                 // Check for assertions
308                 forSingleAssertion(graph, r1, r2, entry, procedure);
309                         
310                 } else {
311
312                 // If functional relation was found there is no need to check assertions
313                         if(entry != null) {
314                                 entry.addOrSetFunctional(r1, r2, result);
315                                 entry.finish(graph, procedure);
316                         } else {
317                                 procedure.execute(graph, r1, r2, result);
318                                 procedure.finished(graph);
319                         }
320                         
321                 }
322
323             
324         } else {
325             
326             final AtomicBoolean found = new AtomicBoolean(false);
327             
328             // Note! The dependency is intentionally cut!
329             IntSet direct = QueryCache.resultDirectPredicates(graph, r1, null, null);
330             direct.forEach(graph, new SyncIntProcedure() {
331                 
332                 @Override
333                 public void run(ReadGraphImpl graph) throws DatabaseException {
334                     
335                     if(found.get()) {
336                         if(entry != null) entry.finish(graph, procedure);
337                         else procedure.finished(graph);
338                     } else {
339                     
340                             // Check for assertions
341                         forSingleAssertion(graph, r1, r2, entry, procedure);
342                             
343                     }
344                     
345                 }
346
347                 @Override
348                 public void execute(ReadGraphImpl graph, final int pred) throws DatabaseException {
349                     
350                     if(found.get()) return;
351
352                     if(pred == r2) {
353                         
354                         inc();
355                         
356                         // Note! The dependency is intentionally cut!
357                         QueryCache.runnerDirectObjects(graph, r1, pred, null, null, new IntProcedure() {
358
359                             @Override
360                             public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
361                                 
362                                 if(found.compareAndSet(false, true)) {
363                                     
364                                     if(entry != null) entry.addOrSetFunctional(r1, pred, i);
365                                     else procedure.execute(graph, r1, pred, i);
366                                         
367                                 } else {
368
369                                         ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has more than one statement.", r1);
370                                         if(entry != null) entry.except(exception);
371                                         procedure.exception(graph, exception);
372                                         
373                                 }
374
375                             }
376
377                             @Override
378                             public void finished(ReadGraphImpl graph) throws DatabaseException {
379                                 dec(graph);
380                             }
381                                                 
382                                                 @Override
383                                                 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
384                                                         procedure.exception(graph, t);
385                                 dec(graph);
386                                     }
387
388                         });
389
390                     } else {
391                         
392                         inc();
393                     
394                         QueryCache.runnerSuperRelations(graph, pred, entry, null, new InternalProcedure<IntSet>() {
395     
396                             @Override
397                             public void execute(ReadGraphImpl graph, IntSet result) throws DatabaseException {
398                                 
399                                 if(found.get()) {
400                                     dec(graph);
401                                     return;
402                                 }
403
404                                 if(result.contains(r2)) {
405                                     
406                                     inc();
407                                     
408                                     // Note! The dependency is intentionally cut!
409                                     QueryCache.runnerDirectObjects(graph, r1, pred, null, null, new IntProcedure() {
410     
411                                         @Override
412                                         public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
413                                             
414                                                 if(found.compareAndSet(false, true)) {
415                                                 
416                                                 if(entry != null) entry.addOrSetFunctional(r1, pred, i);
417                                                 else procedure.execute(graph, r1, pred, i);
418                                                         
419                                                 } else {
420
421                                                 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has more than one statement.", r1);
422                                                 if(entry != null) entry.except(exception);
423                                                 procedure.exception(graph, exception);
424                                                         
425                                                 }
426                                             
427                                         }
428     
429                                         @Override
430                                         public void finished(ReadGraphImpl graph) throws DatabaseException {
431                                             dec(graph);
432                                         }
433                                                         
434                                                         @Override
435                                                         public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
436                                                                 procedure.exception(graph, t);
437                                             dec(graph);
438                                             }
439
440                                     });
441     
442                                 }
443                                 
444                                 dec(graph);
445                                 
446                             }
447                                                 
448                                                 @Override
449                                                 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
450                                                         procedure.exception(graph, t);
451                                 dec(graph);
452                                     }
453
454                         });
455                         
456                     }
457                     
458                 }
459
460                 @Override
461                 public void finished(ReadGraphImpl graph) throws DatabaseException {
462                     dec(graph);
463                 }
464                 
465             });
466             
467         }
468
469         }
470     
471     final static private void forAssertions(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final TripleIntProcedure procedure) throws DatabaseException {
472
473         QueryCache.runnerPrincipalTypes(graph, r1, entry, null, new SyncIntProcedure() {
474             
475             @Override
476             public void run(ReadGraphImpl graph) throws DatabaseException {
477                 
478                 if(entry != null) entry.finish(graph, procedure);
479                 else procedure.finished(graph);
480                 
481             }
482             
483             TripleIntProcedure proc = new TripleIntProcedureAdapter() {
484
485                 @Override
486                 public void execute(ReadGraphImpl graph, int s, int p, int o) throws DatabaseException {
487                         if(entry != null) entry.addOrSet(s, p, o);
488                         else procedure.execute(graph, s, p, o);
489                 }
490
491                 @Override
492                 public void finished(ReadGraphImpl graph) throws DatabaseException {
493                     dec(graph);
494                 }
495                                 
496                                 @Override
497                                 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
498                     dec(graph);
499                                         procedure.exception(graph, t);
500                     }
501
502             }; 
503
504             @Override
505             public void execute(ReadGraphImpl graph, int type) throws DatabaseException {
506
507                 inc();
508                 QueryCache.runnerAssertedStatements(graph, type, r2, entry, null, proc);
509                 
510             }
511             
512             @Override
513             public void finished(ReadGraphImpl graph) throws DatabaseException {
514                 dec(graph);       
515             }
516             
517             @Override
518             public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
519                 dec(graph);
520             }
521             
522         });
523         
524
525     }
526
527         final static public void computeNotFunctionalIndex(ReadGraphImpl graph, final int r1, final int r2, final Statements entry,  final RelationInfo ri, final TripleIntProcedure procedure) throws DatabaseException {
528
529                 if(ri.isFinal) {
530
531                         graph.processor.querySupport.getObjects(graph, r1, r2, new IntProcedure() {
532
533                                 @Override
534                                 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
535                                         if(entry != null) entry.addOrSet(r1, r2, i);
536                                         else procedure.execute(graph, r1, r2, i);
537                                 }
538
539                                 @Override
540                                 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
541                                         if(DebugException.DEBUG) new DebugException(t).printStackTrace();
542                                         procedure.exception(graph, t);
543                                 }
544
545                                 @Override
546                                 public void finished(ReadGraphImpl graph) {
547                                 }
548
549                         });
550
551                         if(ri.isAsserted) {
552                                 forAssertions(graph, r1, r2, entry, procedure);
553                         } else {
554                                 if(entry != null) entry.finish(graph, procedure);
555                                 else procedure.finished(graph);
556                         }
557
558         } else {
559
560             // Note! The dependency is intentionally cut!
561             IntSet direct = QueryCache.resultDirectPredicates(graph, r1, null, null);
562             direct.forEach(graph, new SyncIntProcedure() {
563                 
564                 @Override
565                 public void run(ReadGraphImpl graph) throws DatabaseException {
566                     
567                     forAssertions(graph, r1, r2, entry, procedure);
568                     
569                 }
570
571                 @Override
572                 public void execute(ReadGraphImpl graph, final int pred2) throws DatabaseException {
573
574                     if(pred2 == r2) {
575                         
576                         inc();
577                         
578                         // Note! The dependency is intentionally cut!
579                         QueryCache.runnerDirectObjects(graph, r1, pred2, null, null, new IntProcedure() {
580
581                             @Override
582                             public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
583                                 if(entry != null) entry.addOrSet(r1, pred2, i);
584                                 else procedure.execute(graph, r1, pred2, i);
585                             }
586
587                             @Override
588                             public void finished(ReadGraphImpl graph) throws DatabaseException {
589                                 dec(graph);
590                             }
591                                                 
592                                                 @Override
593                                                 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
594                                                         procedure.exception(graph, t);
595                                 dec(graph);
596                                     }
597
598                         });
599
600                     } else {
601                     
602 //                        inc();
603
604                         try {
605                             
606                             IntSet result = QueryCache.resultSuperRelations(graph, pred2, entry, null);
607                             if(result.contains(r2)) {
608
609                                 inc();
610
611                                 // Note! The dependency is intentionally cut!
612                                 QueryCache.runnerDirectObjects(graph, r1, pred2, null, null, new IntProcedure() {
613
614                                     @Override
615                                     public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
616                                         if(entry != null) entry.addOrSet(r1, pred2, i);
617                                         else procedure.execute(graph, r1, pred2, i);
618
619                                     }
620
621                                     @Override
622                                     public void finished(ReadGraphImpl graph) throws DatabaseException {
623                                         dec(graph);
624                                     }
625
626                                     @Override
627                                     public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
628                                         procedure.exception(graph, t);
629                                         dec(graph);
630                                     }
631
632                                 });
633
634                             }
635                             
636                         } catch (Throwable e) {
637                             procedure.exception(graph, e);
638                         }
639
640                     }
641                     
642                 }
643
644                 @Override
645                 public void finished(ReadGraphImpl graph) throws DatabaseException {
646                     dec(graph);
647                 }
648                 
649             });
650             
651         }
652         
653     }
654         
655     public static void computeForEach(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final TripleIntProcedure procedure) throws DatabaseException {
656         
657         if(entry != null) {
658                 assert(entry.isPending());
659         }
660         
661         QueryCache.runnerRelationInfoQuery(graph, r2, entry, null, new InternalProcedure<RelationInfo>() {
662
663             @Override
664             public void execute(ReadGraphImpl graph, final RelationInfo ri) throws DatabaseException {
665                 
666                 graph.ensureLoaded(r1, r2);
667                 if(ri.isFunctional) {
668                         computeFunctionalIndex(graph, r1, r2, entry, ri, procedure);
669                 } else {
670                         computeNotFunctionalIndex(graph, r1, r2, entry, ri, procedure);
671                 }
672                 
673             }
674                         
675                         @Override
676                         public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
677                                 procedure.exception(graph, t);
678             }
679
680         });
681         
682     }
683     
684     @Override
685     public String toString() {
686         return "Statements[" + r1() + " - " + r2() + "]";
687     }
688
689     final private void finish(ReadGraphImpl graph, TripleIntProcedure procedure) throws DatabaseException {
690         
691         assert(assertPending());
692
693         synchronized(this) {
694             setReady();
695             //new Exception(toString() + " is READY").printStackTrace();
696         }
697
698         IntArray v = (IntArray)getResult();
699         final IntArray value = (IntArray)getResult();
700
701         for(int i=0;i<value.size();i+=3) {
702                 procedure.execute(graph, value.data[i], value.data[i+1], value.data[i+2]);
703         }
704         
705         procedure.finished(graph);
706         
707     }
708
709     synchronized public void addOrSet(int s, int p, int o) {
710         
711         assert(assertPending());
712         
713         IntArray value = (IntArray)getResult();
714         value.add(s);
715         value.add(p);
716         value.add(o);
717         
718     }
719
720     final static public int r1(long id) {
721         return (int)(id>>>32);
722     }
723     
724     final static public int r2(long id) {
725         return (int)id;
726     }
727     
728     final public void addOrSetFunctional(int s, long po) {
729         
730         addOrSetFunctional(s, r1(po), r2(po));
731         
732     }
733
734     final public void addOrSetFunctional(int s, int p, int o) {
735         
736         assert(assertPending());
737         
738         IntArray value = (IntArray)getResult();
739         value.add(s);
740         value.add(p);
741         value.add(o);
742         
743     }
744     
745     @Override
746     public Object performFromCache(ReadGraphImpl graph, final TripleIntProcedure procedure) throws DatabaseException {
747
748         assert(isReady());
749
750         final IntArray value = (IntArray)getResult();
751
752         if(handleException(graph, procedure)) return value;
753         
754         for(int i=0;i<value.size();i+=3) {
755                 procedure.execute(graph, value.data[i], value.data[i+1], value.data[i+2]);
756         }
757
758         procedure.finished(graph);
759         
760         return value;
761         
762     }
763     
764     @Override
765     public void recompute(ReadGraphImpl graph) throws DatabaseException {
766         
767         computeForEach(graph, r1(), r2(), this, new TripleIntProcedureAdapter() {
768
769             @Override
770             public void finished(ReadGraphImpl graph) {
771             }
772                         
773                         @Override
774                         public void exception(ReadGraphImpl graph, Throwable t) {
775                                 new Error("Error in recompute.", t).printStackTrace();
776             }
777
778         });
779         
780     }
781
782     @Override
783     public int type() {
784         return RequestFlags.IMMEDIATE_UPDATE;
785     }
786     
787
788     @Override
789     boolean isImmutable(ReadGraphImpl graph) {
790         return graph.processor.isImmutable(r1());
791     }
792     
793 }