]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.db.procore/src/org/simantics/db/procore/cluster/ResourceTable.java
Multiple reader thread support for db client
[simantics/platform.git] / bundles / org.simantics.db.procore / src / org / simantics / db / procore / cluster / ResourceTable.java
index a36f54d056ac3de5a90915b0a4f55ed6bb3c387d..d0619976d4775421d4bd5b915d4dbe23b6063081 100644 (file)
-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.db.procore.cluster;\r
-\r
-import java.util.ArrayList;\r
-\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.common.utils.Logger;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.exception.ExternalValueException;\r
-import org.simantics.db.exception.ValidationException;\r
-import org.simantics.db.impl.ClusterBase;\r
-import org.simantics.db.impl.ClusterI;\r
-import org.simantics.db.impl.ClusterI.CompleteTypeEnum;\r
-import org.simantics.db.impl.ClusterI.ObjectProcedure;\r
-import org.simantics.db.impl.ClusterI.PredicateProcedure;\r
-import org.simantics.db.impl.ClusterI.Procedure;\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.Table;\r
-import org.simantics.db.impl.TableFactory;\r
-import org.simantics.db.impl.TableSizeListener;\r
-import org.simantics.db.impl.graph.ReadGraphImpl;\r
-import org.simantics.db.procedure.AsyncContextMultiProcedure;\r
-import org.simantics.db.procedure.AsyncMultiProcedure;\r
-import org.simantics.db.procore.cluster.PredicateTable.Status;\r
-\r
-\r
-final class ResourceElement {\r
-    private static final boolean DEBUG = ClusterImpl.DEBUG;\r
-    private static final int DESCRIPTOR_OFFSET = 0; // predicate descriptor\r
-    private static final int VALUE_OFFSET      = 1; // value descriptor\r
-    private static final int STM_OFFSET        = 2; // first statement\r
-    private static final int SIZE_OF           = 4;\r
-\r
-    static void construct(long[] table, int index) {\r
-        int i = DESCRIPTOR_OFFSET + index;\r
-        table[i++] = 0; // predicate capacity & index\r
-        table[i++] = 0; // value capacity & index\r
-        table[i++] = 0; // stm1\r
-        table[i++] = 0; // stm2\r
-    }\r
-\r
-    static void destruct(long[] table, int index) {\r
-        int i = DESCRIPTOR_OFFSET + index;\r
-        table[i++] = 0; // predicate capacity & index\r
-        table[i++] = 0; // value capacity & index\r
-        table[i++] = 0; // stm1\r
-        table[i++] = 0; // stm2\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
-        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 int getCompleteObjectRef(long[] table, int index) {\r
-        int i = DESCRIPTOR_OFFSET + index;\r
-        return BitUtility.getHighInt(table[i]);\r
-    }\r
-\r
-    static void setCompleteObjectRef(long[] table, int index, int ref) {\r
-        int i = DESCRIPTOR_OFFSET + index;\r
-        table[i] = BitUtility.setHighInt(table[i], ref);\r
-    }\r
-\r
-    static int getPredicateIndex(long[] table, int index) {\r
-        int i = DESCRIPTOR_OFFSET + index;\r
-        int predicateIndex = BitUtility.getLowInt(table[i]);\r
-        assert (predicateIndex >= 0);\r
-        return predicateIndex;\r
-    }\r
-\r
-    static void setPredicateIndex(long[] table, int index, int predicateIndex) {\r
-        assert (predicateIndex >= 0);\r
-        int i = DESCRIPTOR_OFFSET + index;\r
-        table[i] = BitUtility.setLowInt(table[i], predicateIndex);\r
-    }\r
-\r
-    static int copyValue(ValueTable valueTable, long[] table, int index, byte[] byteTable, int byteSize, int byteBase,\r
-            int byteCurrent) {\r
-        int i = VALUE_OFFSET + index;\r
-        if (0 == table[i] || -1 == table[i])\r
-            return byteCurrent; // no value or external value\r
-        // getValueCapacity call optimized away\r
-        int capacity = BitUtility.getLowInt(table[i]);\r
-        int valueIndex = getValueIndex(table, index);\r
-        if (0 == valueIndex)\r
-            return byteCurrent;\r
-        valueTable.getValue(valueIndex, byteTable, byteCurrent, capacity);\r
-        valueIndex = byteCurrent - byteBase;\r
-        setValueIndex(table, index, valueIndex);\r
-        byteCurrent += capacity;\r
-        return byteCurrent;\r
-    }\r
-\r
-    static byte[] getValue(ValueTable valueTable, long[] table, int index)\r
-    throws DatabaseException {\r
-        int i = VALUE_OFFSET + index;\r
-        if (0 == table[i])\r
-            return null; // no value\r
-        if (-1 == table[i])\r
-            throw new ExternalValueException("Value stored externally.");\r
-        // getValueCapacity call optimized away\r
-        int capacity = BitUtility.getLowInt(table[i]);\r
-        byte[] t = new byte[capacity];\r
-        int valueIndex = getValueIndex(table, index);\r
-        valueTable.getValue(valueIndex, t, 0, capacity);\r
-        return t;\r
-    }\r
-\r
-//    static int getString(ValueTable valueTable, long[] table, int index, char[] t)\r
-//    throws DatabaseException {\r
-//        long l = table[index + VALUE_OFFSET];\r
-//        if (-1 == l)\r
-//            throw new ExternalValueException("String stored externally.");\r
-//        int capacity = (int)l;\r
-//        int valueIndex = (int) (l >>> 32);\r
-////        char[] t = new char[capacity-1];\r
-//        valueTable.getString(valueIndex, t, 0, capacity-1);\r
-//        return capacity-1;\r
-//        \r
-//    }\r
-\r
-    static boolean hasValue(long[] table, int index) {\r
-        int i = VALUE_OFFSET + index;\r
-        return 0 != table[i];\r
-    }\r
-//KRAA:\r
-//    static boolean hasValue(ValueTable valueTable, long[] table, int index, byte[] value) {\r
-//        int i = VALUE_OFFSET + index;\r
-//        if (0 == table[i])\r
-//            return false;\r
-//        // getValueCapacity call optimized away\r
-//        int capacity = BitUtility.getLowInt(table[i]);\r
-//        if (capacity != value.length)\r
-//            return false;\r
-//        int valueIndex = getValueIndex(table, index);\r
-//        return valueTable.isEqual(valueIndex, value);\r
-//    }\r
-\r
-    static boolean removeValue(ValueTable valueTable, long[] table, int index) {\r
-        int i = VALUE_OFFSET + index;\r
-        if (0 == table[i])\r
-            return false;\r
-        else if (-1 != table[i]) {\r
-            // getValueCapacity call optimized away\r
-            int capacity = BitUtility.getLowInt(table[i]);\r
-            int valueIndex = getValueIndex(table, index);\r
-            valueTable.removeValue(valueIndex, capacity);\r
-        }\r
-       //setValueCapacityAndIndex(table, index, 0, 0); optimized away\r
-        table[i] = 0;\r
-        return true;\r
-    }\r
-\r
-    public static void setValue(ValueTable valueTable, long[] table, int index, byte[] value, int length) {\r
-        int i = VALUE_OFFSET + index;\r
-        // getValueCapacity call optimized away\r
-        int capacity = BitUtility.getLowInt(table[i]); \r
-        int valueIndex = getValueIndex(table, index);\r
-        if (length <= capacity) {\r
-            valueTable.setValue(valueIndex, value, length);\r
-            // we "leak" memory TODO: add value size member to\r
-            // resource entry or value entry\r
-            setValueCapacity(table, index, length);\r
-        } else {\r
-            if (valueIndex != 0 && capacity > 0)\r
-                valueTable.removeValue(valueIndex, capacity);\r
-            valueIndex = valueTable.createValue(value, 0, length);\r
-            capacity = length;\r
-            setValueCapacityAndIndex(table, index, capacity, valueIndex);\r
-        }\r
-        return;\r
-    }\r
-    public static boolean isValueEx(ValueTable valueTable, long[] table, int index) {\r
-        int i = VALUE_OFFSET + index;\r
-        if (-1 == table[i])\r
-            return true;\r
-        else\r
-            return false;\r
-    }\r
-    public static void setValueEx(ValueTable valueTable, long[] table, int index) {\r
-        int i = VALUE_OFFSET + index;\r
-        if (-1 == table[i])\r
-            return;\r
-        else if (0 != table[i]) {\r
-            int capacity = BitUtility.getLowInt(table[i]);\r
-            int valueIndex = getValueIndex(table, index);\r
-            valueTable.removeValue(valueIndex, capacity);\r
-        }\r
-       //setValueCapacityAndIndex(table, index, 0, 0); optimized away\r
-        table[i] = -1;\r
-    }\r
-    static class ValueData {\r
-        int capacity;\r
-        int index;\r
-//        ValueData(int capacity, int index) {\r
-//            this.capacity = capacity;\r
-//            this.index = index;\r
-//        }\r
-    }\r
-    static void getValueCapacityAndIndex(ValueData vd, long[] table, int index) {\r
-        int i = VALUE_OFFSET + index;\r
-        // getValueCapacity call optimized away\r
-        vd.capacity = BitUtility.getLowInt(table[i]); \r
-        vd.index = getValueIndex(table, index);\r
-        \r
-    }\r
-    private static int getValueIndex(long[] table, int index) {\r
-        int i = VALUE_OFFSET + index;\r
-        return BitUtility.getHighInt(table[i]);\r
-    }\r
-\r
-    private static void setValueIndex(long[] table, int index, int valueIndex) {\r
-        int i = VALUE_OFFSET + index;\r
-        table[i] = BitUtility.setHighInt(table[i], valueIndex);\r
-    }\r
-\r
-    private static void setValueCapacity(long[] table, int index, int capacity) {\r
-        int i = VALUE_OFFSET + index;\r
-        table[i] = BitUtility.setLowInt(table[i], capacity);\r
-    }\r
-\r
-    private static void setValueCapacityAndIndex(long[] table, int index, int capacity, int valueIndex) {\r
-        int i = VALUE_OFFSET + index;\r
-        table[i] = BitUtility.setLowAndHighInt(table[i], capacity, valueIndex);\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 = ResourceElement.getCompleteObjectRef(table, index);\r
-        if (0 != completeRef) {\r
-            if (ClusterTraits.completeReferenceIsMultiple(completeRef)) { // multiple complete type elements\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 {\r
-               ClusterI.CompleteTypeEnum completeType = ClusterTraits.completeReferenceGetType(completeRef);\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 != ResourceElement.getPredicateIndex(table, index)) {\r
-            if (DEBUG)\r
-                System.out.println("ResourceElement.foreachPredicate: more than 2 objects");\r
-               return false;\r
-        }\r
-        int i = STM_OFFSET + index;\r
-        int p1 = BitUtility.getHighInt(table[i]);\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 = BitUtility.getHighInt(table[++i]);\r
-        if (0 == p2 || p1 == p2) {\r
-            if (DEBUG)\r
-                System.out.println("ResourceElement.foreachPredicate: cache2 empty");\r
-               return false; // loop finished, one statement\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
-        if (procedure.execute(context, externalRef, 0))\r
-               return true; // loop broken by procedure\r
-        if (DEBUG)\r
-            System.out.println("ResourceElement.foreachPredicate: not in cache");\r
-        return false; // loop finished, two statements\r
-    }\r
-\r
-    public static int getSingleObject(long[] table, int index, ClusterSupport support, final int pRef, final ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, final 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 (ClusterTraits.completeReferenceIsMultiple(completeRef)) {\r
-                // Multiple complete type elements.\r
-                if (DEBUG)\r
-                    System.out.println("ResourceElement.getSingleObject was complete 2");\r
-                class ForeachObject\r
-                implements ClusterI.ObjectProcedure<Integer> {\r
-                    @Override\r
-                    public boolean execute(Integer context, int completeRef)\r
-                    throws DatabaseException {\r
-                        ClusterI.CompleteTypeEnum oCompleteType = ClusterTraits.completeReferenceGetType(completeRef);\r
-                        if (pCompleteType == oCompleteType) { // 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
-                            int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);\r
-                            int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);\r
-                            if (0 == clusterIndex) {\r
-                                context = modifier.execute(resourceIndex);\r
-                            } else {\r
-                                int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);\r
-                                context = modifier.execute(externalRef);\r
-                            }\r
-                        }\r
-                        return true; // continue looping\r
-                    }\r
-                    \r
-                }\r
-                ForeachObject t = new ForeachObject();\r
-                // CompleteRef is complete object set index.\r
-                Integer c = 0;\r
-                ct.foreachComplete(completeRef, t, c, support, modifier);\r
-                return c;\r
-            }\r
-            // one complete type element\r
-            ClusterI.CompleteTypeEnum completeType = ClusterTraits.completeReferenceGetType(completeRef);\r
-            if (pCompleteType != completeType)\r
-                return 0;\r
-            int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);\r
-            int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);\r
-            if (0 == clusterIndex) {\r
-                return modifier.execute(resourceIndex);\r
-            } else {\r
-                int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);\r
-                return modifier.execute(externalRef);\r
-            }\r
-        }\r
-        int i = STM_OFFSET + index;\r
-        int p1 = BitUtility.getHighInt(table[i]);\r
-        if (0 == p1)\r
-            return 0; // loop finished, no statements\r
-        int result = 0;\r
-        if (pRef == p1) {\r
-            int o1 = BitUtility.getLowInt(table[i]);\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 = BitUtility.getHighInt(table[++i]);\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
-           int o2 = BitUtility.getLowInt(table[i]);\r
-        return modifier.execute(o2);\r
-        \r
-//        return 0;\r
-//        int o2 = BitUtility.getLowInt(table[i]);\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
-               final ClusterSupport support, final int pRef, final 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 (ClusterTraits.completeReferenceIsMultiple(completeRef)) {\r
-                // Multiple complete type statements.\r
-                if (DEBUG)\r
-                    System.out.println("ResourceElement.was complete 2");\r
-                class ForeachObject implements ClusterI.ObjectProcedure<Object> {\r
-                    @Override\r
-                    public boolean execute(Object context, int completeRef) throws DatabaseException {\r
-                        ClusterI.CompleteTypeEnum oCompleteType = ClusterTraits.completeReferenceGetType(completeRef);\r
-                        if (pCompleteType == oCompleteType) {\r
-                            int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);\r
-                            int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);\r
-                            if (0 == clusterIndex) {\r
-                                procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(resourceIndex)));\r
-                            } else {\r
-                                int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);\r
-                                procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(externalRef)));\r
-                            }\r
-                        }\r
-                        return false; // continue looping\r
-                    }\r
-                    \r
-                }\r
-                ForeachObject t = new ForeachObject();\r
-                // CompleteRef is complete object set index.\r
-                ct.foreachComplete(completeRef, t, null, support, modifier);\r
-                procedure.finished(graph);\r
-//                graph.state.dec(0);\r
-                return; // loop finished\r
-            }\r
-            // one complete type element\r
-            ClusterI.CompleteTypeEnum completeType = ClusterTraits.completeReferenceGetType(completeRef);\r
-            if (pCompleteType != completeType) {\r
-                       procedure.finished(graph);\r
-//                     graph.state.dec(0);\r
-                return;\r
-            }\r
-            int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);\r
-            int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);\r
-            if (0 == clusterIndex) {\r
-                procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(resourceIndex)));\r
-            } else {\r
-                int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);\r
-                procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(externalRef)));\r
-            }\r
-               procedure.finished(graph);\r
-//             graph.state.dec(0);\r
-            return; // loop finished\r
-        }\r
-        int i = STM_OFFSET + index;\r
-        long l = table[i];\r
-        int p1 = (int) (l >>> 32);\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
-            int o1 = (int)l;\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
-        long l2 = table[++i];\r
-        int p2 = (int) (l2 >>> 32);\r
-        if (pRef != p2) {\r
-               procedure.finished(graph);\r
-//             graph.state.dec(0);\r
-            return; // loop finished, one statements\r
-        }\r
-        int o2 = (int)l2;\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
-               final ClusterSupport support, final int pRef, final 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 (ClusterTraits.completeReferenceIsMultiple(completeRef)) {\r
-                // Multiple complete type statements.\r
-                if (DEBUG)\r
-                    System.out.println("ResourceElement.was complete 2");\r
-                class ForeachObject implements ClusterI.ObjectProcedure<Object> {\r
-                    @Override\r
-                    public boolean execute(Object _context, int completeRef) throws DatabaseException {\r
-                        ClusterI.CompleteTypeEnum oCompleteType = ClusterTraits.completeReferenceGetType(completeRef);\r
-                        if (pCompleteType == oCompleteType) {\r
-                            int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);\r
-                            int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);\r
-                            if (0 == clusterIndex) {\r
-                                procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(resourceIndex)));\r
-                            } else {\r
-                                int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);\r
-                                procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(externalRef)));\r
-                            }\r
-                        }\r
-                        return false; // continue looping\r
-                    }\r
-                    \r
-                }\r
-                ForeachObject t = new ForeachObject();\r
-                // CompleteRef is complete object set index.\r
-                ct.foreachComplete(completeRef, t, null, support, modifier);\r
-                procedure.finished(graph);\r
-//                graph.state.dec(0);\r
-                return; // loop finished\r
-            }\r
-            // one complete type element\r
-            ClusterI.CompleteTypeEnum completeType = ClusterTraits.completeReferenceGetType(completeRef);\r
-            if (pCompleteType != completeType) {\r
-                       procedure.finished(graph);\r
-//                     graph.state.dec(0);\r
-                return;\r
-            }\r
-            int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);\r
-            int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);\r
-            if (0 == clusterIndex) {\r
-                procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(resourceIndex)));\r
-            } else {\r
-                int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);\r
-                procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(externalRef)));\r
-            }\r
-               procedure.finished(graph);\r
-//             graph.state.dec(0);\r
-            return; // loop finished\r
-        }\r
-        int i = STM_OFFSET + index;\r
-        long l = table[i];\r
-        int p1 = (int) (l >>> 32);\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
-            int o1 = (int)l;\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
-        long l2 = table[++i];\r
-        int p2 = (int) (l2 >>> 32);\r
-        if (pRef != p2) {\r
-               procedure.finished(graph);\r
-//             graph.state.dec(0);\r
-            return; // loop finished, one statements\r
-        }\r
-        int o2 = (int)l2;\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 int pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct)\r
-    throws DatabaseException {\r
-        if (DEBUG)\r
-            System.out.println("ResourceElement.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("ResourceElement.foreachObject2: no complete");\r
-                return false; // no objects for given complete type\r
-            }\r
-            if (ClusterTraits.completeReferenceIsMultiple(completeRef)) { // multiple complete type elements\r
-                if (DEBUG)\r
-                    System.out.println("ResourceElement.foreachObject2: multi-complete ci=" + completeRef);\r
-                return ct.foreachObject(completeRef, procedure, context, support, modifier, pCompleteType);\r
-            }\r
-            // one complete type element\r
-            ClusterI.CompleteTypeEnum completeType = ClusterTraits.completeReferenceGetType(completeRef);\r
-            if (pCompleteType != completeType) {\r
-                if (DEBUG)\r
-                    System.out.println("ResourceElement.foreachObject2: complete different predicate");\r
-                return false;\r
-            }\r
-            int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);\r
-            int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);\r
-            if (0 == clusterIndex) {\r
-                int externalRef;\r
-                if (null == modifier)\r
-                    externalRef = resourceIndex;\r
-                else\r
-                    externalRef = modifier.execute(resourceIndex);\r
-                if (DEBUG)\r
-                    System.out.println("ResourceElement.foreachObject2: complete ok=" + externalRef);\r
-                if (procedure.execute(context, externalRef))\r
-                    return true; // loop broken by procedure\r
-            } else {\r
-                int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);\r
-                if (null != modifier)\r
-                    externalRef = modifier.execute(externalRef);\r
-                if (DEBUG)\r
-                    System.out.println("ResourceElement.foreachObject2: complete ok=" + externalRef);\r
-                if (procedure.execute(context, externalRef))\r
-                    return true; // loop broken by procedure\r
-            }\r
-            return false; // loop finished\r
-        }\r
-        int i = STM_OFFSET + index;\r
-        int p1 = BitUtility.getHighInt(table[i]);\r
-        if (0 == p1) {\r
-            if (DEBUG)\r
-                System.out.println("ResourceElement.foreachObject2: empty cache=");\r
-            return false; // loop finished, no statements\r
-        }\r
-        if (pRef == p1) {\r
-            int o1 = BitUtility.getLowInt(table[i]);\r
-            int externalRef;\r
-            if (null == modifier)\r
-               externalRef = o1;\r
-            else\r
-               externalRef = modifier.execute(o1);\r
-            if (DEBUG)\r
-                System.out.println("ResourceElement.foreachObject2: cache1 ok=" + externalRef);\r
-            if (procedure.execute(context, externalRef))\r
-               return true; // loop broken by procedure\r
-        }\r
-        int p2 = BitUtility.getHighInt(table[++i]);\r
-        if (0 == p2 || pRef != p2) {\r
-            if (DEBUG)\r
-                System.out.println("ResourceElement.foreachObject2: not in cache1");\r
-            return false; // loop finished, one statements\r
-        }\r
-        int o2 = BitUtility.getLowInt(table[i]);\r
-        int externalRef;\r
-        if (null == modifier)\r
-               externalRef = o2;\r
-        else\r
-               externalRef = modifier.execute(o2);\r
-        if (DEBUG)\r
-            System.out.println("ResourceElement.foreachObject2: cache2 ok=" + externalRef);\r
-        return procedure.execute(context, externalRef);\r
-    }\r
-    static boolean isEmpty(long[] table, int index) {\r
-        return getStatementCount(table, index) == 0 && !hasValue(table, index);\r
-    }\r
-    static int getStatementCount(long[] table, int index) {\r
-        int i = STM_OFFSET + index;\r
-        int p1 = BitUtility.getHighInt(table[i]);\r
-        int p2 = BitUtility.getLowInt(table[++i]);\r
-        if (0 == p1)\r
-            return 0;\r
-        else if (0 == p2)\r
-            return 1;\r
-        int predicateIndex = getPredicateIndex(table, index);\r
-        if (0 == predicateIndex)\r
-            return 2;\r
-        return 3;\r
-    }\r
-    private static int makeCompleteObjectRef(int oRef, ClusterI.CompleteTypeEnum completeType) {\r
-        int ref;\r
-        if (oRef > 0) {\r
-            int resourceIndex = oRef; \r
-            int clusterIndex = 0;\r
-            ref = ClusterTraits.completeReferenceMake(completeType.getValue(), resourceIndex, clusterIndex);\r
-        } else {\r
-            assert(oRef < 0);\r
-            assert(!ClusterTraits.isFlat(oRef));\r
-            ref = (completeType.getValue() <<30) | (oRef & 0x3FFFFFFF);\r
-        }\r
-        return ref;\r
-    }\r
-    static int addStatement(long[] table, int index, int pRef, int 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) {\r
-            int cRef = makeCompleteObjectRef(oRef, completeType);\r
-            int ctr = getCompleteObjectRef(table, index);\r
-            if (0 == ctr)\r
-                setCompleteObjectRef(table, index, cRef);\r
-            else {\r
-                int nRef;\r
-                if (ctr == cRef)\r
-                    return -1; // old complete\r
-                else if (ClusterTraits.completeReferenceIsMultiple(ctr)) {\r
-                    nRef = ct.addComplete(ctr, cRef);\r
-                    if (0 == nRef)\r
-                        return -1; // old complete\r
-                } else {\r
-                    nRef = ct.createCompleteArraySet(ctr, cRef);\r
-                }\r
-                setCompleteObjectRef(table, index, nRef);\r
-            }\r
-            return 0; // added to complete\r
-        }\r
-        int i = STM_OFFSET + index;\r
-        int p1 = BitUtility.getHighInt(table[i]);\r
-        int o1 = BitUtility.getLowInt(table[i]);\r
-        if (0 == p1) {\r
-            table[i] = BitUtility.setLowAndHighInt(table[i], oRef, pRef);\r
-            return 0; // added to stm cache\r
-        } else if (p1 == pRef && o1 == oRef)\r
-            return -1; // same statement\r
-        int p2 = BitUtility.getHighInt(table[++i]);\r
-        int o2 = BitUtility.getLowInt(table[i]);\r
-        if (0 == p2) {\r
-            table[i] = BitUtility.setLowAndHighInt(table[i], oRef, pRef);\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, o2);\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;\r
-                predicateIndex = pt.createPredicateSet(ps, os);\r
-            } else {\r
-                int[] os = new int[2];\r
-                os[0] = o1; \r
-                os[1] = o2;\r
-                int[] ps = new int[2];\r
-                ps[0] = p1;\r
-                ps[1] = p2;\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, int pRef, int 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 = ResourceElement.getCompleteObjectRef(table, index);\r
-            if (0 != completeRef) {\r
-               ClusterI.CompleteTypeEnum completeType2 = ClusterTraits.completeReferenceGetType(completeRef);\r
-                if (completeType == completeType2) {\r
-                    int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);\r
-                    int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);\r
-                    if (0 == clusterIndex) {\r
-                        if (oRef == resourceIndex) {\r
-                            ResourceElement.setCompleteObjectRef(table, index, 0);\r
-                            return true; // statement removed\r
-                        }\r
-                    } else {\r
-                        int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);\r
-                        if (oRef == externalRef) {\r
-                            ResourceElement.setCompleteObjectRef(table, index, 0);\r
-                            return true; // statement removed\r
-                        }\r
-                    }\r
-                } else if (completeType2 == ClusterI.CompleteTypeEnum.NotComplete) { // multiple complete type references \r
-                    int cRef = makeCompleteObjectRef(oRef, completeType);\r
-                    int oldSize = ct.getCompleteSetSize(completeRef);\r
-                    int newSize = ct.removeComplete(completeRef, cRef);\r
-                    if (oldSize == newSize)\r
-                        return false; // not removed\r
-                    else if (newSize == 1) {\r
-                        cRef = ct.removeLast(completeRef);\r
-                        ResourceElement.setCompleteObjectRef(table, index, cRef);\r
-                    }\r
-                    return true; \r
-                }\r
-            }\r
-        }\r
-        int i = STM_OFFSET + index;\r
-        int p1 = BitUtility.getHighInt(table[i]);\r
-        int o1 = BitUtility.getLowInt(table[i]);\r
-        if (0 == p1)\r
-            return false; // no statements cached\r
-        else if (p1 == pRef && o1 == oRef) {\r
-            table[i] = table[i + 1];\r
-            // BitUtility.setLowAndHighInt(table[i], 0, 0); optimized away\r
-            table[i + 1] = 0;\r
-            return true; // statement removed\r
-        }\r
-        int p2 = BitUtility.getHighInt(table[++i]);\r
-        int o2 = BitUtility.getLowInt(table[i]);\r
-        if (0 == p2)\r
-            return false; // no match\r
-        else if (p2 == pRef && o2 == oRef) {\r
-            // BitUtility.setLowAndHighInt(table[i], 0, 0); optimized away\r
-            table[i] = 0;\r
-            return true; // statement removed\r
-        }\r
-        return false;\r
-    }\r
-}\r
-\r
-public final class ResourceTable extends Table<long[]> {\r
-    public ResourceTable(TableSizeListener sizeListener, int[] header, int headerBase) {\r
-        super(TableFactory.getLongFactory(), sizeListener, header, headerBase);\r
-    }\r
-\r
-    public ResourceTable(TableSizeListener sizeListener, int[] header, int headerBase, long[] longs) {\r
-        super(TableFactory.getLongFactory(), sizeListener, header, headerBase, longs);\r
-    }\r
-\r
-    public int getUsedSize() {\r
-        return getTableCount();\r
-    }\r
-\r
-    public short createResource() {\r
-        final int INDEX = getTableCount();\r
-        final int SIZE = ResourceElement.getSizeOf();\r
-        int resourceIndex = createNewElement(SIZE);\r
-        assert (0 != resourceIndex);\r
-        final int REAL_INDEX = checkIndexAndGetRealIndex(resourceIndex, SIZE);\r
-        ResourceElement.construct(getTable(), REAL_INDEX);\r
-        incResourceCount();\r
-        return (short)(INDEX + ZERO_SHIFT);\r
-    }\r
-\r
-    void createResource(int resourceIndex) {\r
-        final int tableCount = getTableCount();\r
-        if (resourceIndex <= tableCount) { // old index\r
-            int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
-            if (ResourceElement.isEmpty(getTable(), realIndex))\r
-                return;\r
-        } if (resourceIndex == tableCount+1) {\r
-            createResource();\r
-            return;\r
-        }\r
-        throw new InternalError("Trying to create resource with illegal index=" + resourceIndex);\r
-    }\r
-\r
-//    void deleteResource(int resourceIndex) {\r
-//        int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
-//        ResourceElement.destruct(getTable(), realIndex);\r
-//        decResourceCount();\r
-//    }\r
-\r
-    public int getCompleteObjectRef(int resourceIndex) {\r
-        int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
-        return ResourceElement.getCompleteObjectRef(getTable(), realIndex);\r
-    }\r
-    \r
-    public int getPredicateIndex(int resourceIndex) {\r
-        int i = (resourceIndex<<2) - 3 + offset;\r
-        return (int)table[i];\r
-    }\r
-\r
-    public void setPredicateIndex(int resourceIndex, int predicateIndex) {\r
-        int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
-        ResourceElement.setPredicateIndex(getTable(), realIndex, predicateIndex);\r
-    }\r
-\r
-    public byte[] getValue(ValueTable valueTable, int resourceIndex)\r
-    throws DatabaseException {\r
-        int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
-        return ResourceElement.getValue(valueTable, getTable(), realIndex);\r
-    }\r
-\r
-//KRAA:\r
-//    int getString(ValueTable valueTable, int resourceIndex, char[] chars)\r
-//    throws DatabaseException {\r
-//        //int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
-//        return ResourceElement.getString(valueTable, getTable(), 4 * resourceIndex - 3 + offset, chars);\r
-//    }\r
-\r
-    public boolean hasValue(int resourceIndex) {\r
-        int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
-        return ResourceElement.hasValue(getTable(), realIndex);\r
-    }\r
-\r
-//    boolean hasValue(ValueTable valueTable, int resourceIndex, byte[] value) {\r
-//        int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
-//        return ResourceElement.hasValue(valueTable, getTable(), realIndex, value);\r
-//    }\r
-\r
-    public boolean removeValue(ValueTable valueTable, int resourceIndex) {\r
-        int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
-        boolean ret = ResourceElement.removeValue(valueTable, getTable(), realIndex);\r
-//        if (ret && !ResourceElement.isUsed(getTable(), realIndex))\r
-//            decResourceCount();\r
-        return ret;\r
-    }\r
-\r
-    public void setValue(ValueTable valueTable, int resourceIndex, byte[] value, int length) {\r
-        int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
-        ResourceElement.setValue(valueTable, getTable(), realIndex, value, length);\r
-    }\r
-\r
-    public boolean isValueEx(ValueTable valueTable, int resourceIndex) {\r
-        int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
-        return ResourceElement.isValueEx(valueTable, getTable(), realIndex);\r
-    }\r
-\r
-    public void setValueEx(ValueTable valueTable, int resourceIndex) {\r
-        int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
-        ResourceElement.setValueEx(valueTable, getTable(), realIndex);\r
-    }\r
-\r
-    static final int RESOURCE_COUNT_INDEX = 0;\r
-    static final int FOREIGN_COUNT_INDEX = 1; // Reserved by server.\r
-    static final int CLUSTER_STATUS_INDEX = 2;\r
-\r
-    int incResourceCount() {\r
-        int count = getExtra(RESOURCE_COUNT_INDEX) + 1;\r
-        setExtra(RESOURCE_COUNT_INDEX, count);\r
-        return count;\r
-    }\r
-\r
-//    int decResourceCount() {\r
-//        int count = getExtra(RESOURCE_COUNT_INDEX) - 1;\r
-//        setExtra(RESOURCE_COUNT_INDEX, count);\r
-//        return count;\r
-//    }\r
-\r
-    public int getResourceCount() {\r
-        return getExtra(RESOURCE_COUNT_INDEX);\r
-    }\r
-    public int getClusterStatus() {\r
-        return getExtra(CLUSTER_STATUS_INDEX);\r
-    }\r
-    public void setClusterStatus(int value) {\r
-        setExtra(CLUSTER_STATUS_INDEX, value);\r
-    }\r
-    void analyse() {\r
-\r
-       final int tsize = getTableSize();\r
-       final int esize = ResourceElement.getSizeOf();\r
-       long[] table = getTable();\r
-       for (int i = getTableBase(); i < getTableBase() + tsize; i += esize) {\r
-               if (ResourceElement.isUsed(getTable(), i)) {\r
-                       System.out.println("  -" + Long.toHexString(table[i]) + " " + Long.toHexString(table[i+1]) + " " + Long.toHexString(table[i+2]) + " " + Long.toHexString(table[i+3]));\r
-               }\r
-       }\r
-\r
-    }\r
-    \r
-    public <Context> boolean foreachResource(ClusterI.ObjectProcedure<Context> procedure, Context context,\r
-            ClusterSupport support, Modifier modifier) throws DatabaseException {\r
-        final int tsize = getTableSize();\r
-//        final int rsize = getResourceCount();\r
-        final int esize = ResourceElement.getSizeOf();\r
-        //int count = 0;\r
-        int key = ZERO_SHIFT;\r
-        for (int i = getTableBase(); i < getTableBase() + tsize; i += esize, ++key) {\r
-            if (ResourceElement.isUsed(getTable(), i)) {\r
-               int ref;\r
-               if (null == modifier)\r
-                       ref = key;\r
-               else\r
-                       ref = modifier.execute(key);\r
-                if (procedure.execute(context, ref))\r
-                    return true; // loop was broken by procedure\r
-//                if (rsize == ++count)\r
-//                     return false; // loop finished\r
-            }\r
-        }\r
-        //assert(rsize == count);\r
-        return false; // loop finished\r
-    }\r
-\r
-    public <Context> boolean foreachPredicate(int resourceIndex\r
-               , ClusterI.PredicateProcedure<Context> procedure, Context context\r
-               , ClusterSupport support, Modifier modifier, CompleteTable ct)\r
-    throws DatabaseException {\r
-        int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
-        return ResourceElement.foreachPredicate(getTable(), realIndex\r
-                       , procedure, context, support, modifier, ct);\r
-    }\r
-\r
-    public int getSingleObject(int resourceIndex, ClusterSupport support, int pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, Modifier modifier) throws DatabaseException {\r
-//        return ResourceElement.getSingleObject(table, realIndex, support, pRef, pCompleteType, ct, modifier);\r
-        return ResourceElement.getSingleObject(table, 4 * resourceIndex - 3 + offset, support, pRef, pCompleteType, ct, modifier);\r
-    }\r
-\r
-    public void foreachObject(int resourceIndex, ReadGraphImpl graph,\r
-               AsyncMultiProcedure<Resource> procedure, ClusterSupport support, int pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, Modifier modifier) throws DatabaseException {\r
-        int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
-        ResourceElement.foreachObject(table, realIndex, graph, procedure, support,\r
-                       pRef, pCompleteType, ct, modifier);\r
-    }\r
-\r
-    public <C> void foreachObject(int resourceIndex, ReadGraphImpl graph, C context,\r
-               AsyncContextMultiProcedure<C, Resource> procedure, ClusterSupport support, int pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, Modifier modifier) throws DatabaseException {\r
-        int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
-        ResourceElement.foreachObject(table, realIndex, graph, context, procedure, support,\r
-                       pRef, pCompleteType, ct, modifier);\r
-    }\r
-    \r
-    public <Context> boolean foreachObject(int resourceIndex\r
-               , ClusterI.ObjectProcedure<Context> procedure, Context context\r
-               , ClusterSupport support, Modifier modifier,\r
-               int pRef, ClusterI.CompleteTypeEnum completeType, CompleteTable ct)\r
-    throws DatabaseException {\r
-        int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
-        return ResourceElement.foreachObject(table, realIndex\r
-                       , procedure, context, support, modifier\r
-                       , pRef, completeType, ct);\r
-    }\r
-    public int addStatement(int resourceIndex, int pRef, int oRef, PredicateTable pt, ObjectTable ot\r
-            , ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct)\r
-            throws DatabaseException {\r
-        int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
-        return ResourceElement.addStatement(getTable(), realIndex, pRef, oRef, pt, ot, pCompleteType, ct);\r
-    }\r
-\r
-    public boolean removeStatementFromCache(int resourceIndex, int pRef, int oRef,\r
-               ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct)\r
-    throws DatabaseException {\r
-        int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
-        boolean ret = ResourceElement.removeStatement(getTable(), realIndex, pRef, oRef, pCompleteType, ct);\r
-//        if (ret && !ResourceElement.isUsed(getTable(), realIndex))\r
-//            decResourceCount();\r
-        return ret;\r
-    }\r
-    \r
-    public void removeStatement(int resourceIndex, int pRef, int oRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct,\r
-            PredicateTable pt, ObjectTable ot, ClusterBase cluster, ClusterSupport support)\r
-            throws DatabaseException {\r
-        int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
-        boolean removed = ResourceElement.removeStatement(getTable(), realIndex,\r
-                pRef, oRef, pCompleteType, ct);\r
-        if (!removed)\r
-            return;\r
-        int predicateIndex = ResourceElement.getPredicateIndex(getTable(), realIndex);\r
-        if (0 == predicateIndex) {\r
-//            if (!ResourceElement.isUsed(getTable(), realIndex))\r
-//                decResourceCount();\r
-            return;\r
-        }\r
-        GetStatements gs = new GetStatements(ot);\r
-        pt.foreachPredicate(predicateIndex, gs, null, null, null);\r
-        ArrayList<Statement> stms = gs.getStatements();\r
-\r
-        final int SIZE = stms.size();\r
-        if (SIZE < 3) {\r
-            for (int i = 0; i < SIZE; ++i) {\r
-                Statement stm = stms.get(i);\r
-                PredicateTable.Status ret = pt.removePredicate(predicateIndex,\r
-                        stm.pRef, stm.oIndex, ot);\r
-                if (ret == Status.NothingRemoved)\r
-                    throw new DatabaseException("Internal error during statement cache fix (2).");\r
-                int predicateKey = cluster.makeResourceKey(stm.pRef);\r
-                int completeTypeInt = ClusterTraitsBase.getCompleteTypeIntFromResourceKey(predicateKey);\r
-                ClusterI.CompleteTypeEnum completeType = CompleteTypeEnum.make(completeTypeInt);\r
-                int pi = ResourceElement.addStatement(getTable(), realIndex, stm.pRef, stm.oIndex,\r
-                        pt, ot, completeType, ct);\r
-                assert(0 >= pi);\r
-            }\r
-            assert(0 == pt.getPredicateSetSize(predicateIndex));\r
-            ResourceElement.setPredicateIndex(getTable(), realIndex, 0);\r
-        } else {\r
-            for (int i = 0; i < SIZE; ++i) {\r
-                Statement stm = stms.get(i);\r
-                int predicateKey = cluster.makeResourceKey(stm.pRef);\r
-                int completeTypeInt = ClusterTraitsBase.getCompleteTypeIntFromResourceKey(predicateKey);\r
-                ClusterI.CompleteTypeEnum completeType = CompleteTypeEnum.make(completeTypeInt);\r
-                int pIndex = ResourceElement.addStatement(getTable(), realIndex,\r
-                        stm.pRef, stm.oIndex, pt, ot, completeType, ct);\r
-                if (pIndex > 0)\r
-                    return; // cache fixed and full, p and o sets in use\r
-            }\r
-            throw new DatabaseException("Internal error during statement cache fix (3).");\r
-        }\r
-//        if (!ResourceElement.isUsed(getTable(), realIndex))\r
-//            decResourceCount();\r
-    }\r
-\r
-    //(i-1)*4+1 + 4\r
-    private int checkIndexAndGetRealIndex(final int INDEX) {\r
-        assert(INDEX > 0);\r
-        assert(INDEX <= getTableCount());\r
-//        final int TABLE_INDEX = (INDEX - ZERO_SHIFT) * ResourceElement.getSizeOf() + ZERO_SHIFT;\r
-//        final int TABLE_INDEX = (INDEX - ZERO_SHIFT) * ResourceElement.getSizeOf() + ZERO_SHIFT;\r
-//        return checkIndexAndGetRealIndex(TABLE_INDEX, ResourceElement.getSizeOf());\r
-        return 4 * INDEX - 3 + offset;\r
-    }\r
-       public void check(ClusterBase cluster)\r
-       throws DatabaseException {\r
-//        int count = 0;\r
-           cluster.checkValueInit();\r
-        long[] table = getTable();\r
-        int ps = getHeader().getOffset() + ZERO_SHIFT;\r
-        final int TABLE_SIZE = getTableSize();\r
-        int pe = ps + TABLE_SIZE;\r
-        for (int p=ps; p<pe; p+=ResourceElement.getSizeOf()) {\r
-               if (!ResourceElement.isUsed(table, p))\r
-                       continue;\r
-               int cr = ResourceElement.getCompleteObjectRef(table, p);\r
-               if (0 != cr) {\r
-                       if (ClusterTraits.completeReferenceIsMultiple(cr))\r
-                               cluster.checkCompleteSetReference(cr);\r
-                       else {\r
-                       int fi = ClusterTraits.completeReferenceGetForeignIndex(cr);\r
-                       int ri = ClusterTraits.completeReferenceGetResourceIndex(cr);\r
-                       if (0 != fi)\r
-                               cluster.checkForeingIndex(fi);\r
-                       else if (ri < 1 || ri > TABLE_SIZE)\r
-                               throw new ValidationException("Illegal resource index=" + ri);\r
-                       }\r
-               }\r
-               int pi = ResourceElement.getPredicateIndex(table, p);\r
-               if (0 != pi) {\r
-                   cluster.checkPredicateIndex(pi);\r
-               }\r
-               ResourceElement.ValueData vd = new ResourceElement.ValueData();\r
-               ResourceElement.getValueCapacityAndIndex(vd, table, p);\r
-               cluster.checkValue(vd.capacity, vd.index);\r
-        }\r
-        cluster.checkValueFini();\r
-       }\r
-\r
-    @Override\r
-    public <Context> boolean foreach(int setIndex, Procedure procedure, Context context,\r
-            ClusterSupport support, Modifier modifier) throws DatabaseException {\r
-        throw new UnsupportedOperationException();\r
-    }\r
-}\r
-\r
-class Statement {\r
-    Statement(int pRef, int oIndex) {\r
-        this.pRef = pRef;\r
-        this.oIndex = oIndex;\r
-    }\r
-    final int pRef;\r
-    final int oIndex;\r
-}\r
-\r
-class CalculateStatements\r
-implements ClusterI.PredicateProcedure<CalculateStatements> {\r
-    private ObjectTable         ot;\r
-    private final int           sRef;\r
-\r
-    CalculateStatements(int sRef, ObjectTable ot) {\r
-        this.sRef = sRef;\r
-        this.ot = ot;\r
-    }\r
-\r
-    @Override\r
-    public boolean execute(final CalculateStatements context\r
-            , final int pKey, int oIndex) {\r
-        if (ClusterTraits.statementIndexIsDirect(oIndex))\r
-            return false; // osize = 1\r
-        try {\r
-            oIndex = ClusterTraits.statementIndexGet(oIndex);\r
-        } catch (DatabaseException e) {\r
-            Logger.getDefault().logError("Missing object set for s="\r
-                    + sRef + " p=" + pKey, null);\r
-            return false; // continue looping\r
-        }\r
-        int osize = ot.getObjectSetSize(oIndex);\r
-        if (osize == 3 || osize > 9)\r
-            System.out.println("Resource " + sRef + " predicate " + pKey + " has "\r
-                    + osize + " objects.");\r
-        return true; // break loop\r
-    }\r
-}\r
-\r
-class GetStatements implements PredicateProcedure<Object>, ObjectProcedure<Integer> {\r
-    private ObjectTable         ot;\r
-    private final ArrayList<Statement> stms = new ArrayList<Statement>(); \r
-    GetStatements(ObjectTable ot) {\r
-        this.ot = ot;\r
-    }\r
-    ArrayList<Statement> getStatements() {\r
-        return stms;\r
-    }\r
-    @Override\r
-    public boolean execute(Object context, int pRef, int oIndex) {\r
-        try {\r
-            ot.foreachObject(oIndex, this, pRef, null, null);\r
-        } catch (DatabaseException e) {\r
-            e.printStackTrace();\r
-            return false; // continue looping\r
-        }\r
-        if (stms.size() > 2)\r
-            return true; // break loop\r
-        return false; // continue looping\r
-    }\r
-\r
-    @Override\r
-    public boolean execute(Integer pRef, int oRef) {\r
-        stms.add(new Statement(pRef, oRef));\r
-        if (stms.size() > 2)\r
-            return true; // break loop\r
-        return false; // continue looping\r
-    }\r
-    \r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.db.procore.cluster;
+
+import java.util.ArrayList;
+
+import org.simantics.db.Resource;
+import org.simantics.db.common.utils.Logger;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.exception.ExternalValueException;
+import org.simantics.db.exception.ValidationException;
+import org.simantics.db.impl.ClusterBase;
+import org.simantics.db.impl.ClusterI;
+import org.simantics.db.impl.ClusterI.CompleteTypeEnum;
+import org.simantics.db.impl.ClusterI.ObjectProcedure;
+import org.simantics.db.impl.ClusterI.PredicateProcedure;
+import org.simantics.db.impl.ClusterI.Procedure;
+import org.simantics.db.impl.ClusterSupport;
+import org.simantics.db.impl.ClusterTraitsBase;
+import org.simantics.db.impl.Modifier;
+import org.simantics.db.impl.ResourceImpl;
+import org.simantics.db.impl.Table;
+import org.simantics.db.impl.TableFactory;
+import org.simantics.db.impl.TableSizeListener;
+import org.simantics.db.impl.graph.ReadGraphImpl;
+import org.simantics.db.procedure.AsyncContextMultiProcedure;
+import org.simantics.db.procedure.SyncContextMultiProcedure;
+import org.simantics.db.procedure.SyncMultiProcedure;
+import org.simantics.db.procore.cluster.PredicateTable.Status;
+
+
+final class ResourceElement {
+    private static final boolean DEBUG = ClusterImpl.DEBUG;
+    private static final int DESCRIPTOR_OFFSET = 0; // predicate descriptor
+    private static final int VALUE_OFFSET      = 1; // value descriptor
+    private static final int STM_OFFSET        = 2; // first statement
+    private static final int SIZE_OF           = 4;
+
+    static void construct(long[] table, int index) {
+        int i = DESCRIPTOR_OFFSET + index;
+        table[i++] = 0; // predicate capacity & index
+        table[i++] = 0; // value capacity & index
+        table[i++] = 0; // stm1
+        table[i++] = 0; // stm2
+    }
+
+    static void destruct(long[] table, int index) {
+        int i = DESCRIPTOR_OFFSET + index;
+        table[i++] = 0; // predicate capacity & index
+        table[i++] = 0; // value capacity & index
+        table[i++] = 0; // stm1
+        table[i++] = 0; // stm2
+    }
+
+    static boolean isUsed(long[] table, int index) {
+        int i = DESCRIPTOR_OFFSET + index;
+        if (table[i++] != 0)
+            return true;
+        if (table[i++] != 0)
+            return true;
+        if (table[i++] != 0)
+            return true;
+        if (table[i++] != 0)
+            return true;
+        return false;
+    }
+
+    static int getSizeOf() {
+        return SIZE_OF;
+    }
+
+    static int getCompleteObjectRef(long[] table, int index) {
+        int i = DESCRIPTOR_OFFSET + index;
+        return BitUtility.getHighInt(table[i]);
+    }
+
+    static void setCompleteObjectRef(long[] table, int index, int ref) {
+        int i = DESCRIPTOR_OFFSET + index;
+        table[i] = BitUtility.setHighInt(table[i], ref);
+    }
+
+    static int getPredicateIndex(long[] table, int index) {
+        int i = DESCRIPTOR_OFFSET + index;
+        int predicateIndex = BitUtility.getLowInt(table[i]);
+        assert (predicateIndex >= 0);
+        return predicateIndex;
+    }
+
+    static void setPredicateIndex(long[] table, int index, int predicateIndex) {
+        assert (predicateIndex >= 0);
+        int i = DESCRIPTOR_OFFSET + index;
+        table[i] = BitUtility.setLowInt(table[i], predicateIndex);
+    }
+
+    static int copyValue(ValueTable valueTable, long[] table, int index, byte[] byteTable, int byteSize, int byteBase,
+            int byteCurrent) {
+        int i = VALUE_OFFSET + index;
+        if (0 == table[i] || -1 == table[i])
+            return byteCurrent; // no value or external value
+        // getValueCapacity call optimized away
+        int capacity = BitUtility.getLowInt(table[i]);
+        int valueIndex = getValueIndex(table, index);
+        if (0 == valueIndex)
+            return byteCurrent;
+        valueTable.getValue(valueIndex, byteTable, byteCurrent, capacity);
+        valueIndex = byteCurrent - byteBase;
+        setValueIndex(table, index, valueIndex);
+        byteCurrent += capacity;
+        return byteCurrent;
+    }
+
+    static byte[] getValue(ValueTable valueTable, long[] table, int index)
+    throws DatabaseException {
+        int i = VALUE_OFFSET + index;
+        if (0 == table[i])
+            return null; // no value
+        if (-1 == table[i])
+            throw new ExternalValueException("Value stored externally.");
+        // getValueCapacity call optimized away
+        int capacity = BitUtility.getLowInt(table[i]);
+        byte[] t = new byte[capacity];
+        int valueIndex = getValueIndex(table, index);
+        valueTable.getValue(valueIndex, t, 0, capacity);
+        return t;
+    }
+
+//    static int getString(ValueTable valueTable, long[] table, int index, char[] t)
+//    throws DatabaseException {
+//        long l = table[index + VALUE_OFFSET];
+//        if (-1 == l)
+//            throw new ExternalValueException("String stored externally.");
+//        int capacity = (int)l;
+//        int valueIndex = (int) (l >>> 32);
+////        char[] t = new char[capacity-1];
+//        valueTable.getString(valueIndex, t, 0, capacity-1);
+//        return capacity-1;
+//        
+//    }
+
+    static boolean hasValue(long[] table, int index) {
+        int i = VALUE_OFFSET + index;
+        return 0 != table[i];
+    }
+//KRAA:
+//    static boolean hasValue(ValueTable valueTable, long[] table, int index, byte[] value) {
+//        int i = VALUE_OFFSET + index;
+//        if (0 == table[i])
+//            return false;
+//        // getValueCapacity call optimized away
+//        int capacity = BitUtility.getLowInt(table[i]);
+//        if (capacity != value.length)
+//            return false;
+//        int valueIndex = getValueIndex(table, index);
+//        return valueTable.isEqual(valueIndex, value);
+//    }
+
+    static boolean removeValue(ValueTable valueTable, long[] table, int index) {
+        int i = VALUE_OFFSET + index;
+        if (0 == table[i])
+            return false;
+        else if (-1 != table[i]) {
+            // getValueCapacity call optimized away
+            int capacity = BitUtility.getLowInt(table[i]);
+            int valueIndex = getValueIndex(table, index);
+            valueTable.removeValue(valueIndex, capacity);
+        }
+       //setValueCapacityAndIndex(table, index, 0, 0); optimized away
+        table[i] = 0;
+        return true;
+    }
+
+    public static void setValue(ValueTable valueTable, long[] table, int index, byte[] value, int length) {
+        int i = VALUE_OFFSET + index;
+        // getValueCapacity call optimized away
+        int capacity = BitUtility.getLowInt(table[i]); 
+        int valueIndex = getValueIndex(table, index);
+        if (length <= capacity) {
+            valueTable.setValue(valueIndex, value, length);
+            // we "leak" memory TODO: add value size member to
+            // resource entry or value entry
+            setValueCapacity(table, index, length);
+        } else {
+            if (valueIndex != 0 && capacity > 0)
+                valueTable.removeValue(valueIndex, capacity);
+            valueIndex = valueTable.createValue(value, 0, length);
+            capacity = length;
+            setValueCapacityAndIndex(table, index, capacity, valueIndex);
+        }
+        return;
+    }
+    public static boolean isValueEx(ValueTable valueTable, long[] table, int index) {
+        int i = VALUE_OFFSET + index;
+        if (-1 == table[i])
+            return true;
+        else
+            return false;
+    }
+    public static void setValueEx(ValueTable valueTable, long[] table, int index) {
+        int i = VALUE_OFFSET + index;
+        if (-1 == table[i])
+            return;
+        else if (0 != table[i]) {
+            int capacity = BitUtility.getLowInt(table[i]);
+            int valueIndex = getValueIndex(table, index);
+            valueTable.removeValue(valueIndex, capacity);
+        }
+       //setValueCapacityAndIndex(table, index, 0, 0); optimized away
+        table[i] = -1;
+    }
+    static class ValueData {
+        int capacity;
+        int index;
+//        ValueData(int capacity, int index) {
+//            this.capacity = capacity;
+//            this.index = index;
+//        }
+    }
+    static void getValueCapacityAndIndex(ValueData vd, long[] table, int index) {
+        int i = VALUE_OFFSET + index;
+        // getValueCapacity call optimized away
+        vd.capacity = BitUtility.getLowInt(table[i]); 
+        vd.index = getValueIndex(table, index);
+        
+    }
+    private static int getValueIndex(long[] table, int index) {
+        int i = VALUE_OFFSET + index;
+        return BitUtility.getHighInt(table[i]);
+    }
+
+    private static void setValueIndex(long[] table, int index, int valueIndex) {
+        int i = VALUE_OFFSET + index;
+        table[i] = BitUtility.setHighInt(table[i], valueIndex);
+    }
+
+    private static void setValueCapacity(long[] table, int index, int capacity) {
+        int i = VALUE_OFFSET + index;
+        table[i] = BitUtility.setLowInt(table[i], capacity);
+    }
+
+    private static void setValueCapacityAndIndex(long[] table, int index, int capacity, int valueIndex) {
+        int i = VALUE_OFFSET + index;
+        table[i] = BitUtility.setLowAndHighInt(table[i], capacity, valueIndex);
+    }
+
+    public static <Context> boolean foreachPredicate(long[] table, int index,
+               ClusterI.PredicateProcedure<Context> procedure,
+               Context context, ClusterSupport support, Modifier modifier,
+               CompleteTable ct)
+    throws DatabaseException {
+        if (DEBUG)
+            System.out.println("ResourceElement.foreachPredicate: 1");
+        int completeRef = ResourceElement.getCompleteObjectRef(table, index);
+        if (0 != completeRef) {
+            if (ClusterTraits.completeReferenceIsMultiple(completeRef)) { // multiple complete type elements
+                boolean broken = ct.foreachPredicate(completeRef, procedure, context, support, modifier);
+                if (DEBUG)
+                    System.out.println("ResourceElement.foreachPredicate: multi-complete ci=" + completeRef + " break=" + broken);
+                if (broken)
+                    return true; // loop broken by procedure
+            } else {
+               ClusterI.CompleteTypeEnum completeType = ClusterTraits.completeReferenceGetType(completeRef);
+                if (ClusterI.CompleteTypeEnum.NotComplete != completeType) {
+                    int key = ClusterTraitsBase.getCompleteTypeResourceKeyFromEnum(completeType);
+                    boolean broken = procedure.execute(context, key, 0);
+                    if (DEBUG)
+                        System.out.println("ResourceElement.foreachPredicate: complete rk=" + key + " break=" + broken);
+                    if (broken)
+                        return true; // loop broken by procedure
+                }
+            }
+        }
+        // If predicate set is in use it will contain also these statements.
+        if (0 != ResourceElement.getPredicateIndex(table, index)) {
+            if (DEBUG)
+                System.out.println("ResourceElement.foreachPredicate: more than 2 objects");
+               return false;
+        }
+        int i = STM_OFFSET + index;
+        int p1 = BitUtility.getHighInt(table[i]);
+        if (0 == p1) {
+            if (DEBUG)
+                System.out.println("ResourceElement.foreachPredicate: empty cache");
+            return false; // loop finished, no statements
+        }
+        int externalRef;
+        if (null == modifier)
+            externalRef = p1;
+        else
+            externalRef = modifier.execute(p1);
+        if (DEBUG)
+            System.out.println("ResourceElement.foreachPredicate: cache1 pk=" + externalRef);
+        if (procedure.execute(context, externalRef, 0))
+               return true; // loop broken by procedure
+        int p2 = BitUtility.getHighInt(table[++i]);
+        if (0 == p2 || p1 == p2) {
+            if (DEBUG)
+                System.out.println("ResourceElement.foreachPredicate: cache2 empty");
+               return false; // loop finished, one statement
+        } if (null == modifier)
+            externalRef = p2;
+        else
+            externalRef = modifier.execute(p2);
+        if (DEBUG)
+            System.out.println("ResourceElement.foreachPredicate: cache2 pk=" + externalRef);
+        if (procedure.execute(context, externalRef, 0))
+               return true; // loop broken by procedure
+        if (DEBUG)
+            System.out.println("ResourceElement.foreachPredicate: not in cache");
+        return false; // loop finished, two statements
+    }
+
+    public static int getSingleObject(long[] table, int index, ClusterSupport support, final int pRef, final ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, final Modifier modifier)
+    throws DatabaseException {
+        if (DEBUG)
+            System.out.println("ResourceElement.getSingleObject: index=" + index);
+       if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {
+            int completeRef = getCompleteObjectRef(table, index);
+            if (0 == completeRef)
+                return 0; // no objects for given complete type
+            if (ClusterTraits.completeReferenceIsMultiple(completeRef)) {
+                // Multiple complete type elements.
+                if (DEBUG)
+                    System.out.println("ResourceElement.getSingleObject was complete 2");
+                class ForeachObject
+                implements ClusterI.ObjectProcedure<Integer> {
+                    @Override
+                    public boolean execute(Integer context, int completeRef)
+                    throws DatabaseException {
+                        ClusterI.CompleteTypeEnum oCompleteType = ClusterTraits.completeReferenceGetType(completeRef);
+                        if (pCompleteType == oCompleteType) { // we have a match
+                            if (context != 0) { // we have an old match
+                                context = 0; // multiple objects for given type
+                                return true; // break loop
+                            }
+                            int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);
+                            int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);
+                            if (0 == clusterIndex) {
+                                context = modifier.execute(resourceIndex);
+                            } else {
+                                int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);
+                                context = modifier.execute(externalRef);
+                            }
+                        }
+                        return true; // continue looping
+                    }
+                    
+                }
+                ForeachObject t = new ForeachObject();
+                // CompleteRef is complete object set index.
+                Integer c = 0;
+                ct.foreachComplete(completeRef, t, c, support, modifier);
+                return c;
+            }
+            // one complete type element
+            ClusterI.CompleteTypeEnum completeType = ClusterTraits.completeReferenceGetType(completeRef);
+            if (pCompleteType != completeType)
+                return 0;
+            int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);
+            int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);
+            if (0 == clusterIndex) {
+                return modifier.execute(resourceIndex);
+            } else {
+                int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);
+                return modifier.execute(externalRef);
+            }
+        }
+        int i = STM_OFFSET + index;
+        int p1 = BitUtility.getHighInt(table[i]);
+        if (0 == p1)
+            return 0; // loop finished, no statements
+        int result = 0;
+        if (pRef == p1) {
+            int o1 = BitUtility.getLowInt(table[i]);
+            result = modifier.execute(o1);
+//            procedure.execute(graph, new ResourceImpl(null, modifier.execute(o1)));
+//            int externalRef;
+//            if (null == modifier)
+//             externalRef = o1;
+//            else
+//             externalRef = modifier.execute(callerThread, o1);
+//            if (procedure.execute(callerThread, context, externalRef))
+//             return true; // loop broken by procedure
+        }
+        int p2 = BitUtility.getHighInt(table[++i]);
+        if (0 == p2 || pRef != p2)
+            return result; // loop finished, one statements
+
+        // Many statements
+        if (result != 0) return -1;
+        
+           int o2 = BitUtility.getLowInt(table[i]);
+        return modifier.execute(o2);
+        
+//        return 0;
+//        int o2 = BitUtility.getLowInt(table[i]);
+//        int externalRef;
+//        if (null == modifier)
+//             externalRef = o2;
+//        else
+//             externalRef = modifier.execute(callerThread, o2);
+//        if (procedure.execute(callerThread, context, externalRef))
+//             return true; // loop broken by procedure
+//        return false; // loop finished
+//        procedure.execute(graph, new ResourceImpl(null, modifier.execute(o2)));
+    }
+    
+    public static void foreachObject(long[] table, int index,
+               final ReadGraphImpl graph, final SyncMultiProcedure<Resource> procedure,
+               final ClusterSupport support, final int pRef, final ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, final Modifier modifier)
+    throws DatabaseException {
+        if (DEBUG)
+            System.out.println("ResourceElement.foreachObject1: index=" + index);
+        if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {
+            int completeRef = getCompleteObjectRef(table, index);
+            if (0 == completeRef) {
+                       procedure.finished(graph);
+//                     graph.state.dec(0);
+                return; // no objects for given complete type
+            }
+            if (ClusterTraits.completeReferenceIsMultiple(completeRef)) {
+                // Multiple complete type statements.
+                if (DEBUG)
+                    System.out.println("ResourceElement.was complete 2");
+                class ForeachObject implements ClusterI.ObjectProcedure<Object> {
+                    @Override
+                    public boolean execute(Object context, int completeRef) throws DatabaseException {
+                        ClusterI.CompleteTypeEnum oCompleteType = ClusterTraits.completeReferenceGetType(completeRef);
+                        if (pCompleteType == oCompleteType) {
+                            int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);
+                            int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);
+                            if (0 == clusterIndex) {
+                                procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(resourceIndex)));
+                            } else {
+                                int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);
+                                procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(externalRef)));
+                            }
+                        }
+                        return false; // continue looping
+                    }
+                    
+                }
+                ForeachObject t = new ForeachObject();
+                // CompleteRef is complete object set index.
+                ct.foreachComplete(completeRef, t, null, support, modifier);
+                procedure.finished(graph);
+//                graph.state.dec(0);
+                return; // loop finished
+            }
+            // one complete type element
+            ClusterI.CompleteTypeEnum completeType = ClusterTraits.completeReferenceGetType(completeRef);
+            if (pCompleteType != completeType) {
+                       procedure.finished(graph);
+//                     graph.state.dec(0);
+                return;
+            }
+            int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);
+            int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);
+            if (0 == clusterIndex) {
+                procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(resourceIndex)));
+            } else {
+                int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);
+                procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(externalRef)));
+            }
+               procedure.finished(graph);
+//             graph.state.dec(0);
+            return; // loop finished
+        }
+        int i = STM_OFFSET + index;
+        long l = table[i];
+        int p1 = (int) (l >>> 32);
+        if (0 == p1) {
+               procedure.finished(graph);
+//             graph.state.dec(0);
+            return; // loop finished, no statements
+        }
+        if (pRef == p1) {
+            int o1 = (int)l;
+            procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o1)));
+//            int externalRef;
+//            if (null == modifier)
+//             externalRef = o1;
+//            else
+//             externalRef = modifier.execute(callerThread, o1);
+//            if (procedure.execute(callerThread, context, externalRef))
+//             return true; // loop broken by procedure
+        }
+        long l2 = table[++i];
+        int p2 = (int) (l2 >>> 32);
+        if (pRef != p2) {
+               procedure.finished(graph);
+//             graph.state.dec(0);
+            return; // loop finished, one statements
+        }
+        int o2 = (int)l2;
+        procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o2)));
+               procedure.finished(graph);
+//             graph.state.dec(0);
+    }
+
+    public static <C> void foreachObject(long[] table, int index,
+               final ReadGraphImpl graph, final C context, final SyncContextMultiProcedure<C, Resource> procedure,
+               final ClusterSupport support, final int pRef, final ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, final Modifier modifier)
+    throws DatabaseException {
+        if (DEBUG)
+            System.out.println("ResourceElement.foreachObject1: index=" + index);
+        if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {
+            int completeRef = getCompleteObjectRef(table, index);
+            if (0 == completeRef) {
+                       procedure.finished(graph, context);
+//                     graph.state.dec(0);
+                return; // no objects for given complete type
+            }
+            if (ClusterTraits.completeReferenceIsMultiple(completeRef)) {
+                // Multiple complete type statements.
+                if (DEBUG)
+                    System.out.println("ResourceElement.was complete 2");
+                class ForeachObject implements ClusterI.ObjectProcedure<Object> {
+                    @Override
+                    public boolean execute(Object _context, int completeRef) throws DatabaseException {
+                        ClusterI.CompleteTypeEnum oCompleteType = ClusterTraits.completeReferenceGetType(completeRef);
+                        if (pCompleteType == oCompleteType) {
+                            int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);
+                            int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);
+                            if (0 == clusterIndex) {
+                                procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(resourceIndex)));
+                            } else {
+                                int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);
+                                procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(externalRef)));
+                            }
+                        }
+                        return false; // continue looping
+                    }
+                    
+                }
+                ForeachObject t = new ForeachObject();
+                // CompleteRef is complete object set index.
+                ct.foreachComplete(completeRef, t, null, support, modifier);
+                procedure.finished(graph, context);
+//                graph.state.dec(0);
+                return; // loop finished
+            }
+            // one complete type element
+            ClusterI.CompleteTypeEnum completeType = ClusterTraits.completeReferenceGetType(completeRef);
+            if (pCompleteType != completeType) {
+                       procedure.finished(graph, context);
+//                     graph.state.dec(0);
+                return;
+            }
+            int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);
+            int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);
+            if (0 == clusterIndex) {
+                procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(resourceIndex)));
+            } else {
+                int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);
+                procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(externalRef)));
+            }
+               procedure.finished(graph, context);
+//             graph.state.dec(0);
+            return; // loop finished
+        }
+        int i = STM_OFFSET + index;
+        long l = table[i];
+        int p1 = (int) (l >>> 32);
+        if (0 == p1) {
+               procedure.finished(graph, context);
+//             graph.state.dec(0);
+            return; // loop finished, no statements
+        }
+        if (pRef == p1) {
+            int o1 = (int)l;
+            procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o1)));
+//            int externalRef;
+//            if (null == modifier)
+//             externalRef = o1;
+//            else
+//             externalRef = modifier.execute(callerThread, o1);
+//            if (procedure.execute(callerThread, context, externalRef))
+//             return true; // loop broken by procedure
+        }
+        long l2 = table[++i];
+        int p2 = (int) (l2 >>> 32);
+        if (pRef != p2) {
+               procedure.finished(graph, context);
+//             graph.state.dec(0);
+            return; // loop finished, one statements
+        }
+        int o2 = (int)l2;
+        procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o2)));
+               procedure.finished(graph, context);
+//             graph.state.dec(0);
+    }
+    
+    public static <Context> boolean foreachObject(long[] table, int index
+               , ClusterI.ObjectProcedure<Context> procedure
+               , Context context, ClusterSupport support, Modifier modifier
+               , final int pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct)
+    throws DatabaseException {
+        if (DEBUG)
+            System.out.println("ResourceElement.foreachObject2: 1 ");
+        if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {
+            int completeRef = getCompleteObjectRef(table, index);
+            if (0 == completeRef) {
+                if (DEBUG)
+                    System.out.println("ResourceElement.foreachObject2: no complete");
+                return false; // no objects for given complete type
+            }
+            if (ClusterTraits.completeReferenceIsMultiple(completeRef)) { // multiple complete type elements
+                if (DEBUG)
+                    System.out.println("ResourceElement.foreachObject2: multi-complete ci=" + completeRef);
+                return ct.foreachObject(completeRef, procedure, context, support, modifier, pCompleteType);
+            }
+            // one complete type element
+            ClusterI.CompleteTypeEnum completeType = ClusterTraits.completeReferenceGetType(completeRef);
+            if (pCompleteType != completeType) {
+                if (DEBUG)
+                    System.out.println("ResourceElement.foreachObject2: complete different predicate");
+                return false;
+            }
+            int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);
+            int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);
+            if (0 == clusterIndex) {
+                int externalRef;
+                if (null == modifier)
+                    externalRef = resourceIndex;
+                else
+                    externalRef = modifier.execute(resourceIndex);
+                if (DEBUG)
+                    System.out.println("ResourceElement.foreachObject2: complete ok=" + externalRef);
+                if (procedure.execute(context, externalRef))
+                    return true; // loop broken by procedure
+            } else {
+                int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);
+                if (null != modifier)
+                    externalRef = modifier.execute(externalRef);
+                if (DEBUG)
+                    System.out.println("ResourceElement.foreachObject2: complete ok=" + externalRef);
+                if (procedure.execute(context, externalRef))
+                    return true; // loop broken by procedure
+            }
+            return false; // loop finished
+        }
+        int i = STM_OFFSET + index;
+        int p1 = BitUtility.getHighInt(table[i]);
+        if (0 == p1) {
+            if (DEBUG)
+                System.out.println("ResourceElement.foreachObject2: empty cache=");
+            return false; // loop finished, no statements
+        }
+        if (pRef == p1) {
+            int o1 = BitUtility.getLowInt(table[i]);
+            int externalRef;
+            if (null == modifier)
+               externalRef = o1;
+            else
+               externalRef = modifier.execute(o1);
+            if (DEBUG)
+                System.out.println("ResourceElement.foreachObject2: cache1 ok=" + externalRef);
+            if (procedure.execute(context, externalRef))
+               return true; // loop broken by procedure
+        }
+        int p2 = BitUtility.getHighInt(table[++i]);
+        if (0 == p2 || pRef != p2) {
+            if (DEBUG)
+                System.out.println("ResourceElement.foreachObject2: not in cache1");
+            return false; // loop finished, one statements
+        }
+        int o2 = BitUtility.getLowInt(table[i]);
+        int externalRef;
+        if (null == modifier)
+               externalRef = o2;
+        else
+               externalRef = modifier.execute(o2);
+        if (DEBUG)
+            System.out.println("ResourceElement.foreachObject2: cache2 ok=" + externalRef);
+        return procedure.execute(context, externalRef);
+    }
+    static boolean isEmpty(long[] table, int index) {
+        return getStatementCount(table, index) == 0 && !hasValue(table, index);
+    }
+    static int getStatementCount(long[] table, int index) {
+        int i = STM_OFFSET + index;
+        int p1 = BitUtility.getHighInt(table[i]);
+        int p2 = BitUtility.getLowInt(table[++i]);
+        if (0 == p1)
+            return 0;
+        else if (0 == p2)
+            return 1;
+        int predicateIndex = getPredicateIndex(table, index);
+        if (0 == predicateIndex)
+            return 2;
+        return 3;
+    }
+    private static int makeCompleteObjectRef(int oRef, ClusterI.CompleteTypeEnum completeType) {
+        int ref;
+        if (oRef > 0) {
+            int resourceIndex = oRef; 
+            int clusterIndex = 0;
+            ref = ClusterTraits.completeReferenceMake(completeType.getValue(), resourceIndex, clusterIndex);
+        } else {
+            assert(oRef < 0);
+            assert(!ClusterTraits.isFlat(oRef));
+            ref = (completeType.getValue() <<30) | (oRef & 0x3FFFFFFF);
+        }
+        return ref;
+    }
+    static int addStatement(long[] table, int index, int pRef, int oRef
+            , PredicateTable pt, ObjectTable ot
+            , ClusterI.CompleteTypeEnum completeType, CompleteTable ct)
+    throws DatabaseException {
+        assert (0 != pRef);
+        assert (0 != oRef);
+        if (ClusterI.CompleteTypeEnum.NotComplete != completeType) {
+            int cRef = makeCompleteObjectRef(oRef, completeType);
+            int ctr = getCompleteObjectRef(table, index);
+            if (0 == ctr)
+                setCompleteObjectRef(table, index, cRef);
+            else {
+                int nRef;
+                if (ctr == cRef)
+                    return -1; // old complete
+                else if (ClusterTraits.completeReferenceIsMultiple(ctr)) {
+                    nRef = ct.addComplete(ctr, cRef);
+                    if (0 == nRef)
+                        return -1; // old complete
+                } else {
+                    nRef = ct.createCompleteArraySet(ctr, cRef);
+                }
+                setCompleteObjectRef(table, index, nRef);
+            }
+            return 0; // added to complete
+        }
+        int i = STM_OFFSET + index;
+        int p1 = BitUtility.getHighInt(table[i]);
+        int o1 = BitUtility.getLowInt(table[i]);
+        if (0 == p1) {
+            table[i] = BitUtility.setLowAndHighInt(table[i], oRef, pRef);
+            return 0; // added to stm cache
+        } else if (p1 == pRef && o1 == oRef)
+            return -1; // same statement
+        int p2 = BitUtility.getHighInt(table[++i]);
+        int o2 = BitUtility.getLowInt(table[i]);
+        if (0 == p2) {
+            table[i] = BitUtility.setLowAndHighInt(table[i], oRef, pRef);
+            return 0; // added to stm cache
+        } else if (p2 == pRef && o2 == oRef)
+            return -1; // same statement
+        int predicateIndex = getPredicateIndex(table, index);
+        if (0 == predicateIndex) {
+            if (p1 == p2) {
+                int objectIndex = ot.createObjectSet(o1, o2);
+                assert (0 != objectIndex);
+                int[] os = new int[1];
+                os[0] = ClusterTraits.statementIndexMake(objectIndex);
+                int[] ps = new int[1];
+                ps[0] = p1;
+                predicateIndex = pt.createPredicateSet(ps, os);
+            } else {
+                int[] os = new int[2];
+                os[0] = o1; 
+                os[1] = o2;
+                int[] ps = new int[2];
+                ps[0] = p1;
+                ps[1] = p2;
+                predicateIndex = pt.createPredicateSet(ps, os);
+            }
+            assert (0 != predicateIndex);
+            setPredicateIndex(table, index, predicateIndex);
+        }
+        assert (0 != predicateIndex);
+        return predicateIndex;
+    }
+
+    static boolean removeStatement(long[] table, int index, int pRef, int oRef,
+               ClusterI.CompleteTypeEnum completeType, CompleteTable ct)
+    throws DatabaseException {
+        assert (0 != pRef);
+        assert (0 != oRef);
+        if (completeType != ClusterI.CompleteTypeEnum.NotComplete) {
+            int completeRef = ResourceElement.getCompleteObjectRef(table, index);
+            if (0 != completeRef) {
+               ClusterI.CompleteTypeEnum completeType2 = ClusterTraits.completeReferenceGetType(completeRef);
+                if (completeType == completeType2) {
+                    int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);
+                    int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);
+                    if (0 == clusterIndex) {
+                        if (oRef == resourceIndex) {
+                            ResourceElement.setCompleteObjectRef(table, index, 0);
+                            return true; // statement removed
+                        }
+                    } else {
+                        int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);
+                        if (oRef == externalRef) {
+                            ResourceElement.setCompleteObjectRef(table, index, 0);
+                            return true; // statement removed
+                        }
+                    }
+                } else if (completeType2 == ClusterI.CompleteTypeEnum.NotComplete) { // multiple complete type references 
+                    int cRef = makeCompleteObjectRef(oRef, completeType);
+                    int oldSize = ct.getCompleteSetSize(completeRef);
+                    int newSize = ct.removeComplete(completeRef, cRef);
+                    if (oldSize == newSize)
+                        return false; // not removed
+                    else if (newSize == 1) {
+                        cRef = ct.removeLast(completeRef);
+                        ResourceElement.setCompleteObjectRef(table, index, cRef);
+                    }
+                    return true; 
+                }
+            }
+        }
+        int i = STM_OFFSET + index;
+        int p1 = BitUtility.getHighInt(table[i]);
+        int o1 = BitUtility.getLowInt(table[i]);
+        if (0 == p1)
+            return false; // no statements cached
+        else if (p1 == pRef && o1 == oRef) {
+            table[i] = table[i + 1];
+            // BitUtility.setLowAndHighInt(table[i], 0, 0); optimized away
+            table[i + 1] = 0;
+            return true; // statement removed
+        }
+        int p2 = BitUtility.getHighInt(table[++i]);
+        int o2 = BitUtility.getLowInt(table[i]);
+        if (0 == p2)
+            return false; // no match
+        else if (p2 == pRef && o2 == oRef) {
+            // BitUtility.setLowAndHighInt(table[i], 0, 0); optimized away
+            table[i] = 0;
+            return true; // statement removed
+        }
+        return false;
+    }
+}
+
+public final class ResourceTable extends Table<long[]> {
+    public ResourceTable(TableSizeListener sizeListener, int[] header, int headerBase) {
+        super(TableFactory.getLongFactory(), sizeListener, header, headerBase);
+    }
+
+    public ResourceTable(TableSizeListener sizeListener, int[] header, int headerBase, long[] longs) {
+        super(TableFactory.getLongFactory(), sizeListener, header, headerBase, longs);
+    }
+
+    public int getUsedSize() {
+        return getTableCount();
+    }
+
+    public short createResource() {
+        final int INDEX = getTableCount();
+        final int SIZE = ResourceElement.getSizeOf();
+        int resourceIndex = createNewElement(SIZE);
+        assert (0 != resourceIndex);
+        final int REAL_INDEX = checkIndexAndGetRealIndex(resourceIndex, SIZE);
+        ResourceElement.construct(getTable(), REAL_INDEX);
+        incResourceCount();
+        return (short)(INDEX + ZERO_SHIFT);
+    }
+
+    void createResource(int resourceIndex) {
+        final int tableCount = getTableCount();
+        if (resourceIndex <= tableCount) { // old index
+            int realIndex = checkIndexAndGetRealIndex(resourceIndex);
+            if (ResourceElement.isEmpty(getTable(), realIndex))
+                return;
+        } if (resourceIndex == tableCount+1) {
+            createResource();
+            return;
+        }
+        throw new InternalError("Trying to create resource with illegal index=" + resourceIndex);
+    }
+
+//    void deleteResource(int resourceIndex) {
+//        int realIndex = checkIndexAndGetRealIndex(resourceIndex);
+//        ResourceElement.destruct(getTable(), realIndex);
+//        decResourceCount();
+//    }
+
+    public int getCompleteObjectRef(int resourceIndex) {
+        int realIndex = checkIndexAndGetRealIndex(resourceIndex);
+        return ResourceElement.getCompleteObjectRef(getTable(), realIndex);
+    }
+    
+    public int getPredicateIndex(int resourceIndex) {
+        int i = (resourceIndex<<2) - 3 + offset;
+        return (int)table[i];
+    }
+
+    public void setPredicateIndex(int resourceIndex, int predicateIndex) {
+        int realIndex = checkIndexAndGetRealIndex(resourceIndex);
+        ResourceElement.setPredicateIndex(getTable(), realIndex, predicateIndex);
+    }
+
+    public byte[] getValue(ValueTable valueTable, int resourceIndex)
+    throws DatabaseException {
+        int realIndex = checkIndexAndGetRealIndex(resourceIndex);
+        return ResourceElement.getValue(valueTable, getTable(), realIndex);
+    }
+
+//KRAA:
+//    int getString(ValueTable valueTable, int resourceIndex, char[] chars)
+//    throws DatabaseException {
+//        //int realIndex = checkIndexAndGetRealIndex(resourceIndex);
+//        return ResourceElement.getString(valueTable, getTable(), 4 * resourceIndex - 3 + offset, chars);
+//    }
+
+    public boolean hasValue(int resourceIndex) {
+        int realIndex = checkIndexAndGetRealIndex(resourceIndex);
+        return ResourceElement.hasValue(getTable(), realIndex);
+    }
+
+//    boolean hasValue(ValueTable valueTable, int resourceIndex, byte[] value) {
+//        int realIndex = checkIndexAndGetRealIndex(resourceIndex);
+//        return ResourceElement.hasValue(valueTable, getTable(), realIndex, value);
+//    }
+
+    public boolean removeValue(ValueTable valueTable, int resourceIndex) {
+        int realIndex = checkIndexAndGetRealIndex(resourceIndex);
+        boolean ret = ResourceElement.removeValue(valueTable, getTable(), realIndex);
+//        if (ret && !ResourceElement.isUsed(getTable(), realIndex))
+//            decResourceCount();
+        return ret;
+    }
+
+    public void setValue(ValueTable valueTable, int resourceIndex, byte[] value, int length) {
+        int realIndex = checkIndexAndGetRealIndex(resourceIndex);
+        ResourceElement.setValue(valueTable, getTable(), realIndex, value, length);
+    }
+
+    public boolean isValueEx(ValueTable valueTable, int resourceIndex) {
+        int realIndex = checkIndexAndGetRealIndex(resourceIndex);
+        return ResourceElement.isValueEx(valueTable, getTable(), realIndex);
+    }
+
+    public void setValueEx(ValueTable valueTable, int resourceIndex) {
+        int realIndex = checkIndexAndGetRealIndex(resourceIndex);
+        ResourceElement.setValueEx(valueTable, getTable(), realIndex);
+    }
+
+    static final int RESOURCE_COUNT_INDEX = 0;
+    static final int FOREIGN_COUNT_INDEX = 1; // Reserved by server.
+    static final int CLUSTER_STATUS_INDEX = 2;
+
+    int incResourceCount() {
+        int count = getExtra(RESOURCE_COUNT_INDEX) + 1;
+        setExtra(RESOURCE_COUNT_INDEX, count);
+        return count;
+    }
+
+//    int decResourceCount() {
+//        int count = getExtra(RESOURCE_COUNT_INDEX) - 1;
+//        setExtra(RESOURCE_COUNT_INDEX, count);
+//        return count;
+//    }
+
+    public int getResourceCount() {
+        return getExtra(RESOURCE_COUNT_INDEX);
+    }
+    public int getClusterStatus() {
+        return getExtra(CLUSTER_STATUS_INDEX);
+    }
+    public void setClusterStatus(int value) {
+        setExtra(CLUSTER_STATUS_INDEX, value);
+    }
+    void analyse() {
+
+       final int tsize = getTableSize();
+       final int esize = ResourceElement.getSizeOf();
+       long[] table = getTable();
+       for (int i = getTableBase(); i < getTableBase() + tsize; i += esize) {
+               if (ResourceElement.isUsed(getTable(), i)) {
+                       System.out.println("  -" + Long.toHexString(table[i]) + " " + Long.toHexString(table[i+1]) + " " + Long.toHexString(table[i+2]) + " " + Long.toHexString(table[i+3]));
+               }
+       }
+
+    }
+    
+    public <Context> boolean foreachResource(ClusterI.ObjectProcedure<Context> procedure, Context context,
+            ClusterSupport support, Modifier modifier) throws DatabaseException {
+        final int tsize = getTableSize();
+//        final int rsize = getResourceCount();
+        final int esize = ResourceElement.getSizeOf();
+        //int count = 0;
+        int key = ZERO_SHIFT;
+        for (int i = getTableBase(); i < getTableBase() + tsize; i += esize, ++key) {
+            if (ResourceElement.isUsed(getTable(), i)) {
+               int ref;
+               if (null == modifier)
+                       ref = key;
+               else
+                       ref = modifier.execute(key);
+                if (procedure.execute(context, ref))
+                    return true; // loop was broken by procedure
+//                if (rsize == ++count)
+//                     return false; // loop finished
+            }
+        }
+        //assert(rsize == count);
+        return false; // loop finished
+    }
+
+    public <Context> boolean foreachPredicate(int resourceIndex
+               , ClusterI.PredicateProcedure<Context> procedure, Context context
+               , ClusterSupport support, Modifier modifier, CompleteTable ct)
+    throws DatabaseException {
+        int realIndex = checkIndexAndGetRealIndex(resourceIndex);
+        return ResourceElement.foreachPredicate(getTable(), realIndex
+                       , procedure, context, support, modifier, ct);
+    }
+
+    public int getSingleObject(int resourceIndex, ClusterSupport support, int pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, Modifier modifier) throws DatabaseException {
+//        return ResourceElement.getSingleObject(table, realIndex, support, pRef, pCompleteType, ct, modifier);
+        return ResourceElement.getSingleObject(table, 4 * resourceIndex - 3 + offset, support, pRef, pCompleteType, ct, modifier);
+    }
+
+    public void foreachObject(int resourceIndex, ReadGraphImpl graph,
+               SyncMultiProcedure<Resource> procedure, ClusterSupport support, int pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, Modifier modifier) throws DatabaseException {
+        int realIndex = checkIndexAndGetRealIndex(resourceIndex);
+        ResourceElement.foreachObject(table, realIndex, graph, procedure, support,
+                       pRef, pCompleteType, ct, modifier);
+    }
+
+    public <C> void foreachObject(int resourceIndex, ReadGraphImpl graph, C context,
+               SyncContextMultiProcedure<C, Resource> procedure, ClusterSupport support, int pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, Modifier modifier) throws DatabaseException {
+        int realIndex = checkIndexAndGetRealIndex(resourceIndex);
+        ResourceElement.foreachObject(table, realIndex, graph, context, procedure, support,
+                       pRef, pCompleteType, ct, modifier);
+    }
+    
+    public <Context> boolean foreachObject(int resourceIndex
+               , ClusterI.ObjectProcedure<Context> procedure, Context context
+               , ClusterSupport support, Modifier modifier,
+               int pRef, ClusterI.CompleteTypeEnum completeType, CompleteTable ct)
+    throws DatabaseException {
+        int realIndex = checkIndexAndGetRealIndex(resourceIndex);
+        return ResourceElement.foreachObject(table, realIndex
+                       , procedure, context, support, modifier
+                       , pRef, completeType, ct);
+    }
+    public int addStatement(int resourceIndex, int pRef, int oRef, PredicateTable pt, ObjectTable ot
+            , ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct)
+            throws DatabaseException {
+        int realIndex = checkIndexAndGetRealIndex(resourceIndex);
+        return ResourceElement.addStatement(getTable(), realIndex, pRef, oRef, pt, ot, pCompleteType, ct);
+    }
+
+    public boolean removeStatementFromCache(int resourceIndex, int pRef, int oRef,
+               ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct)
+    throws DatabaseException {
+        int realIndex = checkIndexAndGetRealIndex(resourceIndex);
+        boolean ret = ResourceElement.removeStatement(getTable(), realIndex, pRef, oRef, pCompleteType, ct);
+//        if (ret && !ResourceElement.isUsed(getTable(), realIndex))
+//            decResourceCount();
+        return ret;
+    }
+    
+    public void removeStatement(int resourceIndex, int pRef, int oRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct,
+            PredicateTable pt, ObjectTable ot, ClusterBase cluster, ClusterSupport support)
+            throws DatabaseException {
+        int realIndex = checkIndexAndGetRealIndex(resourceIndex);
+        boolean removed = ResourceElement.removeStatement(getTable(), realIndex,
+                pRef, oRef, pCompleteType, ct);
+        if (!removed)
+            return;
+        int predicateIndex = ResourceElement.getPredicateIndex(getTable(), realIndex);
+        if (0 == predicateIndex) {
+//            if (!ResourceElement.isUsed(getTable(), realIndex))
+//                decResourceCount();
+            return;
+        }
+        GetStatements gs = new GetStatements(ot);
+        pt.foreachPredicate(predicateIndex, gs, null, null, null);
+        ArrayList<Statement> stms = gs.getStatements();
+
+        final int SIZE = stms.size();
+        if (SIZE < 3) {
+            for (int i = 0; i < SIZE; ++i) {
+                Statement stm = stms.get(i);
+                PredicateTable.Status ret = pt.removePredicate(predicateIndex,
+                        stm.pRef, stm.oIndex, ot);
+                if (ret == Status.NothingRemoved)
+                    throw new DatabaseException("Internal error during statement cache fix (2).");
+                int predicateKey = cluster.makeResourceKey(stm.pRef);
+                int completeTypeInt = ClusterTraitsBase.getCompleteTypeIntFromResourceKey(predicateKey);
+                ClusterI.CompleteTypeEnum completeType = CompleteTypeEnum.make(completeTypeInt);
+                int pi = ResourceElement.addStatement(getTable(), realIndex, stm.pRef, stm.oIndex,
+                        pt, ot, completeType, ct);
+                assert(0 >= pi);
+            }
+            assert(0 == pt.getPredicateSetSize(predicateIndex));
+            ResourceElement.setPredicateIndex(getTable(), realIndex, 0);
+        } else {
+            for (int i = 0; i < SIZE; ++i) {
+                Statement stm = stms.get(i);
+                int predicateKey = cluster.makeResourceKey(stm.pRef);
+                int completeTypeInt = ClusterTraitsBase.getCompleteTypeIntFromResourceKey(predicateKey);
+                ClusterI.CompleteTypeEnum completeType = CompleteTypeEnum.make(completeTypeInt);
+                int pIndex = ResourceElement.addStatement(getTable(), realIndex,
+                        stm.pRef, stm.oIndex, pt, ot, completeType, ct);
+                if (pIndex > 0)
+                    return; // cache fixed and full, p and o sets in use
+            }
+            throw new DatabaseException("Internal error during statement cache fix (3).");
+        }
+//        if (!ResourceElement.isUsed(getTable(), realIndex))
+//            decResourceCount();
+    }
+
+    //(i-1)*4+1 + 4
+    private int checkIndexAndGetRealIndex(final int INDEX) {
+        assert(INDEX > 0);
+        assert(INDEX <= getTableCount());
+//        final int TABLE_INDEX = (INDEX - ZERO_SHIFT) * ResourceElement.getSizeOf() + ZERO_SHIFT;
+//        final int TABLE_INDEX = (INDEX - ZERO_SHIFT) * ResourceElement.getSizeOf() + ZERO_SHIFT;
+//        return checkIndexAndGetRealIndex(TABLE_INDEX, ResourceElement.getSizeOf());
+        return 4 * INDEX - 3 + offset;
+    }
+       public void check(ClusterBase cluster)
+       throws DatabaseException {
+//        int count = 0;
+           cluster.checkValueInit();
+        long[] table = getTable();
+        int ps = getHeader().getOffset() + ZERO_SHIFT;
+        final int TABLE_SIZE = getTableSize();
+        int pe = ps + TABLE_SIZE;
+        for (int p=ps; p<pe; p+=ResourceElement.getSizeOf()) {
+               if (!ResourceElement.isUsed(table, p))
+                       continue;
+               int cr = ResourceElement.getCompleteObjectRef(table, p);
+               if (0 != cr) {
+                       if (ClusterTraits.completeReferenceIsMultiple(cr))
+                               cluster.checkCompleteSetReference(cr);
+                       else {
+                       int fi = ClusterTraits.completeReferenceGetForeignIndex(cr);
+                       int ri = ClusterTraits.completeReferenceGetResourceIndex(cr);
+                       if (0 != fi)
+                               cluster.checkForeingIndex(fi);
+                       else if (ri < 1 || ri > TABLE_SIZE)
+                               throw new ValidationException("Illegal resource index=" + ri);
+                       }
+               }
+               int pi = ResourceElement.getPredicateIndex(table, p);
+               if (0 != pi) {
+                   cluster.checkPredicateIndex(pi);
+               }
+               ResourceElement.ValueData vd = new ResourceElement.ValueData();
+               ResourceElement.getValueCapacityAndIndex(vd, table, p);
+               cluster.checkValue(vd.capacity, vd.index);
+        }
+        cluster.checkValueFini();
+       }
+
+    @Override
+    public <Context> boolean foreach(int setIndex, Procedure procedure, Context context,
+            ClusterSupport support, Modifier modifier) throws DatabaseException {
+        throw new UnsupportedOperationException();
+    }
+}
+
+class Statement {
+    Statement(int pRef, int oIndex) {
+        this.pRef = pRef;
+        this.oIndex = oIndex;
+    }
+    final int pRef;
+    final int oIndex;
+}
+
+class CalculateStatements
+implements ClusterI.PredicateProcedure<CalculateStatements> {
+    private ObjectTable         ot;
+    private final int           sRef;
+
+    CalculateStatements(int sRef, ObjectTable ot) {
+        this.sRef = sRef;
+        this.ot = ot;
+    }
+
+    @Override
+    public boolean execute(final CalculateStatements context
+            , final int pKey, int oIndex) {
+        if (ClusterTraits.statementIndexIsDirect(oIndex))
+            return false; // osize = 1
+        try {
+            oIndex = ClusterTraits.statementIndexGet(oIndex);
+        } catch (DatabaseException e) {
+            Logger.getDefault().logError("Missing object set for s="
+                    + sRef + " p=" + pKey, null);
+            return false; // continue looping
+        }
+        int osize = ot.getObjectSetSize(oIndex);
+        if (osize == 3 || osize > 9)
+            System.out.println("Resource " + sRef + " predicate " + pKey + " has "
+                    + osize + " objects.");
+        return true; // break loop
+    }
+}
+
+class GetStatements implements PredicateProcedure<Object>, ObjectProcedure<Integer> {
+    private ObjectTable         ot;
+    private final ArrayList<Statement> stms = new ArrayList<Statement>(); 
+    GetStatements(ObjectTable ot) {
+        this.ot = ot;
+    }
+    ArrayList<Statement> getStatements() {
+        return stms;
+    }
+    @Override
+    public boolean execute(Object context, int pRef, int oIndex) {
+        try {
+            ot.foreachObject(oIndex, this, pRef, null, null);
+        } catch (DatabaseException e) {
+            e.printStackTrace();
+            return false; // continue looping
+        }
+        if (stms.size() > 2)
+            return true; // break loop
+        return false; // continue looping
+    }
+
+    @Override
+    public boolean execute(Integer pRef, int oRef) {
+        stms.add(new Statement(pRef, oRef));
+        if (stms.size() > 2)
+            return true; // break loop
+        return false; // continue looping
+    }
+    
+}