]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.db.procore/src/org/simantics/db/procore/cluster/ResourceElementSmall.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.db.procore / src / org / simantics / db / procore / cluster / ResourceElementSmall.java
diff --git a/bundles/org.simantics.db.procore/src/org/simantics/db/procore/cluster/ResourceElementSmall.java b/bundles/org.simantics.db.procore/src/org/simantics/db/procore/cluster/ResourceElementSmall.java
new file mode 100644 (file)
index 0000000..71c4c53
--- /dev/null
@@ -0,0 +1,754 @@
+package org.simantics.db.procore.cluster;\r
+\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.exception.ExternalValueException;\r
+import org.simantics.db.impl.ClusterI;\r
+import org.simantics.db.impl.ClusterSupport;\r
+import org.simantics.db.impl.ClusterTraitsBase;\r
+import org.simantics.db.impl.Modifier;\r
+import org.simantics.db.impl.ResourceImpl;\r
+import org.simantics.db.impl.graph.ReadGraphImpl;\r
+import org.simantics.db.procedure.AsyncContextMultiProcedure;\r
+import org.simantics.db.procedure.AsyncMultiProcedure;\r
+\r
+\r
+public final class ResourceElementSmall {\r
+    private static final boolean DEBUG = ClusterImpl.DEBUG;\r
+    // Descriptor = type & complete object reference & value index & predicate index. \r
+    private static final int DESCRIPTOR_OFFSET = 0; // descriptor\r
+    private static final int STM_OFFSET        = 1; // two statements\r
+    private static final int SIZE_OF           = 2;\r
+\r
+    static void construct(long[] table, int index) {\r
+        int i = DESCRIPTOR_OFFSET + index;\r
+        table[i++] = 0; // descriptor\r
+        table[i++] = 0; // stm1 & 2\r
+    }\r
+\r
+    static void destruct(long[] table, int index) {\r
+        int i = DESCRIPTOR_OFFSET + index;\r
+        table[i++] = 0; // descriptor\r
+        table[i++] = 0; // stm1 & 2\r
+    }\r
+\r
+    static boolean isUsed(long[] table, int index) {\r
+        int i = DESCRIPTOR_OFFSET + index;\r
+        if (table[i++] != 0)\r
+            return true;\r
+        if (table[i++] != 0)\r
+            return true;\r
+        return false;\r
+    }\r
+\r
+    static int getSizeOf() {\r
+        return SIZE_OF;\r
+    }\r
+\r
+    static ClusterI.CompleteTypeEnum getCompleteType(long[] table, int index) {\r
+        int i = DESCRIPTOR_OFFSET + index;\r
+        byte bits = (byte)BitUtility.getMiddle(table[i], 62, 2);\r
+        return ClusterI.CompleteTypeEnum.make(bits);\r
+    }\r
+\r
+    static void setCompleteType(long[] table, int index, byte data) {\r
+        int i = DESCRIPTOR_OFFSET + index;\r
+        table[i] = BitUtility.setMiddle(table[i], 62, 2, data);\r
+    }\r
+\r
+    static short getCompleteObjectRef(long[] table, int index) {\r
+        int i = DESCRIPTOR_OFFSET + index;\r
+        return (short)BitUtility.getMiddle(table[i], 46, 16);\r
+    }\r
+\r
+    static void setCompleteObjectRef(long[] table, int index, int ref) {\r
+        if (ref > (1<<16)-1)\r
+            throw new IllegalArgumentException();\r
+        int i = DESCRIPTOR_OFFSET + index;\r
+        table[i] = BitUtility.setMiddle(table[i], 46, 16, ref);\r
+    }\r
+\r
+    static boolean completeHasMultiple(long[] table, int index) {\r
+        int i = DESCRIPTOR_OFFSET + index;\r
+        int completeRefAndType= BitUtility.getMiddle(table[i], 46, 18); \r
+        boolean complete = (completeRefAndType >>> 16) != 0;\r
+        return !complete && (completeRefAndType != 0);\r
+    }\r
+\r
+    static boolean completeIsFirstStatement(long[] table, int index) {\r
+        int i = DESCRIPTOR_OFFSET + index;\r
+        int completeRefAndType = BitUtility.getMiddle(table[i], 46, 18); \r
+        return completeRefAndType == 0;\r
+    }\r
+    \r
+    static boolean completeIsSameStatement(long[] table, int index, int refAndType) {\r
+        int i = DESCRIPTOR_OFFSET + index;\r
+        int completeRefAndType = BitUtility.getMiddle(table[i], 46, 18); \r
+        return completeRefAndType == refAndType;\r
+    }\r
+    \r
+    static int completeGetRefAndType(long[] table, int index) {\r
+        int i = DESCRIPTOR_OFFSET + index;\r
+        return BitUtility.getMiddle(table[i], 46, 18);\r
+    }\r
+    \r
+    static void completeSetRefAndType(long[] table, int index, int refAndType) {\r
+        int i = DESCRIPTOR_OFFSET + index;\r
+        table[i] = BitUtility.setMiddle(table[i], 46, 18, refAndType); \r
+    }\r
+    \r
+    static int completeMakeObjectRefAndType(short oRef, ClusterI.CompleteTypeEnum completeType) {\r
+        return oRef & (1<<16)-1 | completeType.getValue()<<16;\r
+    }\r
+    \r
+    static short completeGetObjectSetIndex(long[] table, int index) {\r
+        int i = DESCRIPTOR_OFFSET + index;\r
+        return (short)BitUtility.getMiddle(table[i], 46, 16);\r
+    }\r
+    \r
+    static int completeGetStatementCountApproximation(long[] table, int index) {\r
+        int i = DESCRIPTOR_OFFSET + index;\r
+        int cType = BitUtility.getMiddle(table[i], 62, 2);\r
+        if (cType != 0)\r
+            return 1;\r
+        int cRef = BitUtility.getMiddle(table[i], 46, 16);\r
+        if (cRef != 0)\r
+            return 2; // Can be bigger, hence the approximation. \r
+        return 0;\r
+    }\r
+    \r
+    static int getValueIndex(long[] table, int index) {\r
+        int i = DESCRIPTOR_OFFSET + index;\r
+        int valueIndex = BitUtility.getMiddle(table[i], 24, 22);\r
+        return valueIndex;\r
+    }\r
+\r
+    static void setValueIndex(long[] table, int index, int valueIndex) {\r
+        int i = DESCRIPTOR_OFFSET + index;\r
+        table[i] = BitUtility.setMiddle(table[i], 24, 22, valueIndex);\r
+    }\r
+\r
+    static int getPredicateIndex(long[] table, int index) {\r
+        int i = DESCRIPTOR_OFFSET + index;\r
+        int predicateIndex = BitUtility.getMiddle(table[i], 0, 24);\r
+        return predicateIndex;\r
+    }\r
+\r
+    static void setPredicateIndex(long[] table, int index, int predicateIndex) {\r
+        int i = DESCRIPTOR_OFFSET + index;\r
+        table[i] = BitUtility.setMiddle(table[i], 0, 24, predicateIndex);\r
+    }\r
+\r
+    static short getStm1Predicate(long[] table, int index) {\r
+        int i = STM_OFFSET + index;\r
+        short predicateIndex = BitUtility.getLowShort(table[i]);\r
+        return predicateIndex;\r
+    }\r
+\r
+    static void setStm1Predicate(long[] table, int index, short predicateIndex) {\r
+        int i = STM_OFFSET + index;\r
+        table[i] = BitUtility.setLowShort(table[i], predicateIndex);\r
+    }\r
+    \r
+    static short getStm1Object(long[] table, int index) {\r
+        int i = STM_OFFSET + index;\r
+        short objectIndex = (short)BitUtility.getMiddle(table[i], 16, 16);\r
+        return objectIndex;\r
+    }\r
+\r
+    static void setStm1Object(long[] table, int index, short objectIndex) {\r
+        int i = STM_OFFSET + index;\r
+        table[i] = BitUtility.setMiddle(table[i], 16, 16, objectIndex);\r
+    }\r
+    \r
+    static short getStm2Predicate(long[] table, int index) {\r
+        int i = STM_OFFSET + index;\r
+        short predicateIndex = (short)BitUtility.getMiddle(table[i], 32, 16);\r
+        return predicateIndex;\r
+    }\r
+\r
+    static void setStm2Predicate(long[] table, int index, short predicateIndex) {\r
+        int i = STM_OFFSET + index;\r
+        table[i] = BitUtility.setMiddle(table[i], 32, 16, predicateIndex);\r
+    }\r
+\r
+    static short getStm2Object(long[] table, int index) {\r
+        int i = STM_OFFSET + index;\r
+        short objectIndex = (short)BitUtility.getMiddle(table[i], 48, 16);\r
+        return objectIndex;\r
+    }\r
+\r
+    static void setStm2Object(long[] table, int index, short objectIndex) {\r
+        int i = STM_OFFSET + index;\r
+        table[i] = BitUtility.setMiddle(table[i], 48, 16, objectIndex);\r
+    }\r
+\r
+    public static byte[] getValue(ValueTableSmall valueTable, long[] table, int index)\r
+    throws DatabaseException {\r
+        int valueIndex = getValueIndex(table, index);\r
+        if (0 == valueIndex)\r
+            return null; // no value\r
+        else if (ClusterTraitsSmall.VALUE_INDEX_EX == valueIndex)\r
+            throw new ExternalValueException("Value stored externally. index=" + index);\r
+        return valueTable.getValue(valueIndex);\r
+    }\r
+//KRAA:\r
+//    static char[] getString(ValueTableSmall valueTable, long[] table, int index) {\r
+//        int valueIndex = getValueIndex(table, index);\r
+//        if (0 == valueIndex)\r
+//            return null; // no value\r
+////        else if (ClusterTraitsSmall.VALUE_INDEX_MAX == valueIndex)\r
+////            throw new Error("Not implemented! //KRAA:");\r
+//        return valueTable.getString(valueIndex);\r
+//    }\r
+\r
+    static boolean hasValue(long[] table, int index) {\r
+        int valueIndex = getValueIndex(table, index);\r
+        return 0 != valueIndex;\r
+    }\r
+\r
+//    static boolean hasValue(ValueTable valueTable, long[] table, int index, byte[] value) {\r
+//        int valueIndex = getValueIndex(table, index);\r
+//        if (0 == valueIndex)\r
+//            return false;\r
+//        return valueTable.isEqual(valueIndex, value, 0, value.length);\r
+//    }\r
+\r
+    static boolean removeValue(ValueTableSmall valueTable, long[] table, int index) {\r
+        int valueIndex = getValueIndex(table, index);\r
+        if (0 == valueIndex)\r
+            return false; // not removed\r
+        else if (ClusterTraitsSmall.VALUE_INDEX_EX != valueIndex)\r
+            valueTable.removeValue(valueIndex);\r
+        setValueIndex(table, index, 0);\r
+        return true;\r
+    }\r
+\r
+    public static void setValue(ValueTableSmall valueTable, long[] table, int index, byte[] value, int length)\r
+    throws OutOfSpaceException {\r
+        int oldIndex = getValueIndex(table, index);\r
+        if (ClusterTraitsSmall.VALUE_INDEX_EX == oldIndex)\r
+            oldIndex = 0;\r
+        if (length > ClusterTraitsSmall.VALUE_SIZE_MAX)\r
+            throw new OutOfSpaceException("Out of space for value. size=" + length);\r
+        int newIndex = valueTable.setValue(oldIndex, value, 0, length);\r
+        if (newIndex != oldIndex) {\r
+            if (newIndex > ClusterTraitsSmall.VALUE_INDEX_MAX) {\r
+               setValueIndex(table, index, 0);\r
+                throw new OutOfSpaceException("Out of space for values. index=" + newIndex);\r
+            }\r
+            setValueIndex(table, index, newIndex);\r
+        }\r
+        return;\r
+    }\r
+\r
+    public static boolean isValueEx(ValueTableSmall valueTable, long[] table, int index) {\r
+        int vIndex = getValueIndex(table, index);\r
+        if (ClusterTraitsSmall.VALUE_INDEX_EX == vIndex)\r
+            return true;\r
+        else\r
+            return false;\r
+    }\r
+\r
+    public static void setValueEx(ValueTableSmall valueTable, long[] table, int index) {\r
+        setValueIndex(table, index, ClusterTraitsSmall.VALUE_INDEX_EX);\r
+    }\r
+\r
+    public static <Context> boolean foreachPredicate(long[] table, int index,\r
+            ClusterI.PredicateProcedure<Context> procedure,\r
+            Context context, ClusterSupport support, Modifier modifier,\r
+            CompleteTable ct)\r
+    throws DatabaseException {\r
+        if (DEBUG)\r
+            System.out.println("ResourceElement.foreachPredicate: 1");\r
+        int completeRef = ResourceElementSmall.getCompleteObjectRef(table, index);\r
+        if (0 != completeRef) {\r
+            if (ResourceElementSmall.completeHasMultiple(table, index)) { // multiple complete objects\r
+                // CompleteRef is a complete object set index.\r
+                boolean broken = ct.foreachPredicate(completeRef, procedure, context, support, modifier);\r
+                if (DEBUG)\r
+                    System.out.println("ResourceElement.foreachPredicate: multi-complete ci=" + completeRef + " break=" + broken);\r
+                if (broken)\r
+                    return true; // loop broken by procedure\r
+            } else { // We have zero or one complete statement.\r
+                ClusterI.CompleteTypeEnum completeType = ResourceElementSmall.getCompleteType(table, index);\r
+                if (ClusterI.CompleteTypeEnum.NotComplete != completeType) {\r
+                    int key = ClusterTraitsBase.getCompleteTypeResourceKeyFromEnum(completeType);\r
+                    boolean broken = procedure.execute(context, key, 0);\r
+                    if (DEBUG)\r
+                        System.out.println("ResourceElement.foreachPredicate: complete rk=" + key + " break=" + broken);\r
+                    if (broken)\r
+                        return true; // loop broken by procedure\r
+                }\r
+            }\r
+        }\r
+        // If predicate set is in use it will contain also these statements.\r
+        if (0 != ResourceElementSmall.getPredicateIndex(table, index)) {\r
+            if (DEBUG)\r
+                System.out.println("ResourceElement.foreachPredicate: more than 2 objects");\r
+            return false;\r
+        }\r
+        int p1 = getStm1Predicate(table, index);\r
+        if (0 == p1) {\r
+            if (DEBUG)\r
+                System.out.println("ResourceElement.foreachPredicate: empty cache");\r
+            return false; // loop finished, no statements\r
+        }\r
+        int externalRef;\r
+        if (null == modifier)\r
+            externalRef = p1;\r
+        else\r
+            externalRef = modifier.execute(p1);\r
+        if (DEBUG)\r
+            System.out.println("ResourceElement.foreachPredicate: cache1 pk=" + externalRef);\r
+        if (procedure.execute(context, externalRef, 0))\r
+            return true; // loop broken by procedure\r
+        int p2 = getStm2Predicate(table, index);\r
+        if (0 == p2 || p1 == p2) {\r
+            if (DEBUG)\r
+                System.out.println("ResourceElement.foreachPredicate: cache2 empty");\r
+            return false; // loop finished, one predicate\r
+        }\r
+        if (null == modifier)\r
+            externalRef = p2;\r
+        else\r
+            externalRef = modifier.execute(p2);\r
+        if (DEBUG)\r
+            System.out.println("ResourceElement.foreachPredicate: cache2 pk=" + externalRef);\r
+        return procedure.execute(context, externalRef, 0);\r
+    }\r
+\r
+    public static int getSingleObject(long[] table, int index, ClusterSupport support, final short pRef,\r
+            final ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, Modifier modifier)\r
+    throws DatabaseException {\r
+        if (DEBUG)\r
+            System.out.println("ResourceElement.getSingleObject: index=" + index);\r
+        if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {\r
+            int completeRef = getCompleteObjectRef(table, index);\r
+            if (0 == completeRef)\r
+                return 0; // no objects for given complete type\r
+            if (ResourceElementSmall.completeHasMultiple(table, index)) {\r
+                // Multiple complete type statements.\r
+                if (DEBUG)\r
+                    System.out.println("ResourceElement.was complete 2");\r
+                ClusterI.ObjectProcedure<Short> proc = new ClusterI.ObjectProcedure<Short>() {\r
+                    @Override\r
+                    public boolean execute(Short context, int completeRefAndType)\r
+                    throws DatabaseException {\r
+                        ClusterI.CompleteTypeEnum ct = ClusterTraitsSmall.completeRefAndTypeGetType(completeRefAndType);\r
+                        if (ct == pCompleteType) { // we have a match\r
+                            if (context != 0) { // we have an old match\r
+                                context = 0; // multiple objects for given type\r
+                                return true; // break loop\r
+                            }\r
+                            context = ClusterTraitsSmall.completeRefAndTypeGetRef(completeRefAndType);\r
+                        }\r
+                        return true; // continue looping\r
+                    }\r
+                };\r
+                Short objectRef = 0;\r
+                // CompleteRef is complete object set index.\r
+                ct.foreachComplete(completeRef, proc, objectRef, support, modifier);\r
+                return modifier.execute(objectRef);\r
+            } // One complete type statement.\r
+            ClusterI.CompleteTypeEnum rCompleteType = ResourceElementSmall.getCompleteType(table, index);\r
+            if (pCompleteType != rCompleteType)\r
+                return 0; // no objects for given complete type\r
+            // CompleteRef is object resource reference.\r
+            return modifier.execute(completeRef);\r
+        }\r
+        int p1 = getStm1Predicate(table, index);\r
+        if (0 == p1)\r
+            return 0; // loop finished, no statements\r
+        int result = 0;\r
+        if (pRef == p1) {\r
+            short o1 = getStm1Object(table, index);\r
+            result = modifier.execute(o1);\r
+//            procedure.execute(graph, new ResourceImpl(null, modifier.execute(o1)));\r
+//            int externalRef;\r
+//            if (null == modifier)\r
+//                externalRef = o1;\r
+//            else\r
+//                externalRef = modifier.execute(callerThread, o1);\r
+//            if (procedure.execute(callerThread, context, externalRef))\r
+//                return true; // loop broken by procedure\r
+        }\r
+        int p2 = getStm2Predicate(table, index);\r
+        if (0 == p2 || pRef != p2)\r
+            return result; // loop finished, one statements\r
+\r
+        // Many statements\r
+        if (result != 0) return -1;\r
+        \r
+        short o2 = getStm2Object(table, index);\r
+        return modifier.execute(o2);\r
+//        int externalRef;\r
+//        if (null == modifier)\r
+//            externalRef = o2;\r
+//        else\r
+//            externalRef = modifier.execute(callerThread, o2);\r
+//        if (procedure.execute(callerThread, context, externalRef))\r
+//            return true; // loop broken by procedure\r
+//        return false; // loop finished\r
+//        procedure.execute(graph, new ResourceImpl(null, modifier.execute(o2)));\r
+    }\r
+\r
+    public static void foreachObject(long[] table, int index,\r
+            final ReadGraphImpl graph, final AsyncMultiProcedure<Resource> procedure,\r
+            ClusterSupport support, final int pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, final Modifier modifier)\r
+    throws DatabaseException {\r
+        if (DEBUG)\r
+            System.out.println("ResourceElement.foreachObject1: index=" + index);\r
+        if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {\r
+            int completeRef = getCompleteObjectRef(table, index);\r
+            if (0 == completeRef) {\r
+                procedure.finished(graph);\r
+//                graph.state.dec(0);\r
+                return; // no objects for given complete type\r
+            }\r
+            if (ResourceElementSmall.completeHasMultiple(table, index)) {// multiple objects\r
+                ClusterI.ObjectProcedure<Object> proc = new ClusterI.ObjectProcedure<Object>() {\r
+                    @Override\r
+                    public boolean execute(Object _context, int objectRef)\r
+                    throws DatabaseException {\r
+                        procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(objectRef)));\r
+                        return false; // continue looping\r
+                    }\r
+                    \r
+                };\r
+                // CompleteRef is complete object set index.\r
+                ct.foreachComplete(completeRef, proc, null, support, modifier);\r
+            } else { // One complete type element. CompleteRef is resource reference.\r
+                ClusterI.CompleteTypeEnum rCompleteType = ResourceElementSmall.getCompleteType(table, index);\r
+                if (pCompleteType != rCompleteType) {\r
+                    procedure.finished(graph);\r
+//                    graph.state.dec(0);\r
+                    return; // Complete predicate does not match.\r
+                }\r
+                procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(completeRef)));\r
+            }\r
+            procedure.finished(graph);\r
+//            graph.state.dec(0);\r
+            return; // loop finished\r
+        }\r
+        short p1 = getStm1Predicate(table, index);\r
+        if (0 == p1) {\r
+            procedure.finished(graph);\r
+//            graph.state.dec(0);\r
+            return; // loop finished, no statements\r
+        }\r
+        if (pRef == p1) {\r
+            short o1 = getStm1Object(table, index);\r
+            procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o1)));\r
+//            int externalRef;\r
+//            if (null == modifier)\r
+//                externalRef = o1;\r
+//            else\r
+//                externalRef = modifier.execute(callerThread, o1);\r
+//            if (procedure.execute(callerThread, context, externalRef))\r
+//                return true; // loop broken by procedure\r
+        }\r
+        short p2 = getStm2Predicate(table, index);\r
+        if (0 == p2 || pRef != p2) {\r
+            procedure.finished(graph);\r
+//            graph.state.dec(0);\r
+            return; // loop finished, one statements\r
+        }\r
+        int o2 = getStm2Object(table, index);\r
+//        int externalRef;\r
+//        if (null == modifier)\r
+//            externalRef = o2;\r
+//        else\r
+//            externalRef = modifier.execute(callerThread, o2);\r
+//        if (procedure.execute(callerThread, context, externalRef))\r
+//            return true; // loop broken by procedure\r
+//        return false; // loop finished\r
+        procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o2)));\r
+        procedure.finished(graph);\r
+//        graph.state.dec(0);\r
+    }\r
+    \r
+    public static <C> void foreachObject(long[] table, int index,\r
+            final ReadGraphImpl graph, final C context, final AsyncContextMultiProcedure<C, Resource> procedure,\r
+            ClusterSupport support, final int pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, final Modifier modifier)\r
+    throws DatabaseException {\r
+        if (DEBUG)\r
+            System.out.println("ResourceElement.foreachObject1: index=" + index);\r
+        if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {\r
+            int completeRef = getCompleteObjectRef(table, index);\r
+            if (0 == completeRef) {\r
+                procedure.finished(graph);\r
+//                graph.state.dec(0);\r
+                return; // no objects for given complete type\r
+            }\r
+            if (ResourceElementSmall.completeHasMultiple(table, index)) {// multiple objects\r
+                ClusterI.ObjectProcedure<Object> proc = new ClusterI.ObjectProcedure<Object>() {\r
+                    @Override\r
+                    public boolean execute(Object _context, int objectRef)\r
+                    throws DatabaseException {\r
+                        procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(objectRef)));\r
+                        return false; // continue looping\r
+                    }\r
+                    \r
+                };\r
+                // CompleteRef is complete object set index.\r
+                ct.foreachComplete(completeRef, proc, null, support, modifier);\r
+            } else { // One complete type element. CompleteRef is resource reference.\r
+                ClusterI.CompleteTypeEnum rCompleteType = ResourceElementSmall.getCompleteType(table, index);\r
+                if (pCompleteType != rCompleteType) {\r
+                    procedure.finished(graph);\r
+//                    graph.state.dec(0);\r
+                    return; // Complete predicate does not match.\r
+                }\r
+                procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(completeRef)));\r
+            }\r
+            procedure.finished(graph);\r
+//            graph.state.dec(0);\r
+            return; // loop finished\r
+        }\r
+        short p1 = getStm1Predicate(table, index);\r
+        if (0 == p1) {\r
+            procedure.finished(graph);\r
+//            graph.state.dec(0);\r
+            return; // loop finished, no statements\r
+        }\r
+        if (pRef == p1) {\r
+            short o1 = getStm1Object(table, index);\r
+            procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o1)));\r
+//            int externalRef;\r
+//            if (null == modifier)\r
+//                externalRef = o1;\r
+//            else\r
+//                externalRef = modifier.execute(callerThread, o1);\r
+//            if (procedure.execute(callerThread, context, externalRef))\r
+//                return true; // loop broken by procedure\r
+        }\r
+        short p2 = getStm2Predicate(table, index);\r
+        if (0 == p2 || pRef != p2) {\r
+            procedure.finished(graph);\r
+//            graph.state.dec(0);\r
+            return; // loop finished, one statements\r
+        }\r
+        int o2 = getStm2Object(table, index);\r
+//        int externalRef;\r
+//        if (null == modifier)\r
+//            externalRef = o2;\r
+//        else\r
+//            externalRef = modifier.execute(callerThread, o2);\r
+//        if (procedure.execute(callerThread, context, externalRef))\r
+//            return true; // loop broken by procedure\r
+//        return false; // loop finished\r
+        procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o2)));\r
+        procedure.finished(graph);\r
+//        graph.state.dec(0);\r
+    }\r
+\r
+    public static <Context> boolean foreachObject(long[] table, int index\r
+            , ClusterI.ObjectProcedure<Context> procedure\r
+            , Context context, ClusterSupport support, Modifier modifier\r
+            , final short pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct)\r
+    throws DatabaseException {\r
+        if (DEBUG)\r
+            System.out.println("ResourceElementSmall.foreachObject2: 1");\r
+        if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {\r
+            int completeRef = getCompleteObjectRef(table, index);\r
+            if (0 == completeRef) {\r
+                if (DEBUG)\r
+                    System.out.println("ResourceElementSmall.foreachObject2: no complete");\r
+                return false; // no objects for given complete type\r
+            } if (ResourceElementSmall.completeHasMultiple(table, index)) {\r
+                if (DEBUG)\r
+                    System.out.println("ResourceElementSmall.foreachObject2: multi-complete ci=" + completeRef);\r
+                // CompleteRef is complete object set index.\r
+                return ct.foreachObject(completeRef, procedure, context, support, modifier, pCompleteType);\r
+            }\r
+            // One complete type statement at most.\r
+            ClusterI.CompleteTypeEnum completeType = ResourceElementSmall.getCompleteType(table, index);\r
+            if (pCompleteType != completeType) {\r
+                if (DEBUG)\r
+                    System.out.println("ResourceElementSmall.foreachObject2: complete different predicate");\r
+                return false; // Loop finished. No objects for given complete predicate type.\r
+            }\r
+            int externalRef = completeRef;\r
+            if (null != modifier)\r
+                externalRef = modifier.execute(externalRef);\r
+            if (DEBUG)\r
+                System.out.println("ResourceElementSmall.foreachObject2: complete ok=" + externalRef);\r
+            return procedure.execute(context, externalRef);\r
+        }\r
+        int p1 = getStm1Predicate(table, index);\r
+        if (0 == p1) {\r
+            if (DEBUG)\r
+                System.out.println("ResourceElementSmall.foreachObject2: empty cache=");\r
+            return false; // loop finished, no statements\r
+        }\r
+        if (pRef == p1) {\r
+            int o1 = getStm1Object(table, index);\r
+            int externalRef;\r
+            if (null == modifier)\r
+                externalRef = o1;\r
+            else\r
+                externalRef = modifier.execute(o1);\r
+            if (DEBUG)\r
+                System.out.println("ResourceElementSmall.foreachObject2: cache1 ok=" + externalRef);\r
+            if (procedure.execute(context, externalRef))\r
+                return true; // loop broken by procedure\r
+        }\r
+        int p2 = getStm2Predicate(table, index);\r
+        if (0 == p2 || pRef != p2) {\r
+            if (DEBUG)\r
+                System.out.println("ResourceElementSmall.foreachObject2: not in cache1");\r
+            return false; // loop finished, one statements\r
+        }\r
+        int o2 = getStm2Object(table, index);\r
+        int externalRef;\r
+        if (null == modifier)\r
+            externalRef = o2;\r
+        else\r
+            externalRef = modifier.execute(o2);\r
+        if (DEBUG)\r
+            System.out.println("ResourceElementSmall.foreachObject2: cache2 ok=" + externalRef);\r
+        return procedure.execute(context, externalRef);\r
+    }\r
+    static boolean isEmpty(long[] table, int index) {\r
+        return getStatementCountApproximation(table, index) == 0 && !hasValue(table, index);\r
+    }\r
+    static int getStatementCountApproximation(long[] table, int index) {\r
+        int n = ResourceElementSmall.completeGetStatementCountApproximation(table, index);\r
+        short p1 = getStm1Predicate(table, index);\r
+        if (0 == p1)\r
+            return n;\r
+        short p2 = getStm2Predicate(table, index);\r
+        if (0 == p2)\r
+            return n+1;\r
+        int predicateIndex = getPredicateIndex(table, index);\r
+        if (0 == predicateIndex)\r
+            return n + 2;\r
+        return n + 3; // Can be bigger, hence the approximation.\r
+    }\r
+    static int addStatement(long[] table, int index, short pRef, short oRef\r
+            , PredicateTable pt, ObjectTable ot\r
+            , ClusterI.CompleteTypeEnum completeType, CompleteTable ct)\r
+    throws DatabaseException {\r
+        assert (0 != pRef);\r
+        assert (0 != oRef);\r
+        if (ClusterI.CompleteTypeEnum.NotComplete != completeType) { // predicate is complete type\r
+            int coRefAndType = completeMakeObjectRefAndType(oRef, completeType);\r
+            if (completeIsFirstStatement(table, index))\r
+                completeSetRefAndType(table, index, coRefAndType);\r
+            else { // old complete statements exist\r
+                if (completeIsSameStatement(table, index, coRefAndType))\r
+                    return -1; // old complete\r
+                int nRef;\r
+                if (completeHasMultiple(table, index)) { // nth statement\r
+                    int coSetIndex = completeGetObjectSetIndex(table, index) & 0xFFFF;\r
+                    nRef = ct.addComplete(coSetIndex, coRefAndType);\r
+                    if (0 == nRef)\r
+                        return -1; // old complete\r
+                    else if (nRef >= 1<<16) {\r
+                        ct.removeComplete(coSetIndex, coRefAndType);\r
+                        throw new OutOfSpaceException("Out of space for complete objects. index=" + nRef);\r
+                    }\r
+                } else { // second statement\r
+                    int coRefAndTypeOld = ResourceElementSmall.completeGetRefAndType(table, index);\r
+                    nRef = ct.createCompleteArraySet(coRefAndTypeOld, coRefAndType);\r
+                    if (nRef >= 1<<16)\r
+                        throw new OutOfSpaceException("Out of space for complete objects. index=" + nRef);\r
+                    ResourceElementSmall.setCompleteType(table, index, (byte)0);\r
+                }\r
+                setCompleteObjectRef(table, index, nRef);\r
+            }\r
+            return 0; // added to complete\r
+        }\r
+        short p1 = getStm1Predicate(table, index);\r
+        short o1 = getStm1Object(table, index);\r
+        if (0 == p1) {\r
+            setStm1Predicate(table, index, pRef);\r
+            setStm1Object(table, index, oRef);\r
+            return 0; // added to stm cache\r
+        } else if (p1 == pRef && o1 == oRef)\r
+            return -1; // same statement\r
+        short p2 = getStm2Predicate(table, index);\r
+        short o2 = getStm2Object(table, index);\r
+        if (0 == p2) {\r
+            setStm2Predicate(table, index, pRef);\r
+            setStm2Object(table, index, oRef);\r
+            return 0; // added to stm cache\r
+        } else if (p2 == pRef && o2 == oRef)\r
+            return -1; // same statement\r
+        int predicateIndex = getPredicateIndex(table, index);\r
+        if (0 == predicateIndex) {\r
+            if (p1 == p2) {\r
+                int objectIndex = ot.createObjectSet(o1 & 0xFFFF, o2 & 0xFFFF);\r
+                assert (0 != objectIndex);\r
+                int[] os = new int[1];\r
+                os[0] = ClusterTraits.statementIndexMake(objectIndex);\r
+                int[] ps = new int[1];\r
+                ps[0] = p1 & 0xFFFF;\r
+                predicateIndex = pt.createPredicateSet(ps, os);\r
+            } else {\r
+                int[] os = new int[2];\r
+                os[0] = o1 & 0xFFFF; \r
+                os[1] = o2 & 0xFFFF;\r
+                int[] ps = new int[2];\r
+                ps[0] = p1 & 0xFFFF;\r
+                ps[1] = p2 & 0xFFFF;\r
+                predicateIndex = pt.createPredicateSet(ps, os);\r
+            }\r
+            assert (0 != predicateIndex);\r
+            setPredicateIndex(table, index, predicateIndex);\r
+        }\r
+        assert (0 != predicateIndex);\r
+        return predicateIndex;\r
+    }\r
+\r
+    static boolean removeStatement(long[] table, int index, short pRef, short oRef,\r
+            ClusterI.CompleteTypeEnum completeType, CompleteTable ct)\r
+    throws DatabaseException {\r
+        assert (0 != pRef);\r
+        assert (0 != oRef);\r
+        if (completeType != ClusterI.CompleteTypeEnum.NotComplete) {\r
+            int completeRef = ResourceElementSmall.getCompleteObjectRef(table, index);\r
+            if (0 == completeRef)\r
+                return false; // Statement not removed because it doesn't exist.\r
+            int refAndType = ResourceElementSmall.completeMakeObjectRefAndType(oRef, completeType);\r
+            if (ResourceElementSmall.completeIsSameStatement(table, index, refAndType)) {\r
+                ResourceElementSmall.completeSetRefAndType(table, index, 0);\r
+                return true; // statement removed\r
+            } else if (ResourceElementSmall.completeHasMultiple(table, index)) {\r
+                // CompleteRef is index to complete table.\r
+                int oldSize = ct.getCompleteSetSize(completeRef);\r
+                int newSize = ct.removeComplete(completeRef, refAndType);\r
+                if (oldSize == newSize)\r
+                    return false; // not removed\r
+                else if (newSize == 1) {\r
+                    int cRef = ct.removeLast(completeRef);\r
+                    ResourceElementSmall.completeSetRefAndType(table, index, cRef);\r
+                }\r
+                return true; \r
+            }\r
+            return false; // Statement not removed because it doesn't exist.\r
+        }\r
+        short p1 = getStm1Predicate(table, index);\r
+        short o1 = getStm1Object(table, index);\r
+        if (0 == p1)\r
+            return false; // no statements cached\r
+        short p2 = getStm2Predicate(table, index);\r
+        short o2 = getStm2Object(table, index);\r
+        if (p1 == pRef && o1 == oRef) {\r
+            setStm1Predicate(table, index, p2);\r
+            setStm1Object(table, index, o2);\r
+            setStm2Predicate(table, index, (short)0);\r
+            setStm2Object(table, index, (short)0);\r
+            return true; // statement removed\r
+        }\r
+        if (0 == p2)\r
+            return false; // no match\r
+        else if (p2 == pRef && o2 == oRef) {\r
+            setStm2Predicate(table, index, (short)0);\r
+            setStm2Object(table, index, (short)0);\r
+            return true; // statement removed\r
+        }\r
+        return false;\r
+    }\r
+}\r