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