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