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