/******************************************************************************* * 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.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.SyncContextMultiProcedure; import org.simantics.db.procedure.SyncMultiProcedure; import org.simantics.db.procore.cluster.PredicateTable.Status; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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 SyncMultiProcedure 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 SyncContextMultiProcedure 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 { @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 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, SyncMultiProcedure 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, SyncContextMultiProcedure 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 static final Logger LOGGER = LoggerFactory.getLogger(CalculateStatements.class); 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.error("Missing object set for s=" + sRef + " p=" + pKey, e); 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 } }