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