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