]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/Objects.java
Help investigation of query caching problems via query histogram data
[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 java.util.Collection;
15 import java.util.concurrent.Semaphore;
16
17 import org.simantics.databoard.Bindings;
18 import org.simantics.db.DevelopmentKeys;
19 import org.simantics.db.RelationInfo;
20 import org.simantics.db.Resource;
21 import org.simantics.db.common.exception.DebugException;
22 import org.simantics.db.exception.DatabaseException;
23 import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
24 import org.simantics.db.impl.graph.ReadGraphImpl;
25 import org.simantics.db.impl.procedure.IntProcedureAdapter;
26 import org.simantics.db.impl.procedure.InternalProcedure;
27 import org.simantics.db.procedure.AsyncMultiProcedure;
28 import org.simantics.db.procedure.ListenerBase;
29 import org.simantics.db.request.RequestFlags;
30 import org.simantics.utils.Development;
31
32 /*
33  * Size analysis:
34  * java 8 byte
35  * id 8 byte
36  * statusOrException 4 byte
37  * p1 = 4 byte
38  * p2OrParents = 4 byte
39  * result = 4 byte 
40  * 
41  * total 32byte
42  * 
43  */
44
45 final public class Objects extends CollectionBinaryQuery<IntProcedure> {
46
47         public Objects(final int r1, final int r2) {
48                 super(r1, r2);
49         }
50
51         final static Objects entry(final QueryProcessor provider, final int r1, final int r2) {
52                 return (Objects)provider.objectsMap.get(r1,r2);
53         }
54
55         final static Collection<Objects> entries(final QueryProcessor processor, final int r1) {
56                 return processor.objectsMap.values(r1);
57         }
58
59         public final static void runner(ReadGraphImpl graph, final int r1, final int r2, CacheEntry parent, ListenerBase listener, final IntProcedure procedure) {
60
61                 if(parent == null && listener == null) {
62                         if(Development.DEVELOPMENT)
63                                 Development.recordHistogram(new Objects(r1, r2).toString());
64                         
65                         Objects.computeForEach(graph, r1, r2, null, procedure);
66                         return;
67                 }
68
69                 QueryProcessor processor = graph.processor;
70
71                 Objects entry = (Objects)processor.objectsMap.get(r1,r2);
72                 if(entry == null) {
73
74                         entry = new Objects(r1, r2);
75                         entry.setPending();
76                         entry.clearResult(processor.querySupport);
77                         entry.putEntry(processor);
78
79                         if(Development.DEVELOPMENT)
80                                 Development.recordHistogram(entry.toString());
81
82                         processor.performForEach(graph, entry, parent, listener, procedure);
83
84                 } else {
85
86                         if(entry.isPending()) {
87                                 synchronized(entry) {
88                                         if(entry.isPending()) {
89                                                 processor.registerDependencies(graph, entry, parent, listener, procedure, false);
90                                                 computeForEach(graph, r1, r2, null, procedure);
91                                                 return;
92                                         }
93                                 }
94                         }
95
96                         processor.performForEach(graph, entry, parent, listener, procedure);
97
98                 }
99
100         }
101
102         static class Runner2Procedure implements IntProcedure {
103             
104             public int single = 0;
105             public Throwable t = null;
106
107             public void clear() {
108                 single = 0;
109                 t = null;
110             }
111             
112         @Override
113         public void execute(ReadGraphImpl graph, int i) {
114             if(single == 0) single = i;
115             else single = -1;
116         }
117
118         @Override
119         public void finished(ReadGraphImpl graph) {
120             if(single == -1) single = 0;
121         }
122
123         @Override
124         public void exception(ReadGraphImpl graph, Throwable throwable) {
125             single = 0;
126             this.t = throwable;
127         }
128         
129         public int get() throws DatabaseException {
130             if(t != null) {
131                 if(t instanceof DatabaseException) throw (DatabaseException)t;
132                 else throw new DatabaseException(t);
133             }
134             return single;
135         }
136             
137         }
138         
139         static final Runner2Procedure runner2Procedure = new Runner2Procedure();
140         
141     public final static int runner2(ReadGraphImpl graph, final int r1, final int r2, CacheEntry parent) throws DatabaseException {
142
143         runner2Procedure.clear();
144
145         if(parent == null) {
146             Objects.computeForEach(graph, r1, r2, null, runner2Procedure);
147             return runner2Procedure.get();
148         }
149
150         QueryProcessor processor = graph.processor;
151
152         Objects entry = (Objects)processor.objectsMap.get(r1,r2);
153         if(entry == null) {
154
155             entry = new Objects(r1, r2);
156             entry.setPending();
157             entry.clearResult(processor.querySupport);
158             entry.putEntry(processor);
159
160             processor.performForEach(graph, entry, parent, null, runner2Procedure);
161             return runner2Procedure.get();
162
163         } else {
164
165             if(entry.isPending()) throw new IllegalStateException();
166
167             processor.performForEach(graph, entry, parent, null, runner2Procedure);
168             return runner2Procedure.get();
169
170         }
171
172     }
173         
174         @Override
175         public BinaryQuery<IntProcedure> getEntry(QueryProcessor provider) {
176                 return provider.objectsMap.get(id);
177         }
178
179         @Override
180         public void putEntry(QueryProcessor provider) {
181                 if(Development.DEVELOPMENT) {
182                         if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_PUT, Bindings.BOOLEAN)) {
183                                 System.err.println("put " + this);
184                         }
185                 }
186                 provider.objectsMap.put(id, this);
187         }
188
189         @Override
190         final public void removeEntry(QueryProcessor provider) {
191                 provider.objectsMap.remove(id);
192         }
193
194         final static private IntArray getAssertionMap(ReadGraphImpl graph, final int r1, final int r2, final Objects entry) {
195
196                 class AssertionMapProc implements IntProcedure {
197
198                         boolean first = true;
199
200                         private IntArray result;
201
202                         public void addStatement(int s, int p, int o) {
203
204                                 if(result.size() == 0) {
205                                         result.add(s);
206                                         result.add(p);
207                                         result.add(o);
208                                 } else {
209                                         for(int i = 0;i < result.sizeOrData ; i+=3) {
210                                                 int existingP = result.data[i+1];
211                                                 if(p == existingP) {
212                                                         int existingO = result.data[i+2];
213                                                         if(existingO == o) return;
214                                                 }
215                                         }
216                                         result.add(s);
217                                         result.add(p);
218                                         result.add(o);
219                                 }
220
221                         }
222
223                         @Override
224                         public void execute(ReadGraphImpl graph, int type) {
225                                 AssertedStatements stms = AssertedStatements.queryEach(graph, type, r2, graph.processor, entry, null, NOPT);
226                                 if(result == null) {
227                                         result = stms.getResult();
228                                 } else {
229                                         if (first) {
230                                                 IntArray ia = result;
231                                                 result = new IntArray();
232                                                 if(ia.data != null) {
233                                                         for(int i = 0;i < ia.sizeOrData ; i+=3) addStatement(ia.data[i],ia.data[i+1],ia.data[i+2]);
234                                                 }
235                                                 first = false;
236                                         }
237                                         IntArray ia = stms.getResult();
238                                         if(ia.data != null) {
239                                                 for(int i = 0;i < ia.sizeOrData ; i+=3) addStatement(ia.data[i],ia.data[i+1],ia.data[i+2]);
240                                         }
241                                 }
242                         }
243
244                         @Override
245                         public void finished(ReadGraphImpl graph) {
246                         }
247
248                         @Override
249                         public void exception(ReadGraphImpl graph, Throwable throwable) {
250                         }
251
252                 }
253
254                 AssertionMapProc amp = new AssertionMapProc();
255
256                 // This dependency could be cut
257                 PrincipalTypes.queryEach(graph, r1, graph.processor, entry, null, amp);
258
259                 return amp.result;
260
261         }
262
263         final static private void forSingleAssertion(ReadGraphImpl graph, final int r1, final int r2, final Objects entry, final IntProcedure procedure) {
264
265                 IntArray map = getAssertionMap(graph, r1, r2, entry);
266                 if(map == null) {
267                         if(entry != null) entry.finish(graph, procedure);
268                         else procedure.finished(graph);
269                         return;
270                 }
271
272                 int size = map.size();
273                 if(size == 3) {
274
275                         int value = map.data[2];
276
277                         if(entry != null) {
278                                 entry.addOrSetFunctional(value);
279                                 entry.finish(graph, procedure);
280                         } else {
281                                 procedure.execute(graph, value);
282                                 procedure.finished(graph);
283                         }
284
285                 } else if(size == 0) {
286
287                         if(entry != null) entry.finish(graph, procedure);
288                         else procedure.finished(graph);
289
290                 } else {
291
292                         int candidateS = map.data[0];
293                         int candidateO = map.data[2];
294
295                         SuperTypes candidate = SuperTypes.queryEach(graph, candidateS, graph.processor, entry, null, NOP);
296                         if(candidate.isExcepted()) {
297                                 if(entry != null) entry.except((Throwable)candidate.getResult());
298                                 procedure.exception(graph, (Throwable)candidate.getResult());
299                                 return;
300                         }
301                         IntSet candidateIs = candidate.getResult();
302
303                         for(int i=3;i<map.size();i+=3) {
304
305                                 int nextS = map.data[i];
306                                 int nextO = map.data[i+2];
307
308                                 if(nextS != candidateS) {
309
310                                         if(candidateIs.contains(nextS)) {
311
312                                                 // Next is a super type of candidate => ignore next
313
314                                         } else {
315
316                                                 SuperTypes next = SuperTypes.queryEach(graph, nextS, graph.processor, entry, null, NOP);
317                                                 if(next.isExcepted()) {
318                                                         if(entry != null) entry.except((Throwable)next.getResult());
319                                                         procedure.exception(graph, (Throwable)next.getResult());
320                                                         return;
321                                                 }
322                                                 IntSet nextIs = next.getResult();
323
324                                                 if(nextIs.contains(candidateS)) {
325
326                                                         // Candidate is a super type of next => next is the new candidate
327
328                                                         candidateS = nextS;
329                                                         candidateO = nextO;
330                                                         candidateIs = nextIs;
331
332                                                 } else {
333
334                                                         // candidate and next are unrelated => error
335                                                         ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has conflicting assertions " + r1 + ", " + r2 + " " + map , r1);
336
337                                                         if(entry != null) entry.except(exception);
338                                                         procedure.exception(graph, exception);
339                                                         return;                                         
340
341                                                 }
342
343                                         }
344
345                                 }
346
347                         }
348
349                         if(entry != null) {
350                                 entry.addOrSetFunctional(candidateO);
351                                 entry.finish(graph, procedure);
352                         } else {
353                                 procedure.execute(graph, candidateO);
354                                 procedure.finished(graph);
355                         }
356
357                 }
358
359         }
360
361         final static InternalProcedure<IntSet> NOP = new InternalProcedure<IntSet>() {
362
363                 @Override
364                 public void execute(ReadGraphImpl graph, IntSet result) {
365                 }
366
367                 @Override
368                 public void exception(ReadGraphImpl graph, Throwable throwable) {
369                 }
370
371         };
372
373         final static TripleIntProcedure NOPT = new TripleIntProcedure() {
374
375
376                 @Override
377                 public void exception(ReadGraphImpl graph, Throwable throwable) {
378                 }
379
380                 @Override
381                 public void execute(ReadGraphImpl graph, int s, int p, int o) {
382                 }
383
384                 @Override
385                 public void finished(ReadGraphImpl graph) {
386                 }
387
388         };
389
390         // Search for one statement
391         final public void computeFunctionalIndex(ReadGraphImpl graph, final QueryProcessor provider, final RelationInfo ri, final IntProcedure procedure) {
392                 computeFunctionalIndex(graph, r1(), r2(), this, ri, procedure);
393         }
394
395         // Search for one statement
396         final static public void computeFunctionalIndex(ReadGraphImpl graph, final int r1, final int r2, final Objects entry, final RelationInfo ri, final IntProcedure procedure) {
397
398                 if(ri.isFinal) {
399
400                         int result = graph.processor.querySupport.getFunctionalObject(r1, r2);
401
402                         if(result == 0) {
403
404                                 // Check for assertions
405                                 forSingleAssertion(graph, r1, r2, entry, procedure);
406
407                         } else if (result == -1) {
408
409                                 graph.processor.querySupport.getObjects(graph, r1, r2, new IntProcedure() {
410
411                                         @Override
412                                         public void execute(ReadGraphImpl graph, int i) {
413                                                 if(entry != null) entry.addOrSetFunctional(i);
414                                                 else procedure.execute(graph, i);
415                                         }
416
417                                         @Override
418                                         public void exception(ReadGraphImpl graph, Throwable t) {
419                                                 if(DebugException.DEBUG) new DebugException(t).printStackTrace();
420                                         }
421
422                                         @Override
423                                         public void finished(ReadGraphImpl graph) {
424                                         }
425
426                                 });
427
428                                 // Check for assertions
429                                 forSingleAssertion(graph, r1, r2, entry, procedure);
430
431                         } else {
432
433                                 // If functional relation was found there is no need to check assertions
434                                 if(entry != null) {
435                                         entry.addOrSetFunctional(result);
436                                         entry.finish(graph, procedure);
437                                 } else {
438                                         procedure.execute(graph, result);
439                                         procedure.finished(graph);
440                                 }
441
442                                 
443                         }
444
445                 } else {
446
447                         // Note! The dependency is intentionally cut!
448                         DirectPredicates.queryEach(graph, r1, graph.processor, null, null, new SyncIntProcedure() {
449
450                                 boolean found = false;
451
452                                 @Override
453                                 public void run(ReadGraphImpl graph) {
454
455                                         if(found) {
456                                                 if(entry != null) entry.finish(graph, procedure);
457                                                 else procedure.finished(graph);
458                                         } else {
459
460                                                 // Check for assertions
461                                                 forSingleAssertion(graph, r1, r2, entry, procedure);
462
463                                         }
464
465                                 }
466
467                                 @Override
468                                 public void execute(ReadGraphImpl graph, final int pred) {
469
470                                         if(found) return;
471
472                                         if(pred == r2) {
473
474                                                 // Note! The dependency is intentionally cut!
475                                                 DirectObjects.queryEach(graph, r1, pred, graph.processor, null, null, new IntProcedure() {
476
477                                                         @Override
478                                                         public void execute(ReadGraphImpl graph, int i) {
479
480                                                                 if(!found) {
481
482                                                                         if(entry != null) entry.addOrSetFunctional(i);
483                                                                         else procedure.execute(graph, i);
484
485                                                                         found = true;
486
487                                                                 } else {
488
489                                                                         ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has more than one statement (r1=" + r1 + ", r2=" + r2 + ").", r1);
490                                                                         if(entry != null) entry.except(exception);
491                                                                         procedure.exception(graph, exception);
492
493                                                                 }
494
495                                                         }
496
497                                                         @Override
498                                                         public void finished(ReadGraphImpl graph) {
499                                                         }
500
501                                                         @Override
502                                                         public void exception(ReadGraphImpl graph, Throwable t) {
503                                                                 procedure.exception(graph, t);
504                                                         }
505
506                                                 });
507
508                                         } else {
509
510                                                 SuperRelations.queryEach(graph, pred, graph.processor, entry, null, new InternalProcedure<IntSet>() {
511
512                                                         @Override
513                                                         public void execute(ReadGraphImpl graph, IntSet result) {
514
515                                                                 if(found) return;
516
517                                                                 if(result.contains(r2)) {
518
519                                                                         // Note! The dependency is intentionally cut!
520                                                                         DirectObjects.queryEach(graph, r1, pred, graph.processor, null, null, new IntProcedure() {
521
522                                                                                 @Override
523                                                                                 public void execute(ReadGraphImpl graph, int i) {
524
525                                                                                         if(!found) {
526
527                                                                                                 if(entry != null) entry.addOrSetFunctional(i);
528                                                                                                 else procedure.execute(graph, i);
529
530                                                                                                 found = true;
531
532                                                                                         } else {
533
534                                                                                                 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has more than one statement (r1=" + r1 + ", r2=" + r2 + ").", r1);
535                                                                                                 if(entry != null) entry.except(exception);
536                                                                                                 procedure.exception(graph, exception);
537
538                                                                                         }
539
540                                                                                 }
541
542                                                                                 @Override
543                                                                                 public void finished(ReadGraphImpl graph) {
544                                                                                 }
545
546                                                                                 @Override
547                                                                                 public void exception(ReadGraphImpl graph, Throwable t) {
548                                                                                         procedure.exception(graph, t);
549                                                                                 }
550
551                                                                         });
552
553                                                                 }
554
555                                                         }
556
557                                                         @Override
558                                                         public void exception(ReadGraphImpl graph, Throwable t) {
559                                                                 procedure.exception(graph, t);
560                                                         }
561
562                                                 });
563
564                                         }
565
566                                 }
567
568                                 @Override
569                                 public void finished(ReadGraphImpl graph) {
570
571                                         dec(graph);
572
573                                 }
574
575                         });
576
577
578                 }
579
580         }
581
582         final static private void forAssertions(ReadGraphImpl graph, final int r1, final int r2, final Objects entry, final IntProcedure procedure) {
583
584                 // Note! The dependency is intentionally cut!
585                 PrincipalTypes.queryEach(graph, r1, graph.processor, null, null, new SyncIntProcedure() {
586
587                         @Override
588                         public void run(ReadGraphImpl graph) {
589
590                                 if(entry != null) entry.finish(graph, procedure);
591                                 else procedure.finished(graph);
592
593                         }
594
595                         TripleIntProcedure proc = new TripleIntProcedure() {
596
597                                 @Override
598                                 public void execute(ReadGraphImpl graph, int s, int p, int o) {
599                                         if(entry != null) entry.addOrSet(o);
600                                         else procedure.execute(graph, o);
601                                 }
602
603                                 @Override
604                                 public void finished(ReadGraphImpl graph) {
605                                         dec(graph);
606                                 }
607
608                                 @Override
609                                 public void exception(ReadGraphImpl graph, Throwable t) {
610                                         if(DebugException.DEBUG) new DebugException(t).printStackTrace();
611                                         procedure.exception(graph, t);
612                                         dec(graph);
613                                 }
614
615                         };
616
617                         @Override
618                         public void execute(ReadGraphImpl graph, int type) {
619
620                                 inc();
621
622                                 AssertedStatements.queryEach(graph, type, r2, graph.processor, entry, null, proc);
623
624                         }
625
626                         @Override
627                         public void finished(ReadGraphImpl graph) {
628                                 dec(graph);
629                         }
630
631                 });
632
633
634         }
635
636         final public static void computeNotFunctionalFinalIndex(ReadGraphImpl graph, final int r1, final int r2, final QueryProcessor provider, RelationInfo ri, AsyncMultiProcedure<Resource> procedure) {
637
638                 throw new Error();
639
640         }
641
642         final public void computeNotFunctionalIndex(ReadGraphImpl graph, RelationInfo ri, final IntProcedure procedure) {
643                 computeNotFunctionalIndex(graph, r1(), r2(), this, ri, procedure);
644         }
645
646         final static public void computeNotFunctionalIndex(ReadGraphImpl graph, final int r1, final int r2, final Objects entry, RelationInfo ri, final IntProcedure procedure) {
647
648                 if(ri.isFinal) {
649
650                         graph.processor.querySupport.getObjects(graph, r1, r2, new IntProcedure() {
651
652                                 @Override
653                                 public void execute(ReadGraphImpl graph, int i) {
654                                         if(entry != null) entry.addOrSet(i);
655                                         else procedure.execute(graph, i);
656                                 }
657
658                                 @Override
659                                 public void exception(ReadGraphImpl graph, Throwable t) {
660                                         if(DebugException.DEBUG) new DebugException(t).printStackTrace();
661                                         procedure.exception(graph, t);
662                                 }
663
664                                 @Override
665                                 public void finished(ReadGraphImpl graph) {
666                                 }
667
668                         });
669
670                         if(ri.isAsserted) {
671                                 forAssertions(graph, r1, r2, entry, procedure);
672                         } else {
673                                 if(entry != null) entry.finish(graph, procedure);
674                                 else procedure.finished(graph);
675                         }
676
677                 } else {
678
679                         // Note! The dependency is intentionally cut!
680                         DirectPredicates.queryEach(graph, r1, graph.processor, null, null, new SyncIntProcedure() {
681
682                                 @Override
683                                 public void run(ReadGraphImpl graph) {
684
685                                         forAssertions(graph, r1, r2, entry, procedure);
686
687                                 }
688
689                                 @Override
690                                 public void execute(ReadGraphImpl graph, final int pred) {
691
692                                         if(pred == r2) {
693
694                                                 inc();
695
696                                                 // Note! The dependency is intentionally cut!
697                                                 DirectObjects.queryEach(graph, r1, pred, graph.processor, null, null, new IntProcedure() {
698
699                                                         @Override
700                                                         public void execute(ReadGraphImpl graph, int i) {
701                                                                 if(entry != null) entry.addOrSet(i);
702                                                                 else procedure.execute(graph, i);
703                                                         }
704
705                                                         @Override
706                                                         public void finished(ReadGraphImpl graph) {
707                                                                 dec(graph);
708                                                         }
709
710                                                         @Override
711                                                         public void exception(ReadGraphImpl graph, Throwable t) {
712                                                                 procedure.exception(graph, t);
713                                                                 dec(graph);
714                                                         }
715
716                                                 });
717
718                                         } else {
719
720                                                 inc();
721
722                                                 SuperRelations.queryEach(graph, pred, graph.processor, entry, null, new InternalProcedure<IntSet>() {
723
724                                                         @Override
725                                                         public void execute(ReadGraphImpl graph, IntSet result) {
726
727                                                                 if(result.contains(r2)) {
728
729                                                                         inc();
730
731                                                                         // Note! The dependency is intentionally cut!
732                                                                         DirectObjects.queryEach(graph, r1, pred, graph.processor, null, null, new IntProcedure() {
733
734                                                                                 @Override
735                                                                                 public void execute(ReadGraphImpl graph, int i) {
736                                                                                         if(entry != null) entry.addOrSet(i);
737                                                                                         else procedure.execute(graph, i);
738                                                                                 }
739
740                                                                                 @Override
741                                                                                 public void finished(ReadGraphImpl graph) {
742                                                                                         dec(graph);
743                                                                                 }
744
745                                                                                 @Override
746                                                                                 public void exception(ReadGraphImpl graph, Throwable t) {
747                                                                                         if(DebugException.DEBUG) new DebugException(t).printStackTrace();
748                                                                                         procedure.exception(graph, t);
749                                                                                         dec(graph);
750                                                                                 }
751
752                                                                         });
753
754                                                                 }
755
756                                                                 dec(graph);
757
758                                                         }
759
760                                                         @Override
761                                                         public void exception(ReadGraphImpl graph, Throwable t) {
762                                                                 procedure.exception(graph, t);
763                                                                 dec(graph);
764                                                         }
765
766                                                 });
767
768                                         }
769
770                                 }
771
772                                 @Override
773                                 public void finished(ReadGraphImpl graph) {
774                                         dec(graph);
775                                 }
776
777                         });
778
779                 }
780
781         }
782
783         @Override
784         public void computeForEach(ReadGraphImpl graph, final QueryProcessor provider, final IntProcedure procedure, final boolean store) {
785                 computeForEach(graph, r1(), r2(), this, procedure);
786         }
787
788         public static void computeForEach(ReadGraphImpl graph, final int r1, final int r2, final Objects entry, final IntProcedure procedure) {
789
790                 RelationInfo ri = RelationInfoQuery.queryEach(graph, r2, graph.processor, entry, null, ip);
791                 graph.ensureLoaded(r1, r2);       
792                 if(ri.isFunctional) {
793                         computeFunctionalIndex(graph, r1, r2, entry, ri, procedure);
794                 } else {
795                         computeNotFunctionalIndex(graph, r1, r2, entry, ri, procedure);
796                 }
797
798         }
799
800         final static InternalProcedure<RelationInfo> ip = new InternalProcedure<RelationInfo>() {
801
802                 @Override
803                 public void execute(ReadGraphImpl graph, RelationInfo result) {
804                 }
805
806                 @Override
807                 public void exception(ReadGraphImpl graph, Throwable throwable) {
808                 }
809
810         };
811
812         @Override
813         public String toString() {
814                 return "Objects[" + r1() + " - " + r2() + "]";
815         }
816
817         final private void finish(ReadGraphImpl graph, IntProcedure procedure) {
818
819                 assert(assertPending());
820
821                 synchronized(this) {
822                         setReady();
823                 }
824
825                 IntArray v = (IntArray)getResult();
826
827                 if(v.data == null) {
828                         if(v.sizeOrData != IntArray.NO_DATA) {
829                                 procedure.execute(graph, v.sizeOrData);
830                         }
831                 } else {
832                         for(int i = 0;i < v.sizeOrData ; i++) {
833                                 procedure.execute(graph, v.data[i]);
834                         }
835                 }
836
837                 procedure.finished(graph);
838
839         }
840
841         final public void addOrSet(int add) {
842
843                 assert(assertPending());
844
845                 IntArray value = (IntArray)getResult();
846                 synchronized(value) {
847                         value.add(add);
848                 }
849
850         }
851
852         final public void addOrSetFunctional(int add) {
853
854                 assert(isPending());
855
856                 IntArray value = (IntArray)getResult();
857                 value.add(add);
858
859         }
860
861         @Override
862         public void performFromCache(ReadGraphImpl graph, QueryProcessor provider, final IntProcedure procedure) {
863
864                 assert(isReady());
865
866                 if(handleException(graph, procedure)) return;
867
868                 final IntArray value = (IntArray)getResult();
869                 if(value.data == null) {
870                         if(value.sizeOrData != IntArray.NO_DATA) procedure.execute(graph, value.sizeOrData);
871                 } else {
872                         for(int i = 0;i < value.sizeOrData ; i++) procedure.execute(graph, value.data[i]);
873                 }
874
875                 procedure.finished(graph);
876
877         }
878
879         @Override
880         public void recompute(ReadGraphImpl graph, QueryProcessor provider) {
881
882                 final Semaphore s = new Semaphore(0);
883
884                 computeForEach(graph, provider, new IntProcedureAdapter() {
885
886                         @Override
887                         public void finished(ReadGraphImpl graph) {
888                                 s.release();
889                         }
890
891                         @Override
892                         public void exception(ReadGraphImpl graph, Throwable t) {
893                                 s.release();
894                                 new Error("Error in recompute.", t).printStackTrace();
895                         }
896
897                 }, true);
898
899                 while(!s.tryAcquire()) {
900                         provider.resume(graph);
901                 }
902
903         }
904
905         @Override
906         public int type() {
907                 return RequestFlags.IMMEDIATE_UPDATE;
908         }
909
910         @Override
911         boolean isImmutable(ReadGraphImpl graph) {
912                 return graph.processor.isImmutable(r1());
913         }
914
915 }