]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.procore/src/org/simantics/db/procore/cluster/ResourceTable.java
Merge "Multiple reader thread support for db client"
[simantics/platform.git] / bundles / org.simantics.db.procore / src / org / simantics / db / procore / cluster / ResourceTable.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.procore.cluster;
13
14 import java.util.ArrayList;
15
16 import org.simantics.db.Resource;
17 import org.simantics.db.common.utils.Logger;
18 import org.simantics.db.exception.DatabaseException;
19 import org.simantics.db.exception.ExternalValueException;
20 import org.simantics.db.exception.ValidationException;
21 import org.simantics.db.impl.ClusterBase;
22 import org.simantics.db.impl.ClusterI;
23 import org.simantics.db.impl.ClusterI.CompleteTypeEnum;
24 import org.simantics.db.impl.ClusterI.ObjectProcedure;
25 import org.simantics.db.impl.ClusterI.PredicateProcedure;
26 import org.simantics.db.impl.ClusterI.Procedure;
27 import org.simantics.db.impl.ClusterSupport;
28 import org.simantics.db.impl.ClusterTraitsBase;
29 import org.simantics.db.impl.Modifier;
30 import org.simantics.db.impl.ResourceImpl;
31 import org.simantics.db.impl.Table;
32 import org.simantics.db.impl.TableFactory;
33 import org.simantics.db.impl.TableSizeListener;
34 import org.simantics.db.impl.graph.ReadGraphImpl;
35 import org.simantics.db.procedure.AsyncContextMultiProcedure;
36 import org.simantics.db.procedure.SyncContextMultiProcedure;
37 import org.simantics.db.procedure.SyncMultiProcedure;
38 import org.simantics.db.procore.cluster.PredicateTable.Status;
39
40
41 final class ResourceElement {
42     private static final boolean DEBUG = ClusterImpl.DEBUG;
43     private static final int DESCRIPTOR_OFFSET = 0; // predicate descriptor
44     private static final int VALUE_OFFSET      = 1; // value descriptor
45     private static final int STM_OFFSET        = 2; // first statement
46     private static final int SIZE_OF           = 4;
47
48     static void construct(long[] table, int index) {
49         int i = DESCRIPTOR_OFFSET + index;
50         table[i++] = 0; // predicate capacity & index
51         table[i++] = 0; // value capacity & index
52         table[i++] = 0; // stm1
53         table[i++] = 0; // stm2
54     }
55
56     static void destruct(long[] table, int index) {
57         int i = DESCRIPTOR_OFFSET + index;
58         table[i++] = 0; // predicate capacity & index
59         table[i++] = 0; // value capacity & index
60         table[i++] = 0; // stm1
61         table[i++] = 0; // stm2
62     }
63
64     static boolean isUsed(long[] table, int index) {
65         int i = DESCRIPTOR_OFFSET + index;
66         if (table[i++] != 0)
67             return true;
68         if (table[i++] != 0)
69             return true;
70         if (table[i++] != 0)
71             return true;
72         if (table[i++] != 0)
73             return true;
74         return false;
75     }
76
77     static int getSizeOf() {
78         return SIZE_OF;
79     }
80
81     static int getCompleteObjectRef(long[] table, int index) {
82         int i = DESCRIPTOR_OFFSET + index;
83         return BitUtility.getHighInt(table[i]);
84     }
85
86     static void setCompleteObjectRef(long[] table, int index, int ref) {
87         int i = DESCRIPTOR_OFFSET + index;
88         table[i] = BitUtility.setHighInt(table[i], ref);
89     }
90
91     static int getPredicateIndex(long[] table, int index) {
92         int i = DESCRIPTOR_OFFSET + index;
93         int predicateIndex = BitUtility.getLowInt(table[i]);
94         assert (predicateIndex >= 0);
95         return predicateIndex;
96     }
97
98     static void setPredicateIndex(long[] table, int index, int predicateIndex) {
99         assert (predicateIndex >= 0);
100         int i = DESCRIPTOR_OFFSET + index;
101         table[i] = BitUtility.setLowInt(table[i], predicateIndex);
102     }
103
104     static int copyValue(ValueTable valueTable, long[] table, int index, byte[] byteTable, int byteSize, int byteBase,
105             int byteCurrent) {
106         int i = VALUE_OFFSET + index;
107         if (0 == table[i] || -1 == table[i])
108             return byteCurrent; // no value or external value
109         // getValueCapacity call optimized away
110         int capacity = BitUtility.getLowInt(table[i]);
111         int valueIndex = getValueIndex(table, index);
112         if (0 == valueIndex)
113             return byteCurrent;
114         valueTable.getValue(valueIndex, byteTable, byteCurrent, capacity);
115         valueIndex = byteCurrent - byteBase;
116         setValueIndex(table, index, valueIndex);
117         byteCurrent += capacity;
118         return byteCurrent;
119     }
120
121     static byte[] getValue(ValueTable valueTable, long[] table, int index)
122     throws DatabaseException {
123         int i = VALUE_OFFSET + index;
124         if (0 == table[i])
125             return null; // no value
126         if (-1 == table[i])
127             throw new ExternalValueException("Value stored externally.");
128         // getValueCapacity call optimized away
129         int capacity = BitUtility.getLowInt(table[i]);
130         byte[] t = new byte[capacity];
131         int valueIndex = getValueIndex(table, index);
132         valueTable.getValue(valueIndex, t, 0, capacity);
133         return t;
134     }
135
136 //    static int getString(ValueTable valueTable, long[] table, int index, char[] t)
137 //    throws DatabaseException {
138 //        long l = table[index + VALUE_OFFSET];
139 //        if (-1 == l)
140 //            throw new ExternalValueException("String stored externally.");
141 //        int capacity = (int)l;
142 //        int valueIndex = (int) (l >>> 32);
143 ////        char[] t = new char[capacity-1];
144 //        valueTable.getString(valueIndex, t, 0, capacity-1);
145 //        return capacity-1;
146 //        
147 //    }
148
149     static boolean hasValue(long[] table, int index) {
150         int i = VALUE_OFFSET + index;
151         return 0 != table[i];
152     }
153 //KRAA:
154 //    static boolean hasValue(ValueTable valueTable, long[] table, int index, byte[] value) {
155 //        int i = VALUE_OFFSET + index;
156 //        if (0 == table[i])
157 //            return false;
158 //        // getValueCapacity call optimized away
159 //        int capacity = BitUtility.getLowInt(table[i]);
160 //        if (capacity != value.length)
161 //            return false;
162 //        int valueIndex = getValueIndex(table, index);
163 //        return valueTable.isEqual(valueIndex, value);
164 //    }
165
166     static boolean removeValue(ValueTable valueTable, long[] table, int index) {
167         int i = VALUE_OFFSET + index;
168         if (0 == table[i])
169             return false;
170         else if (-1 != table[i]) {
171             // getValueCapacity call optimized away
172             int capacity = BitUtility.getLowInt(table[i]);
173             int valueIndex = getValueIndex(table, index);
174             valueTable.removeValue(valueIndex, capacity);
175         }
176        //setValueCapacityAndIndex(table, index, 0, 0); optimized away
177         table[i] = 0;
178         return true;
179     }
180
181     public static void setValue(ValueTable valueTable, long[] table, int index, byte[] value, int length) {
182         int i = VALUE_OFFSET + index;
183         // getValueCapacity call optimized away
184         int capacity = BitUtility.getLowInt(table[i]); 
185         int valueIndex = getValueIndex(table, index);
186         if (length <= capacity) {
187             valueTable.setValue(valueIndex, value, length);
188             // we "leak" memory TODO: add value size member to
189             // resource entry or value entry
190             setValueCapacity(table, index, length);
191         } else {
192             if (valueIndex != 0 && capacity > 0)
193                 valueTable.removeValue(valueIndex, capacity);
194             valueIndex = valueTable.createValue(value, 0, length);
195             capacity = length;
196             setValueCapacityAndIndex(table, index, capacity, valueIndex);
197         }
198         return;
199     }
200     public static boolean isValueEx(ValueTable valueTable, long[] table, int index) {
201         int i = VALUE_OFFSET + index;
202         if (-1 == table[i])
203             return true;
204         else
205             return false;
206     }
207     public static void setValueEx(ValueTable valueTable, long[] table, int index) {
208         int i = VALUE_OFFSET + index;
209         if (-1 == table[i])
210             return;
211         else if (0 != table[i]) {
212             int capacity = BitUtility.getLowInt(table[i]);
213             int valueIndex = getValueIndex(table, index);
214             valueTable.removeValue(valueIndex, capacity);
215         }
216        //setValueCapacityAndIndex(table, index, 0, 0); optimized away
217         table[i] = -1;
218     }
219     static class ValueData {
220         int capacity;
221         int index;
222 //        ValueData(int capacity, int index) {
223 //            this.capacity = capacity;
224 //            this.index = index;
225 //        }
226     }
227     static void getValueCapacityAndIndex(ValueData vd, long[] table, int index) {
228         int i = VALUE_OFFSET + index;
229         // getValueCapacity call optimized away
230         vd.capacity = BitUtility.getLowInt(table[i]); 
231         vd.index = getValueIndex(table, index);
232         
233     }
234     private static int getValueIndex(long[] table, int index) {
235         int i = VALUE_OFFSET + index;
236         return BitUtility.getHighInt(table[i]);
237     }
238
239     private static void setValueIndex(long[] table, int index, int valueIndex) {
240         int i = VALUE_OFFSET + index;
241         table[i] = BitUtility.setHighInt(table[i], valueIndex);
242     }
243
244     private static void setValueCapacity(long[] table, int index, int capacity) {
245         int i = VALUE_OFFSET + index;
246         table[i] = BitUtility.setLowInt(table[i], capacity);
247     }
248
249     private static void setValueCapacityAndIndex(long[] table, int index, int capacity, int valueIndex) {
250         int i = VALUE_OFFSET + index;
251         table[i] = BitUtility.setLowAndHighInt(table[i], capacity, valueIndex);
252     }
253
254     public static <Context> boolean foreachPredicate(long[] table, int index,
255                 ClusterI.PredicateProcedure<Context> procedure,
256                 Context context, ClusterSupport support, Modifier modifier,
257                 CompleteTable ct)
258     throws DatabaseException {
259         if (DEBUG)
260             System.out.println("ResourceElement.foreachPredicate: 1");
261         int completeRef = ResourceElement.getCompleteObjectRef(table, index);
262         if (0 != completeRef) {
263             if (ClusterTraits.completeReferenceIsMultiple(completeRef)) { // multiple complete type elements
264                 boolean broken = ct.foreachPredicate(completeRef, procedure, context, support, modifier);
265                 if (DEBUG)
266                     System.out.println("ResourceElement.foreachPredicate: multi-complete ci=" + completeRef + " break=" + broken);
267                 if (broken)
268                     return true; // loop broken by procedure
269             } else {
270                 ClusterI.CompleteTypeEnum completeType = ClusterTraits.completeReferenceGetType(completeRef);
271                 if (ClusterI.CompleteTypeEnum.NotComplete != completeType) {
272                     int key = ClusterTraitsBase.getCompleteTypeResourceKeyFromEnum(completeType);
273                     boolean broken = procedure.execute(context, key, 0);
274                     if (DEBUG)
275                         System.out.println("ResourceElement.foreachPredicate: complete rk=" + key + " break=" + broken);
276                     if (broken)
277                         return true; // loop broken by procedure
278                 }
279             }
280         }
281         // If predicate set is in use it will contain also these statements.
282         if (0 != ResourceElement.getPredicateIndex(table, index)) {
283             if (DEBUG)
284                 System.out.println("ResourceElement.foreachPredicate: more than 2 objects");
285                 return false;
286         }
287         int i = STM_OFFSET + index;
288         int p1 = BitUtility.getHighInt(table[i]);
289         if (0 == p1) {
290             if (DEBUG)
291                 System.out.println("ResourceElement.foreachPredicate: empty cache");
292             return false; // loop finished, no statements
293         }
294         int externalRef;
295         if (null == modifier)
296             externalRef = p1;
297         else
298             externalRef = modifier.execute(p1);
299         if (DEBUG)
300             System.out.println("ResourceElement.foreachPredicate: cache1 pk=" + externalRef);
301         if (procedure.execute(context, externalRef, 0))
302                 return true; // loop broken by procedure
303         int p2 = BitUtility.getHighInt(table[++i]);
304         if (0 == p2 || p1 == p2) {
305             if (DEBUG)
306                 System.out.println("ResourceElement.foreachPredicate: cache2 empty");
307                 return false; // loop finished, one statement
308         } if (null == modifier)
309             externalRef = p2;
310         else
311             externalRef = modifier.execute(p2);
312         if (DEBUG)
313             System.out.println("ResourceElement.foreachPredicate: cache2 pk=" + externalRef);
314         if (procedure.execute(context, externalRef, 0))
315                 return true; // loop broken by procedure
316         if (DEBUG)
317             System.out.println("ResourceElement.foreachPredicate: not in cache");
318         return false; // loop finished, two statements
319     }
320
321     public static int getSingleObject(long[] table, int index, ClusterSupport support, final int pRef, final ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, final Modifier modifier)
322     throws DatabaseException {
323         if (DEBUG)
324             System.out.println("ResourceElement.getSingleObject: index=" + index);
325         if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {
326             int completeRef = getCompleteObjectRef(table, index);
327             if (0 == completeRef)
328                 return 0; // no objects for given complete type
329             if (ClusterTraits.completeReferenceIsMultiple(completeRef)) {
330                 // Multiple complete type elements.
331                 if (DEBUG)
332                     System.out.println("ResourceElement.getSingleObject was complete 2");
333                 class ForeachObject
334                 implements ClusterI.ObjectProcedure<Integer> {
335                     @Override
336                     public boolean execute(Integer context, int completeRef)
337                     throws DatabaseException {
338                         ClusterI.CompleteTypeEnum oCompleteType = ClusterTraits.completeReferenceGetType(completeRef);
339                         if (pCompleteType == oCompleteType) { // we have a match
340                             if (context != 0) { // we have an old match
341                                 context = 0; // multiple objects for given type
342                                 return true; // break loop
343                             }
344                             int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);
345                             int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);
346                             if (0 == clusterIndex) {
347                                 context = modifier.execute(resourceIndex);
348                             } else {
349                                 int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);
350                                 context = modifier.execute(externalRef);
351                             }
352                         }
353                         return true; // continue looping
354                     }
355                     
356                 }
357                 ForeachObject t = new ForeachObject();
358                 // CompleteRef is complete object set index.
359                 Integer c = 0;
360                 ct.foreachComplete(completeRef, t, c, support, modifier);
361                 return c;
362             }
363             // one complete type element
364             ClusterI.CompleteTypeEnum completeType = ClusterTraits.completeReferenceGetType(completeRef);
365             if (pCompleteType != completeType)
366                 return 0;
367             int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);
368             int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);
369             if (0 == clusterIndex) {
370                 return modifier.execute(resourceIndex);
371             } else {
372                 int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);
373                 return modifier.execute(externalRef);
374             }
375         }
376         int i = STM_OFFSET + index;
377         int p1 = BitUtility.getHighInt(table[i]);
378         if (0 == p1)
379             return 0; // loop finished, no statements
380         int result = 0;
381         if (pRef == p1) {
382             int o1 = BitUtility.getLowInt(table[i]);
383             result = modifier.execute(o1);
384 //            procedure.execute(graph, new ResourceImpl(null, modifier.execute(o1)));
385 //            int externalRef;
386 //            if (null == modifier)
387 //              externalRef = o1;
388 //            else
389 //              externalRef = modifier.execute(callerThread, o1);
390 //            if (procedure.execute(callerThread, context, externalRef))
391 //              return true; // loop broken by procedure
392         }
393         int p2 = BitUtility.getHighInt(table[++i]);
394         if (0 == p2 || pRef != p2)
395             return result; // loop finished, one statements
396
397         // Many statements
398         if (result != 0) return -1;
399         
400             int o2 = BitUtility.getLowInt(table[i]);
401         return modifier.execute(o2);
402         
403 //        return 0;
404 //        int o2 = BitUtility.getLowInt(table[i]);
405 //        int externalRef;
406 //        if (null == modifier)
407 //              externalRef = o2;
408 //        else
409 //              externalRef = modifier.execute(callerThread, o2);
410 //        if (procedure.execute(callerThread, context, externalRef))
411 //              return true; // loop broken by procedure
412 //        return false; // loop finished
413 //        procedure.execute(graph, new ResourceImpl(null, modifier.execute(o2)));
414     }
415     
416     public static void foreachObject(long[] table, int index,
417                 final ReadGraphImpl graph, final SyncMultiProcedure<Resource> procedure,
418                 final ClusterSupport support, final int pRef, final ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, final Modifier modifier)
419     throws DatabaseException {
420         if (DEBUG)
421             System.out.println("ResourceElement.foreachObject1: index=" + index);
422         if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {
423             int completeRef = getCompleteObjectRef(table, index);
424             if (0 == completeRef) {
425                         procedure.finished(graph);
426 //                      graph.state.dec(0);
427                 return; // no objects for given complete type
428             }
429             if (ClusterTraits.completeReferenceIsMultiple(completeRef)) {
430                 // Multiple complete type statements.
431                 if (DEBUG)
432                     System.out.println("ResourceElement.was complete 2");
433                 class ForeachObject implements ClusterI.ObjectProcedure<Object> {
434                     @Override
435                     public boolean execute(Object context, int completeRef) throws DatabaseException {
436                         ClusterI.CompleteTypeEnum oCompleteType = ClusterTraits.completeReferenceGetType(completeRef);
437                         if (pCompleteType == oCompleteType) {
438                             int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);
439                             int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);
440                             if (0 == clusterIndex) {
441                                 procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(resourceIndex)));
442                             } else {
443                                 int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);
444                                 procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(externalRef)));
445                             }
446                         }
447                         return false; // continue looping
448                     }
449                     
450                 }
451                 ForeachObject t = new ForeachObject();
452                 // CompleteRef is complete object set index.
453                 ct.foreachComplete(completeRef, t, null, support, modifier);
454                 procedure.finished(graph);
455 //                graph.state.dec(0);
456                 return; // loop finished
457             }
458             // one complete type element
459             ClusterI.CompleteTypeEnum completeType = ClusterTraits.completeReferenceGetType(completeRef);
460             if (pCompleteType != completeType) {
461                         procedure.finished(graph);
462 //                      graph.state.dec(0);
463                 return;
464             }
465             int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);
466             int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);
467             if (0 == clusterIndex) {
468                 procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(resourceIndex)));
469             } else {
470                 int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);
471                 procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(externalRef)));
472             }
473                 procedure.finished(graph);
474 //              graph.state.dec(0);
475             return; // loop finished
476         }
477         int i = STM_OFFSET + index;
478         long l = table[i];
479         int p1 = (int) (l >>> 32);
480         if (0 == p1) {
481                 procedure.finished(graph);
482 //              graph.state.dec(0);
483             return; // loop finished, no statements
484         }
485         if (pRef == p1) {
486             int o1 = (int)l;
487             procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o1)));
488 //            int externalRef;
489 //            if (null == modifier)
490 //              externalRef = o1;
491 //            else
492 //              externalRef = modifier.execute(callerThread, o1);
493 //            if (procedure.execute(callerThread, context, externalRef))
494 //              return true; // loop broken by procedure
495         }
496         long l2 = table[++i];
497         int p2 = (int) (l2 >>> 32);
498         if (pRef != p2) {
499                 procedure.finished(graph);
500 //              graph.state.dec(0);
501             return; // loop finished, one statements
502         }
503         int o2 = (int)l2;
504         procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o2)));
505                 procedure.finished(graph);
506 //              graph.state.dec(0);
507     }
508
509     public static <C> void foreachObject(long[] table, int index,
510                 final ReadGraphImpl graph, final C context, final SyncContextMultiProcedure<C, Resource> procedure,
511                 final ClusterSupport support, final int pRef, final ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, final Modifier modifier)
512     throws DatabaseException {
513         if (DEBUG)
514             System.out.println("ResourceElement.foreachObject1: index=" + index);
515         if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {
516             int completeRef = getCompleteObjectRef(table, index);
517             if (0 == completeRef) {
518                         procedure.finished(graph, context);
519 //                      graph.state.dec(0);
520                 return; // no objects for given complete type
521             }
522             if (ClusterTraits.completeReferenceIsMultiple(completeRef)) {
523                 // Multiple complete type statements.
524                 if (DEBUG)
525                     System.out.println("ResourceElement.was complete 2");
526                 class ForeachObject implements ClusterI.ObjectProcedure<Object> {
527                     @Override
528                     public boolean execute(Object _context, int completeRef) throws DatabaseException {
529                         ClusterI.CompleteTypeEnum oCompleteType = ClusterTraits.completeReferenceGetType(completeRef);
530                         if (pCompleteType == oCompleteType) {
531                             int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);
532                             int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);
533                             if (0 == clusterIndex) {
534                                 procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(resourceIndex)));
535                             } else {
536                                 int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);
537                                 procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(externalRef)));
538                             }
539                         }
540                         return false; // continue looping
541                     }
542                     
543                 }
544                 ForeachObject t = new ForeachObject();
545                 // CompleteRef is complete object set index.
546                 ct.foreachComplete(completeRef, t, null, support, modifier);
547                 procedure.finished(graph, context);
548 //                graph.state.dec(0);
549                 return; // loop finished
550             }
551             // one complete type element
552             ClusterI.CompleteTypeEnum completeType = ClusterTraits.completeReferenceGetType(completeRef);
553             if (pCompleteType != completeType) {
554                         procedure.finished(graph, context);
555 //                      graph.state.dec(0);
556                 return;
557             }
558             int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);
559             int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);
560             if (0 == clusterIndex) {
561                 procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(resourceIndex)));
562             } else {
563                 int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);
564                 procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(externalRef)));
565             }
566                 procedure.finished(graph, context);
567 //              graph.state.dec(0);
568             return; // loop finished
569         }
570         int i = STM_OFFSET + index;
571         long l = table[i];
572         int p1 = (int) (l >>> 32);
573         if (0 == p1) {
574                 procedure.finished(graph, context);
575 //              graph.state.dec(0);
576             return; // loop finished, no statements
577         }
578         if (pRef == p1) {
579             int o1 = (int)l;
580             procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o1)));
581 //            int externalRef;
582 //            if (null == modifier)
583 //              externalRef = o1;
584 //            else
585 //              externalRef = modifier.execute(callerThread, o1);
586 //            if (procedure.execute(callerThread, context, externalRef))
587 //              return true; // loop broken by procedure
588         }
589         long l2 = table[++i];
590         int p2 = (int) (l2 >>> 32);
591         if (pRef != p2) {
592                 procedure.finished(graph, context);
593 //              graph.state.dec(0);
594             return; // loop finished, one statements
595         }
596         int o2 = (int)l2;
597         procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o2)));
598                 procedure.finished(graph, context);
599 //              graph.state.dec(0);
600     }
601     
602     public static <Context> boolean foreachObject(long[] table, int index
603                 , ClusterI.ObjectProcedure<Context> procedure
604                 , Context context, ClusterSupport support, Modifier modifier
605                 , final int pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct)
606     throws DatabaseException {
607         if (DEBUG)
608             System.out.println("ResourceElement.foreachObject2: 1 ");
609         if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {
610             int completeRef = getCompleteObjectRef(table, index);
611             if (0 == completeRef) {
612                 if (DEBUG)
613                     System.out.println("ResourceElement.foreachObject2: no complete");
614                 return false; // no objects for given complete type
615             }
616             if (ClusterTraits.completeReferenceIsMultiple(completeRef)) { // multiple complete type elements
617                 if (DEBUG)
618                     System.out.println("ResourceElement.foreachObject2: multi-complete ci=" + completeRef);
619                 return ct.foreachObject(completeRef, procedure, context, support, modifier, pCompleteType);
620             }
621             // one complete type element
622             ClusterI.CompleteTypeEnum completeType = ClusterTraits.completeReferenceGetType(completeRef);
623             if (pCompleteType != completeType) {
624                 if (DEBUG)
625                     System.out.println("ResourceElement.foreachObject2: complete different predicate");
626                 return false;
627             }
628             int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);
629             int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);
630             if (0 == clusterIndex) {
631                 int externalRef;
632                 if (null == modifier)
633                     externalRef = resourceIndex;
634                 else
635                     externalRef = modifier.execute(resourceIndex);
636                 if (DEBUG)
637                     System.out.println("ResourceElement.foreachObject2: complete ok=" + externalRef);
638                 if (procedure.execute(context, externalRef))
639                     return true; // loop broken by procedure
640             } else {
641                 int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);
642                 if (null != modifier)
643                     externalRef = modifier.execute(externalRef);
644                 if (DEBUG)
645                     System.out.println("ResourceElement.foreachObject2: complete ok=" + externalRef);
646                 if (procedure.execute(context, externalRef))
647                     return true; // loop broken by procedure
648             }
649             return false; // loop finished
650         }
651         int i = STM_OFFSET + index;
652         int p1 = BitUtility.getHighInt(table[i]);
653         if (0 == p1) {
654             if (DEBUG)
655                 System.out.println("ResourceElement.foreachObject2: empty cache=");
656             return false; // loop finished, no statements
657         }
658         if (pRef == p1) {
659             int o1 = BitUtility.getLowInt(table[i]);
660             int externalRef;
661             if (null == modifier)
662                 externalRef = o1;
663             else
664                 externalRef = modifier.execute(o1);
665             if (DEBUG)
666                 System.out.println("ResourceElement.foreachObject2: cache1 ok=" + externalRef);
667             if (procedure.execute(context, externalRef))
668                 return true; // loop broken by procedure
669         }
670         int p2 = BitUtility.getHighInt(table[++i]);
671         if (0 == p2 || pRef != p2) {
672             if (DEBUG)
673                 System.out.println("ResourceElement.foreachObject2: not in cache1");
674             return false; // loop finished, one statements
675         }
676         int o2 = BitUtility.getLowInt(table[i]);
677         int externalRef;
678         if (null == modifier)
679                 externalRef = o2;
680         else
681                 externalRef = modifier.execute(o2);
682         if (DEBUG)
683             System.out.println("ResourceElement.foreachObject2: cache2 ok=" + externalRef);
684         return procedure.execute(context, externalRef);
685     }
686     static boolean isEmpty(long[] table, int index) {
687         return getStatementCount(table, index) == 0 && !hasValue(table, index);
688     }
689     static int getStatementCount(long[] table, int index) {
690         int i = STM_OFFSET + index;
691         int p1 = BitUtility.getHighInt(table[i]);
692         int p2 = BitUtility.getLowInt(table[++i]);
693         if (0 == p1)
694             return 0;
695         else if (0 == p2)
696             return 1;
697         int predicateIndex = getPredicateIndex(table, index);
698         if (0 == predicateIndex)
699             return 2;
700         return 3;
701     }
702     private static int makeCompleteObjectRef(int oRef, ClusterI.CompleteTypeEnum completeType) {
703         int ref;
704         if (oRef > 0) {
705             int resourceIndex = oRef; 
706             int clusterIndex = 0;
707             ref = ClusterTraits.completeReferenceMake(completeType.getValue(), resourceIndex, clusterIndex);
708         } else {
709             assert(oRef < 0);
710             assert(!ClusterTraits.isFlat(oRef));
711             ref = (completeType.getValue() <<30) | (oRef & 0x3FFFFFFF);
712         }
713         return ref;
714     }
715     static int addStatement(long[] table, int index, int pRef, int oRef
716             , PredicateTable pt, ObjectTable ot
717             , ClusterI.CompleteTypeEnum completeType, CompleteTable ct)
718     throws DatabaseException {
719         assert (0 != pRef);
720         assert (0 != oRef);
721         if (ClusterI.CompleteTypeEnum.NotComplete != completeType) {
722             int cRef = makeCompleteObjectRef(oRef, completeType);
723             int ctr = getCompleteObjectRef(table, index);
724             if (0 == ctr)
725                 setCompleteObjectRef(table, index, cRef);
726             else {
727                 int nRef;
728                 if (ctr == cRef)
729                     return -1; // old complete
730                 else if (ClusterTraits.completeReferenceIsMultiple(ctr)) {
731                     nRef = ct.addComplete(ctr, cRef);
732                     if (0 == nRef)
733                         return -1; // old complete
734                 } else {
735                     nRef = ct.createCompleteArraySet(ctr, cRef);
736                 }
737                 setCompleteObjectRef(table, index, nRef);
738             }
739             return 0; // added to complete
740         }
741         int i = STM_OFFSET + index;
742         int p1 = BitUtility.getHighInt(table[i]);
743         int o1 = BitUtility.getLowInt(table[i]);
744         if (0 == p1) {
745             table[i] = BitUtility.setLowAndHighInt(table[i], oRef, pRef);
746             return 0; // added to stm cache
747         } else if (p1 == pRef && o1 == oRef)
748             return -1; // same statement
749         int p2 = BitUtility.getHighInt(table[++i]);
750         int o2 = BitUtility.getLowInt(table[i]);
751         if (0 == p2) {
752             table[i] = BitUtility.setLowAndHighInt(table[i], oRef, pRef);
753             return 0; // added to stm cache
754         } else if (p2 == pRef && o2 == oRef)
755             return -1; // same statement
756         int predicateIndex = getPredicateIndex(table, index);
757         if (0 == predicateIndex) {
758             if (p1 == p2) {
759                 int objectIndex = ot.createObjectSet(o1, o2);
760                 assert (0 != objectIndex);
761                 int[] os = new int[1];
762                 os[0] = ClusterTraits.statementIndexMake(objectIndex);
763                 int[] ps = new int[1];
764                 ps[0] = p1;
765                 predicateIndex = pt.createPredicateSet(ps, os);
766             } else {
767                 int[] os = new int[2];
768                 os[0] = o1; 
769                 os[1] = o2;
770                 int[] ps = new int[2];
771                 ps[0] = p1;
772                 ps[1] = p2;
773                 predicateIndex = pt.createPredicateSet(ps, os);
774             }
775             assert (0 != predicateIndex);
776             setPredicateIndex(table, index, predicateIndex);
777         }
778         assert (0 != predicateIndex);
779         return predicateIndex;
780     }
781
782     static boolean removeStatement(long[] table, int index, int pRef, int oRef,
783                 ClusterI.CompleteTypeEnum completeType, CompleteTable ct)
784     throws DatabaseException {
785         assert (0 != pRef);
786         assert (0 != oRef);
787         if (completeType != ClusterI.CompleteTypeEnum.NotComplete) {
788             int completeRef = ResourceElement.getCompleteObjectRef(table, index);
789             if (0 != completeRef) {
790                 ClusterI.CompleteTypeEnum completeType2 = ClusterTraits.completeReferenceGetType(completeRef);
791                 if (completeType == completeType2) {
792                     int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);
793                     int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);
794                     if (0 == clusterIndex) {
795                         if (oRef == resourceIndex) {
796                             ResourceElement.setCompleteObjectRef(table, index, 0);
797                             return true; // statement removed
798                         }
799                     } else {
800                         int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);
801                         if (oRef == externalRef) {
802                             ResourceElement.setCompleteObjectRef(table, index, 0);
803                             return true; // statement removed
804                         }
805                     }
806                 } else if (completeType2 == ClusterI.CompleteTypeEnum.NotComplete) { // multiple complete type references 
807                     int cRef = makeCompleteObjectRef(oRef, completeType);
808                     int oldSize = ct.getCompleteSetSize(completeRef);
809                     int newSize = ct.removeComplete(completeRef, cRef);
810                     if (oldSize == newSize)
811                         return false; // not removed
812                     else if (newSize == 1) {
813                         cRef = ct.removeLast(completeRef);
814                         ResourceElement.setCompleteObjectRef(table, index, cRef);
815                     }
816                     return true; 
817                 }
818             }
819         }
820         int i = STM_OFFSET + index;
821         int p1 = BitUtility.getHighInt(table[i]);
822         int o1 = BitUtility.getLowInt(table[i]);
823         if (0 == p1)
824             return false; // no statements cached
825         else if (p1 == pRef && o1 == oRef) {
826             table[i] = table[i + 1];
827             // BitUtility.setLowAndHighInt(table[i], 0, 0); optimized away
828             table[i + 1] = 0;
829             return true; // statement removed
830         }
831         int p2 = BitUtility.getHighInt(table[++i]);
832         int o2 = BitUtility.getLowInt(table[i]);
833         if (0 == p2)
834             return false; // no match
835         else if (p2 == pRef && o2 == oRef) {
836             // BitUtility.setLowAndHighInt(table[i], 0, 0); optimized away
837             table[i] = 0;
838             return true; // statement removed
839         }
840         return false;
841     }
842 }
843
844 public final class ResourceTable extends Table<long[]> {
845     public ResourceTable(TableSizeListener sizeListener, int[] header, int headerBase) {
846         super(TableFactory.getLongFactory(), sizeListener, header, headerBase);
847     }
848
849     public ResourceTable(TableSizeListener sizeListener, int[] header, int headerBase, long[] longs) {
850         super(TableFactory.getLongFactory(), sizeListener, header, headerBase, longs);
851     }
852
853     public int getUsedSize() {
854         return getTableCount();
855     }
856
857     public short createResource() {
858         final int INDEX = getTableCount();
859         final int SIZE = ResourceElement.getSizeOf();
860         int resourceIndex = createNewElement(SIZE);
861         assert (0 != resourceIndex);
862         final int REAL_INDEX = checkIndexAndGetRealIndex(resourceIndex, SIZE);
863         ResourceElement.construct(getTable(), REAL_INDEX);
864         incResourceCount();
865         return (short)(INDEX + ZERO_SHIFT);
866     }
867
868     void createResource(int resourceIndex) {
869         final int tableCount = getTableCount();
870         if (resourceIndex <= tableCount) { // old index
871             int realIndex = checkIndexAndGetRealIndex(resourceIndex);
872             if (ResourceElement.isEmpty(getTable(), realIndex))
873                 return;
874         } if (resourceIndex == tableCount+1) {
875             createResource();
876             return;
877         }
878         throw new InternalError("Trying to create resource with illegal index=" + resourceIndex);
879     }
880
881 //    void deleteResource(int resourceIndex) {
882 //        int realIndex = checkIndexAndGetRealIndex(resourceIndex);
883 //        ResourceElement.destruct(getTable(), realIndex);
884 //        decResourceCount();
885 //    }
886
887     public int getCompleteObjectRef(int resourceIndex) {
888         int realIndex = checkIndexAndGetRealIndex(resourceIndex);
889         return ResourceElement.getCompleteObjectRef(getTable(), realIndex);
890     }
891     
892     public int getPredicateIndex(int resourceIndex) {
893         int i = (resourceIndex<<2) - 3 + offset;
894         return (int)table[i];
895     }
896
897     public void setPredicateIndex(int resourceIndex, int predicateIndex) {
898         int realIndex = checkIndexAndGetRealIndex(resourceIndex);
899         ResourceElement.setPredicateIndex(getTable(), realIndex, predicateIndex);
900     }
901
902     public byte[] getValue(ValueTable valueTable, int resourceIndex)
903     throws DatabaseException {
904         int realIndex = checkIndexAndGetRealIndex(resourceIndex);
905         return ResourceElement.getValue(valueTable, getTable(), realIndex);
906     }
907
908 //KRAA:
909 //    int getString(ValueTable valueTable, int resourceIndex, char[] chars)
910 //    throws DatabaseException {
911 //        //int realIndex = checkIndexAndGetRealIndex(resourceIndex);
912 //        return ResourceElement.getString(valueTable, getTable(), 4 * resourceIndex - 3 + offset, chars);
913 //    }
914
915     public boolean hasValue(int resourceIndex) {
916         int realIndex = checkIndexAndGetRealIndex(resourceIndex);
917         return ResourceElement.hasValue(getTable(), realIndex);
918     }
919
920 //    boolean hasValue(ValueTable valueTable, int resourceIndex, byte[] value) {
921 //        int realIndex = checkIndexAndGetRealIndex(resourceIndex);
922 //        return ResourceElement.hasValue(valueTable, getTable(), realIndex, value);
923 //    }
924
925     public boolean removeValue(ValueTable valueTable, int resourceIndex) {
926         int realIndex = checkIndexAndGetRealIndex(resourceIndex);
927         boolean ret = ResourceElement.removeValue(valueTable, getTable(), realIndex);
928 //        if (ret && !ResourceElement.isUsed(getTable(), realIndex))
929 //            decResourceCount();
930         return ret;
931     }
932
933     public void setValue(ValueTable valueTable, int resourceIndex, byte[] value, int length) {
934         int realIndex = checkIndexAndGetRealIndex(resourceIndex);
935         ResourceElement.setValue(valueTable, getTable(), realIndex, value, length);
936     }
937
938     public boolean isValueEx(ValueTable valueTable, int resourceIndex) {
939         int realIndex = checkIndexAndGetRealIndex(resourceIndex);
940         return ResourceElement.isValueEx(valueTable, getTable(), realIndex);
941     }
942
943     public void setValueEx(ValueTable valueTable, int resourceIndex) {
944         int realIndex = checkIndexAndGetRealIndex(resourceIndex);
945         ResourceElement.setValueEx(valueTable, getTable(), realIndex);
946     }
947
948     static final int RESOURCE_COUNT_INDEX = 0;
949     static final int FOREIGN_COUNT_INDEX = 1; // Reserved by server.
950     static final int CLUSTER_STATUS_INDEX = 2;
951
952     int incResourceCount() {
953         int count = getExtra(RESOURCE_COUNT_INDEX) + 1;
954         setExtra(RESOURCE_COUNT_INDEX, count);
955         return count;
956     }
957
958 //    int decResourceCount() {
959 //        int count = getExtra(RESOURCE_COUNT_INDEX) - 1;
960 //        setExtra(RESOURCE_COUNT_INDEX, count);
961 //        return count;
962 //    }
963
964     public int getResourceCount() {
965         return getExtra(RESOURCE_COUNT_INDEX);
966     }
967     public int getClusterStatus() {
968         return getExtra(CLUSTER_STATUS_INDEX);
969     }
970     public void setClusterStatus(int value) {
971         setExtra(CLUSTER_STATUS_INDEX, value);
972     }
973     void analyse() {
974
975         final int tsize = getTableSize();
976         final int esize = ResourceElement.getSizeOf();
977         long[] table = getTable();
978         for (int i = getTableBase(); i < getTableBase() + tsize; i += esize) {
979                 if (ResourceElement.isUsed(getTable(), i)) {
980                         System.out.println("  -" + Long.toHexString(table[i]) + " " + Long.toHexString(table[i+1]) + " " + Long.toHexString(table[i+2]) + " " + Long.toHexString(table[i+3]));
981                 }
982         }
983
984     }
985     
986     public <Context> boolean foreachResource(ClusterI.ObjectProcedure<Context> procedure, Context context,
987             ClusterSupport support, Modifier modifier) throws DatabaseException {
988         final int tsize = getTableSize();
989 //        final int rsize = getResourceCount();
990         final int esize = ResourceElement.getSizeOf();
991         //int count = 0;
992         int key = ZERO_SHIFT;
993         for (int i = getTableBase(); i < getTableBase() + tsize; i += esize, ++key) {
994             if (ResourceElement.isUsed(getTable(), i)) {
995                 int ref;
996                 if (null == modifier)
997                         ref = key;
998                 else
999                         ref = modifier.execute(key);
1000                 if (procedure.execute(context, ref))
1001                     return true; // loop was broken by procedure
1002 //                if (rsize == ++count)
1003 //                      return false; // loop finished
1004             }
1005         }
1006         //assert(rsize == count);
1007         return false; // loop finished
1008     }
1009
1010     public <Context> boolean foreachPredicate(int resourceIndex
1011                 , ClusterI.PredicateProcedure<Context> procedure, Context context
1012                 , ClusterSupport support, Modifier modifier, CompleteTable ct)
1013     throws DatabaseException {
1014         int realIndex = checkIndexAndGetRealIndex(resourceIndex);
1015         return ResourceElement.foreachPredicate(getTable(), realIndex
1016                         , procedure, context, support, modifier, ct);
1017     }
1018
1019     public int getSingleObject(int resourceIndex, ClusterSupport support, int pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, Modifier modifier) throws DatabaseException {
1020 //        return ResourceElement.getSingleObject(table, realIndex, support, pRef, pCompleteType, ct, modifier);
1021         return ResourceElement.getSingleObject(table, 4 * resourceIndex - 3 + offset, support, pRef, pCompleteType, ct, modifier);
1022     }
1023
1024     public void foreachObject(int resourceIndex, ReadGraphImpl graph,
1025                 SyncMultiProcedure<Resource> procedure, ClusterSupport support, int pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, Modifier modifier) throws DatabaseException {
1026         int realIndex = checkIndexAndGetRealIndex(resourceIndex);
1027         ResourceElement.foreachObject(table, realIndex, graph, procedure, support,
1028                         pRef, pCompleteType, ct, modifier);
1029     }
1030
1031     public <C> void foreachObject(int resourceIndex, ReadGraphImpl graph, C context,
1032                 SyncContextMultiProcedure<C, Resource> procedure, ClusterSupport support, int pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, Modifier modifier) throws DatabaseException {
1033         int realIndex = checkIndexAndGetRealIndex(resourceIndex);
1034         ResourceElement.foreachObject(table, realIndex, graph, context, procedure, support,
1035                         pRef, pCompleteType, ct, modifier);
1036     }
1037     
1038     public <Context> boolean foreachObject(int resourceIndex
1039                 , ClusterI.ObjectProcedure<Context> procedure, Context context
1040                 , ClusterSupport support, Modifier modifier,
1041                 int pRef, ClusterI.CompleteTypeEnum completeType, CompleteTable ct)
1042     throws DatabaseException {
1043         int realIndex = checkIndexAndGetRealIndex(resourceIndex);
1044         return ResourceElement.foreachObject(table, realIndex
1045                         , procedure, context, support, modifier
1046                         , pRef, completeType, ct);
1047     }
1048     public int addStatement(int resourceIndex, int pRef, int oRef, PredicateTable pt, ObjectTable ot
1049             , ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct)
1050             throws DatabaseException {
1051         int realIndex = checkIndexAndGetRealIndex(resourceIndex);
1052         return ResourceElement.addStatement(getTable(), realIndex, pRef, oRef, pt, ot, pCompleteType, ct);
1053     }
1054
1055     public boolean removeStatementFromCache(int resourceIndex, int pRef, int oRef,
1056                 ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct)
1057     throws DatabaseException {
1058         int realIndex = checkIndexAndGetRealIndex(resourceIndex);
1059         boolean ret = ResourceElement.removeStatement(getTable(), realIndex, pRef, oRef, pCompleteType, ct);
1060 //        if (ret && !ResourceElement.isUsed(getTable(), realIndex))
1061 //            decResourceCount();
1062         return ret;
1063     }
1064     
1065     public void removeStatement(int resourceIndex, int pRef, int oRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct,
1066             PredicateTable pt, ObjectTable ot, ClusterBase cluster, ClusterSupport support)
1067             throws DatabaseException {
1068         int realIndex = checkIndexAndGetRealIndex(resourceIndex);
1069         boolean removed = ResourceElement.removeStatement(getTable(), realIndex,
1070                 pRef, oRef, pCompleteType, ct);
1071         if (!removed)
1072             return;
1073         int predicateIndex = ResourceElement.getPredicateIndex(getTable(), realIndex);
1074         if (0 == predicateIndex) {
1075 //            if (!ResourceElement.isUsed(getTable(), realIndex))
1076 //                decResourceCount();
1077             return;
1078         }
1079         GetStatements gs = new GetStatements(ot);
1080         pt.foreachPredicate(predicateIndex, gs, null, null, null);
1081         ArrayList<Statement> stms = gs.getStatements();
1082
1083         final int SIZE = stms.size();
1084         if (SIZE < 3) {
1085             for (int i = 0; i < SIZE; ++i) {
1086                 Statement stm = stms.get(i);
1087                 PredicateTable.Status ret = pt.removePredicate(predicateIndex,
1088                         stm.pRef, stm.oIndex, ot);
1089                 if (ret == Status.NothingRemoved)
1090                     throw new DatabaseException("Internal error during statement cache fix (2).");
1091                 int predicateKey = cluster.makeResourceKey(stm.pRef);
1092                 int completeTypeInt = ClusterTraitsBase.getCompleteTypeIntFromResourceKey(predicateKey);
1093                 ClusterI.CompleteTypeEnum completeType = CompleteTypeEnum.make(completeTypeInt);
1094                 int pi = ResourceElement.addStatement(getTable(), realIndex, stm.pRef, stm.oIndex,
1095                         pt, ot, completeType, ct);
1096                 assert(0 >= pi);
1097             }
1098             assert(0 == pt.getPredicateSetSize(predicateIndex));
1099             ResourceElement.setPredicateIndex(getTable(), realIndex, 0);
1100         } else {
1101             for (int i = 0; i < SIZE; ++i) {
1102                 Statement stm = stms.get(i);
1103                 int predicateKey = cluster.makeResourceKey(stm.pRef);
1104                 int completeTypeInt = ClusterTraitsBase.getCompleteTypeIntFromResourceKey(predicateKey);
1105                 ClusterI.CompleteTypeEnum completeType = CompleteTypeEnum.make(completeTypeInt);
1106                 int pIndex = ResourceElement.addStatement(getTable(), realIndex,
1107                         stm.pRef, stm.oIndex, pt, ot, completeType, ct);
1108                 if (pIndex > 0)
1109                     return; // cache fixed and full, p and o sets in use
1110             }
1111             throw new DatabaseException("Internal error during statement cache fix (3).");
1112         }
1113 //        if (!ResourceElement.isUsed(getTable(), realIndex))
1114 //            decResourceCount();
1115     }
1116
1117     //(i-1)*4+1 + 4
1118     private int checkIndexAndGetRealIndex(final int INDEX) {
1119         assert(INDEX > 0);
1120         assert(INDEX <= getTableCount());
1121 //        final int TABLE_INDEX = (INDEX - ZERO_SHIFT) * ResourceElement.getSizeOf() + ZERO_SHIFT;
1122 //        final int TABLE_INDEX = (INDEX - ZERO_SHIFT) * ResourceElement.getSizeOf() + ZERO_SHIFT;
1123 //        return checkIndexAndGetRealIndex(TABLE_INDEX, ResourceElement.getSizeOf());
1124         return 4 * INDEX - 3 + offset;
1125     }
1126         public void check(ClusterBase cluster)
1127         throws DatabaseException {
1128 //        int count = 0;
1129             cluster.checkValueInit();
1130         long[] table = getTable();
1131         int ps = getHeader().getOffset() + ZERO_SHIFT;
1132         final int TABLE_SIZE = getTableSize();
1133         int pe = ps + TABLE_SIZE;
1134         for (int p=ps; p<pe; p+=ResourceElement.getSizeOf()) {
1135                 if (!ResourceElement.isUsed(table, p))
1136                         continue;
1137                 int cr = ResourceElement.getCompleteObjectRef(table, p);
1138                 if (0 != cr) {
1139                         if (ClusterTraits.completeReferenceIsMultiple(cr))
1140                                 cluster.checkCompleteSetReference(cr);
1141                         else {
1142                         int fi = ClusterTraits.completeReferenceGetForeignIndex(cr);
1143                         int ri = ClusterTraits.completeReferenceGetResourceIndex(cr);
1144                         if (0 != fi)
1145                                 cluster.checkForeingIndex(fi);
1146                         else if (ri < 1 || ri > TABLE_SIZE)
1147                                 throw new ValidationException("Illegal resource index=" + ri);
1148                         }
1149                 }
1150                 int pi = ResourceElement.getPredicateIndex(table, p);
1151                 if (0 != pi) {
1152                     cluster.checkPredicateIndex(pi);
1153                 }
1154                 ResourceElement.ValueData vd = new ResourceElement.ValueData();
1155                 ResourceElement.getValueCapacityAndIndex(vd, table, p);
1156                 cluster.checkValue(vd.capacity, vd.index);
1157         }
1158         cluster.checkValueFini();
1159         }
1160
1161     @Override
1162     public <Context> boolean foreach(int setIndex, Procedure procedure, Context context,
1163             ClusterSupport support, Modifier modifier) throws DatabaseException {
1164         throw new UnsupportedOperationException();
1165     }
1166 }
1167
1168 class Statement {
1169     Statement(int pRef, int oIndex) {
1170         this.pRef = pRef;
1171         this.oIndex = oIndex;
1172     }
1173     final int pRef;
1174     final int oIndex;
1175 }
1176
1177 class CalculateStatements
1178 implements ClusterI.PredicateProcedure<CalculateStatements> {
1179     private ObjectTable         ot;
1180     private final int           sRef;
1181
1182     CalculateStatements(int sRef, ObjectTable ot) {
1183         this.sRef = sRef;
1184         this.ot = ot;
1185     }
1186
1187     @Override
1188     public boolean execute(final CalculateStatements context
1189             , final int pKey, int oIndex) {
1190         if (ClusterTraits.statementIndexIsDirect(oIndex))
1191             return false; // osize = 1
1192         try {
1193             oIndex = ClusterTraits.statementIndexGet(oIndex);
1194         } catch (DatabaseException e) {
1195             Logger.getDefault().logError("Missing object set for s="
1196                     + sRef + " p=" + pKey, null);
1197             return false; // continue looping
1198         }
1199         int osize = ot.getObjectSetSize(oIndex);
1200         if (osize == 3 || osize > 9)
1201             System.out.println("Resource " + sRef + " predicate " + pKey + " has "
1202                     + osize + " objects.");
1203         return true; // break loop
1204     }
1205 }
1206
1207 class GetStatements implements PredicateProcedure<Object>, ObjectProcedure<Integer> {
1208     private ObjectTable         ot;
1209     private final ArrayList<Statement> stms = new ArrayList<Statement>(); 
1210     GetStatements(ObjectTable ot) {
1211         this.ot = ot;
1212     }
1213     ArrayList<Statement> getStatements() {
1214         return stms;
1215     }
1216     @Override
1217     public boolean execute(Object context, int pRef, int oIndex) {
1218         try {
1219             ot.foreachObject(oIndex, this, pRef, null, null);
1220         } catch (DatabaseException e) {
1221             e.printStackTrace();
1222             return false; // continue looping
1223         }
1224         if (stms.size() > 2)
1225             return true; // break loop
1226         return false; // continue looping
1227     }
1228
1229     @Override
1230     public boolean execute(Integer pRef, int oRef) {
1231         stms.add(new Statement(pRef, oRef));
1232         if (stms.size() > 2)
1233             return true; // break loop
1234         return false; // continue looping
1235     }
1236     
1237 }