X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.db.procore%2Fsrc%2Forg%2Fsimantics%2Fdb%2Fprocore%2Fcluster%2FResourceTable.java;fp=bundles%2Forg.simantics.db.procore%2Fsrc%2Forg%2Fsimantics%2Fdb%2Fprocore%2Fcluster%2FResourceTable.java;h=a36f54d056ac3de5a90915b0a4f55ed6bb3c387d;hp=0000000000000000000000000000000000000000;hb=969bd23cab98a79ca9101af33334000879fb60c5;hpb=866dba5cd5a3929bbeae85991796acb212338a08 diff --git a/bundles/org.simantics.db.procore/src/org/simantics/db/procore/cluster/ResourceTable.java b/bundles/org.simantics.db.procore/src/org/simantics/db/procore/cluster/ResourceTable.java new file mode 100644 index 000000000..a36f54d05 --- /dev/null +++ b/bundles/org.simantics.db.procore/src/org/simantics/db/procore/cluster/ResourceTable.java @@ -0,0 +1,1236 @@ +/******************************************************************************* + * 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.AsyncMultiProcedure; +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 boolean foreachPredicate(long[] table, int index, + ClusterI.PredicateProcedure 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 { + @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 AsyncMultiProcedure 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 { + @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 void foreachObject(long[] table, int index, + final ReadGraphImpl graph, final C context, final AsyncContextMultiProcedure 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 { + @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); +// 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, 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); +// 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, 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); +// 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); +// graph.state.dec(0); + } + + public static boolean foreachObject(long[] table, int index + , ClusterI.ObjectProcedure 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 { + 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 boolean foreachResource(ClusterI.ObjectProcedure 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 boolean foreachPredicate(int resourceIndex + , ClusterI.PredicateProcedure 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, + AsyncMultiProcedure 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 void foreachObject(int resourceIndex, ReadGraphImpl graph, C context, + AsyncContextMultiProcedure 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 boolean foreachObject(int resourceIndex + , ClusterI.ObjectProcedure 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 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 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 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 { + 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, ObjectProcedure { + private ObjectTable ot; + private final ArrayList stms = new ArrayList(); + GetStatements(ObjectTable ot) { + this.ot = ot; + } + ArrayList 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 + } + +}