]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/Objects.java
Multiple reader thread support for db client
[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
274                 } else {
275
276                         // Note! The dependency is intentionally cut!
277             IntSet direct = QueryCache.resultDirectPredicates(graph, r1, null, null);
278             direct.forEach(graph, new SyncIntProcedure() {
279
280                                 boolean found = false;
281
282                                 @Override
283                                 public void run(ReadGraphImpl graph) throws DatabaseException {
284
285                                         if(found) {
286                                                 procedure.finished(graph);
287                                         } else {
288
289                                                 // Check for assertions
290                                                 forSingleAssertion(graph, r1, r2, parent, procedure);
291
292                                         }
293
294                                 }
295
296                                 @Override
297                                 public void execute(ReadGraphImpl graph, final int pred) throws DatabaseException {
298
299                                         if(found) return;
300
301                                         if(pred == r2) {
302
303                                                 // Note! The dependency is intentionally cut!
304                                                 QueryCache.runnerDirectObjects(graph, r1, pred, null, null, new IntProcedure() {
305
306                                                         @Override
307                                                         public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
308
309                                                                 if(!found) {
310
311                                                                         procedure.execute(graph, i);
312                                                                         found = true;
313
314                                                                 } else {
315
316                                                                         ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has more than one statement (r1=" + r1 + ", r2=" + r2 + ").", r1);
317                                                                         procedure.exception(graph, exception);
318
319                                                                 }
320
321                                                         }
322
323                                                         @Override
324                                                         public void finished(ReadGraphImpl graph) {
325                                                         }
326
327                                                         @Override
328                                                         public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
329                                                                 procedure.exception(graph, t);
330                                                         }
331
332                                                 });
333
334                                         } else {
335
336                                                 QueryCache.runnerSuperRelations(graph, pred, parent, null, new InternalProcedure<IntSet>() {
337
338                                                         @Override
339                                                         public void execute(ReadGraphImpl graph, IntSet result) throws DatabaseException {
340
341                                                                 if(found) return;
342
343                                                                 if(result.contains(r2)) {
344
345                                                                         // Note! The dependency is intentionally cut!
346                                                                         QueryCache.runnerDirectObjects(graph, r1, pred, null, null, new IntProcedure() {
347
348                                                                                 @Override
349                                                                                 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
350
351                                                                                         if(!found) {
352
353                                                                                                 procedure.execute(graph, i);
354                                                                                                 found = true;
355
356                                                                                         } else {
357
358                                                                                                 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has more than one statement (r1=" + r1 + ", r2=" + r2 + ").", r1);
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                                                                 }
377
378                                                         }
379
380                                                         @Override
381                                                         public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
382                                                                 procedure.exception(graph, t);
383                                                         }
384
385                                                 });
386
387                                         }
388
389                                 }
390
391                                 @Override
392                                 public void finished(ReadGraphImpl graph) throws DatabaseException {
393
394                                         dec(graph);
395
396                                 }
397
398                         });
399
400
401                 }
402
403         }
404
405         final static private void forAssertions(ReadGraphImpl graph, final int r1, final int r2, final Objects parent, final IntProcedure procedure) throws DatabaseException {
406
407                 // Note! The dependency is intentionally cut!
408                 QueryCache.runnerPrincipalTypes(graph, r1, null, null, new SyncIntProcedure() {
409
410                         @Override
411                         public void run(ReadGraphImpl graph) throws DatabaseException {
412                                 procedure.finished(graph);
413                         }
414
415                         TripleIntProcedure proc = new TripleIntProcedure() {
416
417                                 @Override
418                                 public void execute(ReadGraphImpl graph, int s, int p, int o) throws DatabaseException {
419                                         procedure.execute(graph, o);
420                                 }
421
422                                 @Override
423                                 public void finished(ReadGraphImpl graph) throws DatabaseException {
424                                         dec(graph);
425                                 }
426
427                                 @Override
428                                 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
429                                         if(DebugException.DEBUG) new DebugException(t).printStackTrace();
430                                         procedure.exception(graph, t);
431                                         dec(graph);
432                                 }
433
434                         };
435
436                         @Override
437                         public void execute(ReadGraphImpl graph, int type) throws DatabaseException {
438
439                                 inc();
440                                 QueryCache.runnerAssertedStatements(graph, type, r2, parent, null, proc);
441
442                         }
443
444                         @Override
445                         public void finished(ReadGraphImpl graph) throws DatabaseException {
446                                 dec(graph);
447                         }
448
449                 });
450
451
452         }
453
454         final public static void computeNotFunctionalFinalIndex(ReadGraphImpl graph, final int r1, final int r2, final QueryProcessor provider, RelationInfo ri, AsyncMultiProcedure<Resource> procedure) {
455                 throw new Error();
456         }
457
458         final public void computeNotFunctionalIndex(ReadGraphImpl graph, RelationInfo ri, final IntProcedure procedure) throws DatabaseException {
459                 computeNotFunctionalIndex(graph, r1(), r2(), this, ri, procedure);
460         }
461
462         final static public void computeNotFunctionalIndex(ReadGraphImpl graph, final int r1, final int r2, final Objects parent, RelationInfo ri, final IntProcedure procedure) throws DatabaseException {
463
464                 if(ri.isFinal) {
465
466                         graph.processor.querySupport.getObjects(graph, r1, r2, new IntProcedure() {
467
468                                 @Override
469                                 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
470                                         procedure.execute(graph, i);
471                                 }
472
473                                 @Override
474                                 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
475                                         if(DebugException.DEBUG) new DebugException(t).printStackTrace();
476                                         procedure.exception(graph, t);
477                                 }
478
479                                 @Override
480                                 public void finished(ReadGraphImpl graph) {
481                                 }
482
483                         });
484
485                         if(ri.isAsserted) {
486                                 forAssertions(graph, r1, r2, parent, procedure);
487                         } else {
488                                 procedure.finished(graph);
489                         }
490
491                 } else {
492
493                         // Note! The dependency is intentionally cut!
494                         IntSet direct = QueryCache.resultDirectPredicates(graph, r1, null, null);
495                         direct.forEach(graph, new SyncIntProcedure() {
496
497                                 @Override
498                                 public void run(ReadGraphImpl graph) throws DatabaseException {
499                                         forAssertions(graph, r1, r2, parent, procedure);
500                                 }
501
502                                 @Override
503                                 public void execute(ReadGraphImpl graph, final int pred) throws DatabaseException {
504
505                                         if(pred == r2) {
506
507                                                 inc();
508
509                                                 // Note! The dependency is intentionally cut!
510                                                 QueryCache.runnerDirectObjects(graph, r1, pred, null, null, new IntProcedure() {
511
512                                                         @Override
513                                                         public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
514                                                                 procedure.execute(graph, i);
515                                                         }
516
517                                                         @Override
518                                                         public void finished(ReadGraphImpl graph) throws DatabaseException {
519                                                                 dec(graph);
520                                                         }
521
522                                                         @Override
523                                                         public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
524                                                                 procedure.exception(graph, t);
525                                                                 dec(graph);
526                                                         }
527
528                                                 });
529
530                                         } else {
531
532                                                 inc();
533
534                                                 QueryCache.runnerSuperRelations(graph, pred, parent, null, new InternalProcedure<IntSet>() {
535
536                                                         @Override
537                                                         public void execute(ReadGraphImpl graph, IntSet result) throws DatabaseException {
538
539                                                                 if(result.contains(r2)) {
540
541                                                                         inc();
542
543                                                                         // Note! The dependency is intentionally cut!
544                                                                         QueryCache.runnerDirectObjects(graph, r1, pred, null, null, new IntProcedure() {
545
546                                                                                 @Override
547                                                                                 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
548                                                                                         procedure.execute(graph, i);
549                                                                                 }
550
551                                                                                 @Override
552                                                                                 public void finished(ReadGraphImpl graph) throws DatabaseException {
553                                                                                         dec(graph);
554                                                                                 }
555
556                                                                                 @Override
557                                                                                 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
558                                                                                         if(DebugException.DEBUG) new DebugException(t).printStackTrace();
559                                                                                         procedure.exception(graph, t);
560                                                                                         dec(graph);
561                                                                                 }
562
563                                                                         });
564
565                                                                 }
566
567                                                                 dec(graph);
568
569                                                         }
570
571                                                         @Override
572                                                         public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
573                                                                 procedure.exception(graph, t);
574                                                                 dec(graph);
575                                                         }
576
577                                                 });
578
579                                         }
580
581                                 }
582
583                                 @Override
584                                 public void finished(ReadGraphImpl graph) throws DatabaseException {
585                                         dec(graph);
586                                 }
587
588                         });
589
590                 }
591
592         }
593
594         public Object compute(ReadGraphImpl graph, final IntProcedure procedure) throws DatabaseException {
595                 computeForEach(graph, r1(), r2(), this, procedure);
596                 return getResult();
597         }
598
599         public static void computeForEach(ReadGraphImpl graph, final int r1, final int r2, final Objects entry, final IntProcedure procedure_) throws DatabaseException {
600
601             IntProcedure procedure = entry != null ? entry : procedure_;
602             
603         RelationInfo ri = QueryCache.resultRelationInfoQuery(graph, r2, entry, null);
604         graph.ensureLoaded(r1, r2);
605         if(ri.isFunctional) {
606             computeFunctionalIndex(graph, r1, r2, entry, ri, procedure);
607         } else {
608             computeNotFunctionalIndex(graph, r1, r2, entry, ri, procedure);
609         }
610                 
611                 if(entry != null) entry.performFromCache(graph, procedure_);
612
613         }
614
615         @Override
616         public String toString() {
617                 return "Objects[" + r1() + " - " + r2() + "]";
618         }
619
620         @Override
621         public Object performFromCache(ReadGraphImpl graph, final IntProcedure procedure) throws DatabaseException {
622
623                 assert(isReady());
624
625                 if(handleException(graph, procedure)) return getResult();
626
627                 final IntArray value = (IntArray)getResult();
628                 if(value.data == null) {
629                         if(value.sizeOrData != IntArray.NO_DATA) procedure.execute(graph, value.sizeOrData);
630                 } else {
631                         for(int i = 0;i < value.sizeOrData ; i++) procedure.execute(graph, value.data[i]);
632                 }
633
634                 procedure.finished(graph);
635                 
636                 return value;
637
638         }
639
640         @Override
641         public void recompute(ReadGraphImpl graph) throws DatabaseException {
642
643                 compute(graph, new IntProcedureAdapter() {
644
645                         @Override
646                         public void finished(ReadGraphImpl graph) {
647                         }
648
649                         @Override
650                         public void exception(ReadGraphImpl graph, Throwable t) {
651                                 new Error("Error in recompute.", t).printStackTrace();
652                         }
653
654                 });
655
656         }
657
658         @Override
659         public int type() {
660                 return RequestFlags.IMMEDIATE_UPDATE;
661         }
662
663         @Override
664         boolean isImmutable(ReadGraphImpl graph) {
665                 return graph.processor.isImmutable(r1());
666         }
667
668     @Override
669     public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
670         IntArray value = (IntArray)getResult();
671         synchronized(value) {
672             value.add(i);
673         }
674     }
675
676     @Override
677     public void finished(ReadGraphImpl graph) throws DatabaseException {
678         setReady();
679     }
680
681     @Override
682     public void exception(ReadGraphImpl graph, Throwable throwable) throws DatabaseException {
683         except(throwable);
684     }
685
686 }