+/*******************************************************************************
+ * 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.acorn.cluster;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+
+import org.simantics.acorn.internal.ClusterChange;
+import org.simantics.acorn.internal.ClusterStream;
+import org.simantics.acorn.internal.ClusterSupport2;
+import org.simantics.acorn.internal.DebugPolicy;
+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.ClusterSupport;
+import org.simantics.db.impl.ClusterTraitsBase;
+import org.simantics.db.impl.ForEachObjectContextProcedure;
+import org.simantics.db.impl.ForEachObjectProcedure;
+import org.simantics.db.impl.ForPossibleRelatedValueContextProcedure;
+import org.simantics.db.impl.ForPossibleRelatedValueProcedure;
+import org.simantics.db.impl.IClusterTable;
+import org.simantics.db.impl.Table;
+import org.simantics.db.impl.TableHeader;
+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.ClusterMapSmall;
+import org.simantics.db.procore.cluster.ClusterTraits;
+import org.simantics.db.procore.cluster.ClusterTraitsSmall;
+import org.simantics.db.procore.cluster.CompleteTableSmall;
+import org.simantics.db.procore.cluster.ForeignTableSmall;
+import org.simantics.db.procore.cluster.ObjectTable;
+import org.simantics.db.procore.cluster.OutOfSpaceException;
+import org.simantics.db.procore.cluster.PredicateTable;
+import org.simantics.db.procore.cluster.ResourceTableSmall;
+import org.simantics.db.procore.cluster.ValueTableSmall;
+import org.simantics.db.service.Bytes;
+import org.simantics.db.service.ClusterUID;
+import org.simantics.db.service.ResourceUID;
+import org.simantics.utils.datastructures.Callback;
+
+import gnu.trove.map.hash.TIntShortHashMap;
+import gnu.trove.procedure.TIntProcedure;
+import gnu.trove.set.hash.TIntHashSet;
+
+final public class ClusterSmall extends ClusterImpl {
+ private static final int TABLE_HEADER_SIZE = TableHeader.HEADER_SIZE + TableHeader.EXTRA_SIZE;
+ private static final int RESOURCE_TABLE_OFFSET = 0;
+ private static final int PREDICATE_TABLE_OFFSET = RESOURCE_TABLE_OFFSET + TABLE_HEADER_SIZE;
+ private static final int OBJECT_TABLE_OFFSET = PREDICATE_TABLE_OFFSET + TABLE_HEADER_SIZE;
+ private static final int VALUE_TABLE_OFFSET = OBJECT_TABLE_OFFSET + TABLE_HEADER_SIZE;
+ private static final int FLAT_TABLE_OFFSET = VALUE_TABLE_OFFSET + TABLE_HEADER_SIZE;
+ private static final int COMPLETE_TABLE_OFFSET = FLAT_TABLE_OFFSET + TABLE_HEADER_SIZE;
+ private static final int FOREIGN_TABLE_OFFSET = COMPLETE_TABLE_OFFSET + TABLE_HEADER_SIZE;
+ private static final int INT_HEADER_SIZE = FOREIGN_TABLE_OFFSET + TABLE_HEADER_SIZE;
+ private final int clusterBits;
+ private final ResourceTableSmall resourceTable;
+ private final PredicateTable predicateTable;
+ private final ObjectTable objectTable;
+ private final ValueTableSmall valueTable;
+ private final ForeignTableSmall foreignTable;
+ private final CompleteTableSmall completeTable;
+ private final ClusterMapSmall clusterMap;
+ private final int[] headerTable;
+ public final ClusterSupport2 clusterSupport;
+ private boolean proxy;
+ private boolean deleted = false;
+
+ protected ClusterSmall() {
+ this.proxy = true;
+ this.headerTable = null;
+ this.resourceTable = null;
+ this.foreignTable = null;
+ this.predicateTable = null;
+ this.objectTable = null;
+ this.valueTable = null;
+ this.completeTable = null;
+ this.clusterMap = null;
+ this.clusterSupport = null;
+ this.clusterBits = 0;
+ this.importance = 0;
+ }
+
+ public ClusterSmall(IClusterTable clusterTable, ClusterUID clusterUID, int clusterKey, ClusterSupport2 support) {
+ super(clusterTable, clusterUID, clusterKey, support);
+ if(DebugPolicy.REPORT_CLUSTER_EVENTS)
+ new Exception(clusterUID.toString()).printStackTrace();
+ this.proxy = true;
+ this.headerTable = null;
+ this.resourceTable = null;
+ this.foreignTable = null;
+ this.predicateTable = null;
+ this.objectTable = null;
+ this.valueTable = null;
+ this.completeTable = null;
+ this.clusterMap = null;
+ this.clusterSupport = support;
+ this.clusterBits = 0;
+ this.importance = 0;
+// new Exception("ClusterSmall " + clusterKey).printStackTrace();
+ }
+ ClusterSmall(ClusterUID clusterUID, int clusterKey, ClusterSupport2 support, IClusterTable clusterTable) {
+ super(clusterTable, clusterUID, clusterKey, support);
+ if(DebugPolicy.REPORT_CLUSTER_EVENTS)
+ new Exception(clusterUID.toString()).printStackTrace();
+ this.proxy = false;
+ this.clusterSupport = support;
+ this.headerTable = new int[INT_HEADER_SIZE];
+ this.resourceTable = new ResourceTableSmall(this, headerTable, RESOURCE_TABLE_OFFSET);
+ this.foreignTable = new ForeignTableSmall(this, headerTable, FOREIGN_TABLE_OFFSET);
+ this.predicateTable = new PredicateTable(this, headerTable, PREDICATE_TABLE_OFFSET);
+ this.objectTable = new ObjectTable(this, headerTable, OBJECT_TABLE_OFFSET);
+ this.valueTable = new ValueTableSmall(this, headerTable, VALUE_TABLE_OFFSET);
+ this.completeTable = new CompleteTableSmall(this, headerTable, COMPLETE_TABLE_OFFSET);
+ this.clusterMap = new ClusterMapSmall(this, foreignTable);
+ this.clusterBits = ClusterTraitsBase.getClusterBits(clusterKey);
+// if(clusterTable != null)
+// this.importance = -clusterTable.timeCounter();
+// else
+ this.importance = 0;
+// new Exception("ClusterSmall " + clusterKey).printStackTrace();
+ }
+ protected ClusterSmall(IClusterTable clusterTable, long[] longs, int[] ints, byte[] bytes, ClusterSupport2 support, int clusterKey)
+ throws DatabaseException {
+ super(clusterTable, checkValidity(-1, longs, ints, bytes), clusterKey, support);
+ this.proxy = false;
+ this.clusterSupport = support;
+ if (ints.length < INT_HEADER_SIZE)
+ throw new IllegalArgumentException("Too small integer table for cluster.");
+ this.headerTable = ints;
+ if(DebugPolicy.REPORT_CLUSTER_EVENTS) new Exception(Long.toString(clusterId)).printStackTrace();
+ this.resourceTable = new ResourceTableSmall(this, ints, RESOURCE_TABLE_OFFSET, longs);
+ this.foreignTable = new ForeignTableSmall(this, headerTable, FOREIGN_TABLE_OFFSET, longs);
+ this.predicateTable = new PredicateTable(this, ints, PREDICATE_TABLE_OFFSET, ints);
+ this.objectTable = new ObjectTable(this, ints, OBJECT_TABLE_OFFSET, ints);
+ this.valueTable = new ValueTableSmall(this, ints, VALUE_TABLE_OFFSET, bytes);
+ this.completeTable = new CompleteTableSmall(this, headerTable, COMPLETE_TABLE_OFFSET, ints);
+ this.clusterMap = new ClusterMapSmall(this, foreignTable);
+ this.clusterBits = ClusterTraitsBase.getClusterBits(clusterKey);
+// if(clusterTable != null) {
+// this.importance = clusterTable.timeCounter();
+// clusterTable.markImmutable(this, getImmutable());
+// }
+// new Exception("ClusterSmall " + clusterKey).printStackTrace();
+ }
+ void analyse() {
+ System.out.println("Cluster " + clusterId);
+ System.out.println("-size:" + getUsedSpace());
+ System.out.println(" -rt:" + (resourceTable.getTableCapacity() * 8 + 8));
+ System.out.println(" -ft:" + foreignTable.getTableCapacity() * 8);
+ System.out.println(" -pt:" + predicateTable.getTableCapacity() * 4);
+ System.out.println(" -ot:" + objectTable.getTableCapacity() * 4);
+ System.out.println(" -ct:" + completeTable.getTableCapacity() * 4);
+ System.out.println(" -vt:" + valueTable.getTableCapacity());
+
+ System.out.println("-resourceTable:");
+ System.out.println(" -resourceCount=" + resourceTable.getResourceCount());
+ System.out.println(" -size=" + resourceTable.getTableSize());
+ System.out.println(" -capacity=" + resourceTable.getTableCapacity());
+ System.out.println(" -count=" + resourceTable.getTableCount());
+ System.out.println(" -size=" + resourceTable.getTableSize());
+ //resourceTable.analyse();
+ }
+ public void checkDirectReference(int dr)
+ throws DatabaseException {
+ if (!ClusterTraits.statementIndexIsDirect(dr))
+ throw new ValidationException("Reference is not direct. Reference=" + dr);
+ if (ClusterTraits.isFlat(dr))
+ throw new ValidationException("Reference is flat. Reference=" + dr);
+ if (ClusterTraits.isLocal(dr)) {
+ if (dr < 1 || dr > resourceTable.getUsedSize())
+ throw new ValidationException("Illegal local reference. Reference=" + dr);
+ } else {
+ int fi = ClusterTraits.getForeignIndexFromReference(dr);
+ int ri = ClusterTraits.getResourceIndexFromForeignReference(dr);
+ if (fi < 1 || fi > foreignTable.getUsedSize())
+ throw new ValidationException("Illegal foreign reference. Reference=" + dr + " foreign index=" + fi);
+ if (ri < 1 || ri > ClusterTraits.getMaxNumberOfResources())
+ throw new ValidationException("Illegal foreign reference. Reference=" + dr + " resource index=" + ri);
+ }
+ }
+ public void checkPredicateIndex(int pi)
+ throws DatabaseException {
+ // predicateTable.checkPredicateSetIndex(this, pi);
+ }
+ public void checkObjectSetReference(int or)
+ throws DatabaseException {
+ if (ClusterTraits.statementIndexIsDirect(or))
+ throw new ValidationException("Illegal object set reference. Reference=" + or);
+ int oi = ClusterTraits.statementIndexGet(or);
+ this.objectTable.checkObjectSetIndex(this, oi);
+ }
+
+ public void checkValueInit()
+ throws DatabaseException {
+ valueTable.checkValueInit();
+ }
+ public void checkValue(int capacity, int index)
+ throws DatabaseException {
+ valueTable.checkValue(capacity, index);
+ }
+ public void checkValueFini()
+ throws DatabaseException {
+ valueTable.checkValueFini();
+ }
+ public void checkForeingIndex(int fi)
+ throws DatabaseException {
+ if (fi<1 || fi > foreignTable.getUsedSize())
+ throw new ValidationException("Illegal foreign index=" + fi);
+ }
+ public void checkCompleteSetReference(int cr)
+ throws DatabaseException {
+ if (!ClusterTraits.completeReferenceIsMultiple(cr))
+ throw new ValidationException("Illegal complete set reference. Reference=" + cr);
+ int ci = cr;
+ this.completeTable.checkCompleteSetIndex(this, ci);
+ }
+ public void check()
+ throws DatabaseException {
+// this.completeTable.check(this);
+// this.objectTable.check(this);
+// // Must be after object table check.
+// this.predicateTable.check(this);
+// this.resourceTable.check(this);
+ }
+ @Override
+ public CompleteTypeEnum getCompleteType(int resourceKey, ClusterSupport support)
+ throws DatabaseException {
+ final int resourceRef = getLocalReference(resourceKey);
+ CompleteTypeEnum ct = resourceTable.getCompleteType(resourceRef);
+ if (DEBUG)
+ System.out.println("ClusterSmall.getCompleteType rk=" + resourceKey + " ct=" + ct);
+ return ct;
+ }
+
+ @Override
+ public int getCompleteObjectKey(int resourceKey, ClusterSupport support)
+ throws DatabaseException {
+ final int resourceIndexOld = getLocalReference(resourceKey);
+ short completeRef = resourceTable.getCompleteObjectRef(resourceIndexOld);
+ int clusterIndex;
+ int resourceIndex;
+ if (0 == completeRef)
+ throw new DatabaseException("Resource's complete object refernce is null. Resource key=" + resourceKey + ".");
+ ClusterI.CompleteTypeEnum completeType = resourceTable.getCompleteType(resourceIndexOld);
+ if (completeType == ClusterI.CompleteTypeEnum.NotComplete)
+ throw new DatabaseException("Resource has multiple complete objects. Resource key=" + resourceKey + ".");
+ if (ClusterTraitsSmall.resourceRefIsLocal(completeRef)) {
+ clusterIndex = clusterKey;
+ resourceIndex = completeRef;
+ } else { // Resource has one complete statement.
+ ResourceUID resourceUID = clusterMap.getForeignResourceUID(completeRef);
+ ClusterUID uid = resourceUID.asCID();
+ clusterIndex = clusterSupport.getClusterKeyByUID(0, uid.second);
+ //ClusterI c = clusterTable.getClusterByClusterUIDOrMakeProxy(uid);
+ //clusterIndex = c.getClusterKey();
+ //assert(clusterIndex == clusterTable.getClusterByClusterUIDOrMakeProxy(uid).getClusterKey());
+ resourceIndex = resourceUID.getIndex();
+ }
+ int key = ClusterTraits.createResourceKey(clusterIndex, resourceIndex);
+ if (DEBUG)
+ System.out.println("ClusterSmall.complete object rk=" + resourceKey + " ck=" + key);
+ return key;
+ }
+
+ @Override
+ public boolean isComplete(int resourceKey, ClusterSupport support)
+ throws DatabaseException {
+ final int resourceRef = getLocalReference(resourceKey);
+ final ClusterI.CompleteTypeEnum completeType = resourceTable.getCompleteType(resourceRef);
+ boolean complete = completeType != ClusterI.CompleteTypeEnum.NotComplete;
+ if (DEBUG)
+ System.out.println("ClusterSmall.key=" + resourceKey + " isComplete=" + complete);
+ return complete;
+ }
+ public int getSingleObject(int resourceKey, int predicateKey, int objectIndex, ClusterSupport support) throws DatabaseException {
+ if (DEBUG)
+ System.out.println("ClusterSmall.getSingleObject: rk=" + resourceKey + " pk=" + predicateKey);
+ if (0 == objectIndex) {
+ final int resourceIndex = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(resourceKey);
+ final short pRef = getInternalReferenceOrZero2(predicateKey, support);
+ final ClusterI.CompleteTypeEnum pCompleteType = ClusterTraitsBase.getCompleteTypeFromResourceKey(predicateKey);
+ return resourceTable.getSingleObject(resourceIndex, support, pRef, pCompleteType, completeTable, this);
+ }
+ return objectTable.getSingleObject(objectIndex, support, this);
+ }
+
+ public void forObjects(ReadGraphImpl graph, int resourceKey, int predicateKey, int objectIndex, AsyncMultiProcedure<Resource> procedure,
+ ClusterSupport support) throws DatabaseException {
+ if (DEBUG)
+ System.out.println("ClusterSmall.forObjects1: rk=" + resourceKey + " pk=" + predicateKey);
+ if (0 == objectIndex) {
+ final int resourceIndex = ClusterTraitsBase.getResourceIndexFromResourceKey(resourceKey);
+ final int pRef = getInternalReferenceOrZero2(predicateKey, support);
+ final ClusterI.CompleteTypeEnum pCompleteType = ClusterTraitsBase.getCompleteTypeFromResourceKey(predicateKey);
+ resourceTable.foreachObject(resourceIndex, graph, procedure, support, pRef, pCompleteType, completeTable, this);
+ return;
+ }
+ objectTable.foreachObject(graph, objectIndex, procedure, this);
+ }
+
+ public <C> void forObjects(ReadGraphImpl graph, int resourceKey, int predicateKey, int objectIndex, C context, AsyncContextMultiProcedure<C, Resource> procedure,
+ ClusterSupport support) throws DatabaseException {
+ if (DEBUG)
+ System.out.println("ClusterSmall.forObjects1: rk=" + resourceKey + " pk=" + predicateKey);
+ if (0 == objectIndex) {
+ final int resourceIndex = ClusterTraitsBase.getResourceIndexFromResourceKey(resourceKey);
+ final int pRef = getInternalReferenceOrZero2(predicateKey, support);
+ final ClusterI.CompleteTypeEnum pCompleteType = ClusterTraitsBase.getCompleteTypeFromResourceKey(predicateKey);
+ resourceTable.foreachObject(resourceIndex, graph, context, procedure, support, pRef, pCompleteType, completeTable, this);
+ return;
+ }
+ objectTable.foreachObject(graph, objectIndex, context, procedure, this);
+ }
+
+ @Override
+ public <Context> boolean forObjects(int resourceKey, int predicateKey, int objectIndex, ObjectProcedure<Context> procedure,
+ Context context, ClusterSupport support) throws DatabaseException {
+ if (DEBUG)
+ System.out.println("ClusterSmall.forObjects2: rk=" + resourceKey + " pk=" + predicateKey);
+ if (0 == objectIndex) {
+ final int resourceIndex = ClusterTraitsBase.getResourceIndexFromResourceKey(resourceKey);
+ final short pRef = getInternalReferenceOrZero2(predicateKey, support);
+ final ClusterI.CompleteTypeEnum pCompleteType = ClusterTraitsBase.getCompleteTypeFromResourceKey(predicateKey);
+ return resourceTable.foreachObject(resourceIndex, procedure, context, support, this, pRef, pCompleteType, completeTable);
+ }
+ return objectTable.foreachObject(objectIndex, procedure, context, support, this);
+ }
+
+ @Override
+ public int getSingleObject(int resourceKey, int predicateKey, ClusterSupport support) throws DatabaseException {
+ if (DEBUG)
+ System.out.println("ClusterSmall.getSingleObject2: rk=" + resourceKey + " pk=" + predicateKey);
+ final int resourceIndex = ClusterTraitsBase.getResourceIndexFromResourceKey(resourceKey);
+ final short pRef = getInternalReferenceOrZero2(predicateKey, support);
+ final int completeType = ClusterTraitsBase.getCompleteTypeIntFromResourceKey(predicateKey);
+ final ClusterI.CompleteTypeEnum pCompleteType = CompleteTypeEnum.make(completeType);
+ if (completeType > 0)
+ return resourceTable.getSingleObject(resourceIndex, support, pRef, pCompleteType, completeTable, this);
+ final int predicateIndex = (int)resourceTable.table[(resourceIndex<<1) - 1 + resourceTable.offset] & 0xFFFFFF;
+ if (0 == predicateIndex) // All relevant data is in resource table.
+ return resourceTable.getSingleObject(resourceIndex, support, pRef, pCompleteType, completeTable, this);
+ int objectIndex = predicateTable.getObjectIndex(predicateIndex, pRef & 0xFFFF);
+ return getSingleObject(resourceKey, predicateKey, objectIndex, support);
+ }
+
+ @Override
+ public <T> int getSingleObject(int resourceKey, ForPossibleRelatedValueProcedure<T> procedure, ClusterSupport support) throws DatabaseException {
+ final short resourceIndex = (short)ClusterTraitsBase.getResourceIndexFromResourceKey(resourceKey);
+ final int predicateKey = procedure.predicateKey;
+ int clusterKey = ClusterTraitsBase.getClusterMaskFromResourceKey(resourceKey);
+ short pRef = 0;
+ if(procedure.clusterKey[0] == clusterKey) {
+ pRef = (short)procedure.predicateReference[0];
+ } else {
+ pRef = getInternalReferenceOrZero2(predicateKey, support);
+ procedure.clusterKey[0] = clusterKey;
+ procedure.predicateReference[0] = pRef;
+ }
+
+ final ClusterI.CompleteTypeEnum pCompleteType = procedure.completeType;
+ if (CompleteTypeEnum.NotComplete != pCompleteType)
+ return resourceTable.getSingleObject(resourceIndex, support, pRef, pCompleteType, completeTable, this);
+ final int predicateIndex = (int)resourceTable.table[(resourceIndex<<1) - 1 + resourceTable.offset] & 0xFFFFFF;
+ if (0 == predicateIndex) // All relevant data is in resource table.
+ return resourceTable.getSingleObject(resourceIndex, support, pRef, pCompleteType, completeTable, this);
+ int objectIndex = predicateTable.getObjectIndex(predicateIndex, pRef & 0xFFFF);
+ return getSingleObject(resourceKey, predicateKey, objectIndex, support);
+ }
+
+ @Override
+ public <C, T> int getSingleObject(int resourceKey, ForPossibleRelatedValueContextProcedure<C, T> procedure, ClusterSupport support) throws DatabaseException {
+ final short resourceIndex = (short)ClusterTraitsBase.getResourceIndexFromResourceKey(resourceKey);
+ final int predicateKey = procedure.predicateKey;
+ int clusterKey = ClusterTraitsBase.getClusterMaskFromResourceKey(resourceKey);
+ short pRef = 0;
+ if(procedure.clusterKey[0] == clusterKey) {
+ pRef = (short)procedure.predicateReference[0];
+ } else {
+ pRef = getInternalReferenceOrZero2(predicateKey, support);
+ procedure.clusterKey[0] = clusterKey;
+ procedure.predicateReference[0] = pRef;
+ }
+ final ClusterI.CompleteTypeEnum pCompleteType = procedure.completeType;
+ if (CompleteTypeEnum.NotComplete != pCompleteType)
+ return resourceTable.getSingleObject(resourceIndex, support, pRef, pCompleteType, completeTable, this);
+ final int predicateIndex = (int)resourceTable.table[(resourceIndex<<1) - 1 + resourceTable.offset] & 0xFFFFFF;
+ if (0 == predicateIndex) // All relevant data is in resource table.
+ return resourceTable.getSingleObject(resourceIndex, support, pRef, pCompleteType, completeTable, this);
+ int objectIndex = predicateTable.getObjectIndex(predicateIndex, pRef & 0xFFFF);
+ return getSingleObject(resourceKey, predicateKey, objectIndex, support);
+ }
+
+ @Override
+ public void forObjects(ReadGraphImpl graph, int resourceKey,
+ int predicateKey, AsyncMultiProcedure<Resource> procedure) throws DatabaseException {
+
+ throw new UnsupportedOperationException();
+
+// SessionImplSocket session = (SessionImplSocket)graph.getSession();
+// ClusterSupport support = session.clusterTranslator;
+// if (DEBUG)
+// System.out.println("ClusterSmall.forObjects3: rk=" + resourceKey + " pk=" + predicateKey);
+// final int resourceIndex = ClusterTraitsBase.getResourceIndexFromResourceKey(resourceKey);
+// final int pRef = getInternalReferenceOrZero2(predicateKey, support);
+// final int completeType = ClusterTraitsBase.getCompleteTypeIntFromResourceKey(predicateKey);
+// final ClusterI.CompleteTypeEnum pCompleteType = CompleteTypeEnum.make(completeType);
+// if (completeType > 0) {
+// resourceTable.foreachObject(resourceIndex, graph, procedure, support, pRef, pCompleteType, completeTable, this);
+// return;
+// }
+// final int predicateIndex = (int)resourceTable.table[(resourceIndex<<1) - 1 + resourceTable.offset] & 0xFFFFFF;
+// if (0 == predicateIndex) {
+// resourceTable.foreachObject(resourceIndex, graph, procedure, support, pRef, pCompleteType, completeTable, this);
+// return;
+// }
+// int objectIndex = predicateTable.getObjectIndex(predicateIndex, pRef & 0xFFFF);
+// forObjects(graph, resourceKey, predicateKey, objectIndex, procedure, support);
+ }
+
+ public void forObjects(ReadGraphImpl graph, int resourceKey, ForEachObjectProcedure procedure) throws DatabaseException {
+
+ throw new UnsupportedOperationException();
+
+// final int resourceIndex = ClusterTraitsBase.getResourceIndexFromResourceKey(resourceKey);
+// final int predicateKey = procedure.predicateKey;
+// int clusterKey = ClusterTraitsBase.getClusterMaskFromResourceKey(resourceKey);
+// int pRef = 0;
+// if(procedure.clusterKey[0] == clusterKey) {
+// pRef = procedure.predicateReference[0];
+// } else {
+// SessionImplSocket session = (SessionImplSocket)graph.getSession();
+// ClusterSupport support = session.clusterTranslator;
+// pRef = getInternalReferenceOrZero2(predicateKey, support);
+// procedure.clusterKey[0] = clusterKey;
+// procedure.predicateReference[0] = pRef;
+// }
+// final ClusterI.CompleteTypeEnum pCompleteType = procedure.completeType;
+// if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {
+// SessionImplSocket session = (SessionImplSocket)graph.getSession();
+// ClusterSupport support = session.clusterTranslator;
+// resourceTable.foreachObject(resourceIndex, graph, procedure, support, pRef, pCompleteType, completeTable, this);
+// return;
+// }
+// final int predicateIndex = (int)resourceTable.table[(resourceIndex<<1) - 1 + resourceTable.offset] & 0xFFFFFF;
+// if (0 == predicateIndex) {
+// SessionImplSocket session = (SessionImplSocket)graph.getSession();
+// ClusterSupport support = session.clusterTranslator;
+// resourceTable.foreachObject(resourceIndex, graph, procedure, support, pRef, pCompleteType, completeTable, this);
+// return;
+// }
+// int hashBase = predicateIndex + predicateTable.offset;
+// if (predicateTable.table[hashBase-1] < 0) {
+// int objectIndex = TableIntArraySet2.get(predicateTable.table, hashBase, pRef & 0xFFFF);
+// //int objectIndex = predicateTable.getObjectIndex(predicateIndex, pRef & 0xFFFF);
+// SessionImplSocket session = (SessionImplSocket)graph.getSession();
+// ClusterSupport support = session.clusterTranslator;
+// forObjects(graph, resourceKey, predicateKey, objectIndex, procedure, support);
+// } else {
+// procedure.finished(graph);
+//// graph.dec();
+// }
+ }
+
+ public <C> void forObjects(ReadGraphImpl graph, int resourceKey, C context, ForEachObjectContextProcedure<C> procedure) throws DatabaseException {
+
+ throw new UnsupportedOperationException();
+
+// final int resourceIndex = ClusterTraitsBase.getResourceIndexFromResourceKey(resourceKey);
+// final int predicateKey = procedure.predicateKey;
+// int clusterKey = ClusterTraitsBase.getClusterMaskFromResourceKey(resourceKey);
+// int pRef = 0;
+// if(procedure.clusterKey[0] == clusterKey) {
+// pRef = procedure.predicateReference[0];
+// } else {
+// SessionImplSocket session = (SessionImplSocket)graph.getSession();
+// ClusterSupport support = session.clusterTranslator;
+// pRef = getInternalReferenceOrZero2(predicateKey, support);
+// procedure.clusterKey[0] = clusterKey;
+// procedure.predicateReference[0] = pRef;
+// }
+//
+// final ClusterI.CompleteTypeEnum pCompleteType = procedure.completeType;
+// if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {
+// SessionImplSocket session = (SessionImplSocket)graph.getSession();
+// ClusterSupport support = session.clusterTranslator;
+// resourceTable.foreachObject(resourceIndex, graph, context, procedure, support, pRef, pCompleteType, completeTable, this);
+// return;
+// }
+// final int predicateIndex = (int)resourceTable.table[(resourceIndex<<1) - 1 + resourceTable.offset] & 0xFFFFFF;
+// if (0 == predicateIndex) {
+// SessionImplSocket session = (SessionImplSocket)graph.getSession();
+// ClusterSupport support = session.clusterTranslator;
+// resourceTable.foreachObject(resourceIndex, graph, context, procedure, support, pRef, pCompleteType, completeTable, this);
+// return;
+// }
+// int hashBase = predicateIndex + predicateTable.offset;
+// if(predicateTable.table[hashBase-1] < 0) {
+// int objectIndex = TableIntArraySet2.get(predicateTable.table, hashBase, pRef & 0xFFFF);
+// SessionImplSocket session = (SessionImplSocket)graph.getSession();
+// ClusterSupport support = session.clusterTranslator;
+// forObjects(graph, resourceKey, predicateKey, objectIndex, context, procedure, support);
+// } else {
+// int objectIndex = TableIntSet2.get(predicateTable.table, hashBase, pRef & 0xFFFF);
+// SessionImplSocket session = (SessionImplSocket)graph.getSession();
+// ClusterSupport support = session.clusterTranslator;
+// forObjects(graph, resourceKey, predicateKey, objectIndex, context, procedure, support);
+// }
+ }
+ @Override
+ public <Context> boolean forObjects(int resourceKey, int predicateKey,
+ ObjectProcedure<Context> procedure, Context context, ClusterSupport support)
+ throws DatabaseException {
+ if (DEBUG)
+ System.out.println("ClusterSmall.forObjects4: rk=" + resourceKey + " pk=" + predicateKey);
+ final short resourceIndex = (short)ClusterTraitsBase.getResourceIndexFromResourceKey(resourceKey);
+ final short pRef = getInternalReferenceOrZero2(predicateKey, support);
+ final ClusterI.CompleteTypeEnum pCompleteType = ClusterTraitsBase.getCompleteTypeFromResourceKey(predicateKey);
+ // PredicateType is complete i.e. all relevant data is in resource table.
+ if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {
+ if (DEBUG)
+ System.out.println("ClusterSmall.forObjects: complete type was " + pCompleteType + " cluster=" + getClusterUID());
+ return resourceTable.foreachObject(resourceIndex, procedure, context, support, this, pRef, pCompleteType, completeTable);
+ }
+ final int predicateIndex = resourceTable.getPredicateIndex(resourceIndex);
+ if (0 == predicateIndex) { // All relevant data is in resource table.
+ if (DEBUG)
+ System.out.println("ClusterSmall.forObjects: no predicate table " + pCompleteType);
+ return resourceTable.foreachObject(resourceIndex, procedure, context, support, this, pRef, pCompleteType, completeTable);
+ }
+ int objectIndex = predicateTable.getObjectIndex(predicateIndex, pRef & 0xFFFF);
+ return forObjects(resourceKey, predicateKey, objectIndex, procedure, context, support);
+ }
+ @Override
+ public <Context> boolean forPredicates(int resourceKey,
+ PredicateProcedure<Context> procedure, Context context, ClusterSupport support)
+ throws DatabaseException {
+ if (DEBUG)
+ System.out.println("ClusterSmall.forPredicates: rk=" + resourceKey );
+ final int resourceIndex = getLocalReference(resourceKey);
+ final int predicateIndex = resourceTable.getPredicateIndex(resourceIndex);
+ if (0 == predicateIndex)
+ return resourceTable.foreachPredicate(resourceIndex,
+ procedure, context, support, this, completeTable);
+ else {
+ boolean broken = resourceTable.foreachPredicate(resourceIndex,
+ procedure, context, support, this, completeTable);
+ if (broken)
+ return true;
+ }
+ return predicateTable.foreachPredicate(predicateIndex,
+ procedure, context, support, this);
+ }
+
+ @Override
+ public ClusterI addRelation(int sResourceKey, ClusterUID puid, int pResourceKey, ClusterUID ouid, int oResourceKey, ClusterSupport support) throws DatabaseException {
+
+ if(proxy) {
+ throw new UnsupportedOperationException();
+// ClusterImpl cluster = clusterTable.load2(clusterId, clusterKey);
+// return cluster.addRelation(sResourceKey, pResourceKey, oResourceKey, support);
+ }
+
+ // check();
+ boolean ret;
+ try {
+ short sri = getLocalReferenceAnd(sResourceKey, support, ClusterChange.ADD_OPERATION);
+ short pri = getReferenceOrCreateIfForeign(pResourceKey, puid, support, ClusterStream.NULL_OPERATION);
+ short ori = getReferenceOrCreateIfForeign(oResourceKey, ouid, support, ClusterStream.NULL_OPERATION);
+ ClusterI.CompleteTypeEnum completeType = ClusterTraitsBase.getCompleteTypeFromResourceKey(pResourceKey);
+ ret = addRelationInternal(sri, pri, ori, completeType);
+ calculateModifiedId();
+ } catch (OutOfSpaceException e) {
+ boolean streamOff = support.getStreamOff();
+ if (!streamOff) {
+ support.cancelStatement(this);
+ support.setStreamOff(true);
+ }
+ ClusterI cluster = toBig(clusterSupport);
+ if (!streamOff)
+ support.setStreamOff(false);
+ ClusterI cluster2 = cluster.addRelation(sResourceKey, pResourceKey, oResourceKey, support);
+ if (cluster != cluster2)
+ throw new DatabaseException("Internal error. Contact application support.");
+ return cluster;
+ }
+// check();
+ if (ret) {
+ support.addStatement(this);
+ return this;
+ } else {
+ support.cancelStatement(this);
+ return null;
+ }
+
+ }
+
+ @Override
+ public ClusterI addRelation(int sResourceKey, int pResourceKey, int oResourceKey, ClusterSupport support) throws DatabaseException {
+
+ if (DEBUG)
+ System.out.println("add rk=" + sResourceKey + " pk=" + pResourceKey + " ok=" + oResourceKey);
+
+ if(proxy) {
+ throw new UnsupportedOperationException();
+// ClusterImpl cluster = clusterTable.load2(clusterId, clusterKey);
+// return cluster.addRelation(sResourceKey, pResourceKey, oResourceKey, support);
+ }
+
+ // check();
+ boolean ret;
+ try {
+ short sri = getLocalReferenceAnd(sResourceKey, support, ClusterChange.ADD_OPERATION);
+ short pri = getReferenceOrCreateIfForeign(pResourceKey, support, ClusterStream.NULL_OPERATION);
+ short ori = getReferenceOrCreateIfForeign(oResourceKey, support, ClusterStream.NULL_OPERATION);
+ ClusterI.CompleteTypeEnum completeType = ClusterTraitsBase.getCompleteTypeFromResourceKey(pResourceKey);
+ ret = addRelationInternal(sri, pri, ori, completeType);
+ calculateModifiedId();
+ } catch (OutOfSpaceException e) {
+ boolean streamOff = support.getStreamOff();
+ if (!streamOff) {
+ support.cancelStatement(this);
+ support.setStreamOff(true);
+ }
+ ClusterI cluster = toBig(clusterSupport);
+ if (!streamOff)
+ support.setStreamOff(false);
+ ClusterI cluster2 = cluster.addRelation(sResourceKey, pResourceKey, oResourceKey, support);
+ if (cluster != cluster2)
+ throw new DatabaseException("Internal error. Contact application support.");
+ return cluster;
+ }
+// check();
+ if (ret) {
+ support.addStatement(this);
+ return this;
+ } else {
+ support.cancelStatement(this);
+ return null;
+ }
+ }
+ @Override
+ public boolean removeRelation(int sResourceKey, int pResourceKey, int oResourceKey, ClusterSupport support)
+ throws DatabaseException {
+ // check();
+ short sri = getLocalReferenceAnd(sResourceKey, support, ClusterChange.REMOVE_OPERATION);
+ short pri = getInternalReferenceOrZeroAnd(pResourceKey, support, ClusterStream.NULL_OPERATION);
+ short ori = getInternalReferenceOrZeroAnd(oResourceKey, support, ClusterStream.NULL_OPERATION);
+ boolean ret = false;
+ if (0 != pri && 0 != ori) {
+ ClusterI.CompleteTypeEnum completeType = ClusterTraitsBase.getCompleteTypeFromResourceKey(pResourceKey);
+ ret = removeRelationInternal(sri, pri, ori, completeType, support);
+ calculateModifiedId();
+ }
+ if (ret)
+ support.removeStatement(this);
+ else
+ support.cancelStatement(this);
+ // check();
+ return ret;
+ }
+ @Override
+ public void denyRelation(int sResourceKey, int pResourceKey, int oResourceKey, ClusterSupport support)
+ throws DatabaseException {
+ short s = checkResourceKeyIsOursAndGetResourceIndexIf(sResourceKey, support);
+ ResourceReferenceAndCluster p = checkResourceKeyAndGetResourceIndexIf(pResourceKey, support);
+ ResourceReferenceAndCluster o = checkResourceKeyAndGetResourceIndexIf(oResourceKey, support);
+ if (0 == s || 0 == p.reference || 0 == o.reference)
+ return;
+ // check();
+ ClusterI.CompleteTypeEnum completeType = ClusterTraitsBase.getCompleteTypeFromResourceKey(pResourceKey);
+ boolean ret = removeRelationInternal(s, p.reference, o.reference, completeType, support);
+ if (ret) {
+ support.addStatementIndex(this, sResourceKey, getClusterUID(), ClusterChange.REMOVE_OPERATION);
+ support.addStatementIndex(this, pResourceKey, p.clusterUID, ClusterStream.NULL_OPERATION);
+ support.addStatementIndex(this, oResourceKey, o.clusterUID, ClusterStream.NULL_OPERATION);
+ support.removeStatement(this);
+ }
+ calculateModifiedId();
+ // check();
+ return;
+ }
+ @Override
+ public InputStream getValueStream(int resourceKey, ClusterSupport support) throws DatabaseException {
+ if (DEBUG)
+ System.out.println("ClusterSmall.getValue " + resourceKey);
+ int resourceIndex = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(resourceKey);
+ try {
+ byte[] buffer = resourceTable.getValue(valueTable, resourceIndex);
+ if(buffer == null) return null;
+ return new ByteArrayInputStream(buffer);
+ } catch (ExternalValueException e) {
+ return support.getValueStreamEx(resourceIndex, clusterUID.second);
+ }
+ }
+ @Override
+ public byte[] getValue(int resourceKey, ClusterSupport support)
+ throws DatabaseException {
+ if (DEBUG)
+ System.out.println("ClusterSmall.getValue " + resourceKey);
+ int resourceIndex = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(resourceKey);
+ try {
+ return resourceTable.getValue(valueTable, resourceIndex);
+ } catch (ExternalValueException e) {
+ return clusterSupport.impl.getResourceFile(clusterUID.asBytes(), resourceIndex);
+ //return support.getValueEx(resourceIndex, clusterUID.second);
+ }
+ }
+ @Override
+ public boolean hasValue(int resourceKey, ClusterSupport support)
+ throws DatabaseException {
+ int resourceIndex = getLocalReference(resourceKey);
+ return resourceTable.hasValue(resourceIndex);
+ }
+ @Override
+ public boolean removeValue(int resourceKey, ClusterSupport support)
+ throws DatabaseException {
+ int resourceIndex = getLocalReferenceAnd(resourceKey, support, ClusterChange.DELETE_OPERATION);
+ support.removeValue(this);
+ calculateModifiedId();
+ return resourceTable.removeValue(valueTable, resourceIndex);
+ }
+ @Override
+ public ClusterI setValue(int rResourceId, byte[] value, int length, ClusterSupport support)
+ throws DatabaseException {
+ int resourceIndex = getLocalReferenceAnd(rResourceId, support, ClusterStream.SET_OPERATION);
+ support.setValue(this, getClusterId(), value, length);
+ try {
+ resourceTable.setValue(valueTable, resourceIndex, value, length);
+ calculateModifiedId();
+ return this;
+ } catch (OutOfSpaceException e) {
+ boolean streamOff = support.getStreamOff();
+ if (!streamOff)
+ support.setStreamOff(true);
+ ClusterI cluster = toBig(support);
+ cluster.setValue(rResourceId, value, length, support);
+ if (!streamOff)
+ support.setStreamOff(false);
+ return cluster;
+ }
+ }
+ @Override
+ public ClusterI modiValueEx(int rResourceId, long voffset, int length, byte[] value, int offset, ClusterSupport support)
+ throws DatabaseException {
+ int resourceIndex = getLocalReferenceAnd(rResourceId, support, ClusterStream.MODI_OPERATION);
+ support.modiValue(this, getClusterId(), voffset, length, value, offset);
+ resourceTable.setValueEx(valueTable, resourceIndex);
+ calculateModifiedId();
+ return this;
+ }
+ @Override
+ public byte[] readValueEx(int rResourceId, long voffset, int length, ClusterSupport support)
+ throws DatabaseException {
+ int resourceIndex = getLocalReference(rResourceId);
+ boolean isExternal = resourceTable.isValueEx(valueTable, resourceIndex);
+ if (!isExternal)
+ throw new DatabaseException("ClusterI.readValue supported only for external value. Resource key=" + rResourceId);
+ return support.getValueEx(resourceIndex, getClusterId(), voffset, length);
+ }
+ @Override
+ public boolean isValueEx(int resourceKey) throws DatabaseException {
+ int resourceIndex = getLocalReference(resourceKey);
+ return resourceTable.isValueEx(valueTable, resourceIndex);
+ }
+ @Override
+ public long getValueSizeEx(int rResourceId, ClusterSupport support)
+ throws DatabaseException, ExternalValueException {
+ int resourceIndex = getLocalReference(rResourceId);
+ boolean isExternal = resourceTable.isValueEx(valueTable, resourceIndex);
+ if (!isExternal)
+ throw new ExternalValueException("ClusterI.getValueSizeEx supported only for external value. Resource key=" + rResourceId);
+ return support.getValueSizeEx(resourceIndex, getClusterId());
+ }
+ @Override
+ public void setValueEx(int rResourceId)
+ throws DatabaseException {
+ int resourceIndex = getLocalReference(rResourceId);
+ resourceTable.setValueEx(valueTable, resourceIndex);
+ }
+ @Override
+ public int createResource(ClusterSupport support)
+ throws DatabaseException {
+
+ if(proxy) {
+ throw new UnsupportedOperationException();
+// ClusterImpl cluster = clusterTable.load2(clusterId, clusterKey);
+// return cluster.createResource(support);
+ }
+
+ short resourceIndex = resourceTable.createResource();
+ calculateModifiedId();
+ if(DebugPolicy.REPORT_RESOURCE_ID_ALLOCATION)
+ System.out.println("[RID_ALLOCATION]: ClusterSmall[" + clusterId + "] allocates " + resourceIndex);
+ support.createResource(this, resourceIndex, getClusterId());
+ return ClusterTraits.createResourceKey(clusterKey, resourceIndex);
+ }
+ @Override
+ public boolean hasResource(int resourceKey, ClusterSupport support) {
+ int clusterKey = ClusterTraitsBase.getClusterKeyFromResourceKeyNoThrow(resourceKey);
+ if (this.clusterKey != clusterKey) // foreign resource
+ return false;
+ int resourceIndex;
+ try {
+ resourceIndex = ClusterTraits.getResourceIndexFromResourceKey(resourceKey);
+ } catch (DatabaseException e) {
+ return false;
+ }
+ if (resourceIndex > 0 & resourceIndex <= resourceTable.getTableCount())
+ return true;
+ else
+ return false;
+ }
+ @Override
+ public int getNumberOfResources(ClusterSupport support)
+ throws DatabaseException {
+
+ if(proxy) {
+ throw new UnsupportedOperationException();
+// ClusterImpl cluster = clusterTable.load2(clusterId, clusterKey);
+// return cluster.getNumberOfResources(support);
+ }
+
+ return resourceTable.getUsedSize();
+ }
+
+ public int getNumberOfResources() {
+
+ if(proxy) throw new IllegalStateException();
+
+ return resourceTable.getUsedSize();
+
+ }
+
+ @Override
+ public long getUsedSpace() {
+ if(isEmpty()) return 0;
+ long rt = resourceTable.getTableCapacity() * 8 + 8; // (8 = cluster id)
+ long ft = foreignTable.getTableCapacity() * 8;
+ long pt = predicateTable.getTableCapacity() * 4;
+ long ot = objectTable.getTableCapacity() * 4;
+ long ct = completeTable.getTableCapacity() * 4;
+ long vt = valueTable.getTableCapacity() * 1;
+ long cm = clusterMap.getUsedSpace();
+ return rt + ft + pt + ot + ct + vt + cm;
+ }
+ @Override
+ public boolean isEmpty() {
+ if(resourceTable == null) return true;
+ return resourceTable.getTableCount() == 0;
+ }
+ @Override
+ public void printDebugInfo(String message, ClusterSupport support)
+ throws DatabaseException {
+ throw new DatabaseException("Not implemented!");
+ }
+ private short getInternalReferenceOrZero2(int resourceKey, ClusterSupport support) throws DatabaseException {
+ int resourceIndex = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(resourceKey);
+ if (!ClusterTraitsBase.isCluster(clusterBits, resourceKey)) {
+ return clusterMap.getForeignReferenceOrZero(resourceKey);
+ } else {
+ return (short)resourceIndex;
+ }
+ }
+ private short getInternalReferenceOrZeroAnd(int resourceKey, ClusterSupport support, byte op)
+ throws DatabaseException {
+ int clusterKey = ClusterTraits.getClusterKeyFromResourceKey(resourceKey);
+ int resourceIndex = ClusterTraits.getResourceIndexFromResourceKey(resourceKey);
+ if (this.clusterKey != clusterKey) { // foreign resource
+ ClusterUID clusterUID = clusterSupport.getClusterUIDByResourceKey(resourceKey);
+ short foreignRef = clusterMap.getForeignReferenceOrZero(resourceKey);
+ support.addStatementIndex(this, resourceKey, clusterUID, op);
+ return foreignRef;
+ }
+ support.addStatementIndex(this, resourceKey, getClusterUID(), op);
+ return (short)resourceIndex;
+ }
+ private final short getLocalReference(int resourceKey) throws DatabaseException {
+ return ClusterTraits.getResourceIndexFromResourceKeyNoThrow(resourceKey);
+ }
+ private final short getLocalReferenceAnd(int resourceKey, ClusterSupport support, byte op)
+ throws DatabaseException {
+ short resourceIndex = getLocalReference(resourceKey);
+ support.addStatementIndex(this, resourceKey, getClusterUID(), op);
+ return resourceIndex;
+ }
+ private short checkResourceKeyIsOursAndGetResourceIndexIf(int resourceKey, ClusterSupport support)
+ throws DatabaseException {
+ int clusterShortId = ClusterTraits.getClusterKeyFromResourceKey(resourceKey);
+ if (this.clusterKey != clusterShortId)
+ return 0;
+ int resourceIndex = ClusterTraits.getResourceIndexFromResourceKey(resourceKey);
+ return (short)resourceIndex;
+ }
+ private short getReferenceOrCreateIfForeign(int resourceKey, ClusterUID clusterUID, ClusterSupport support, byte op)
+ throws DatabaseException {
+ int clusterKey = ClusterTraits.getClusterKeyFromResourceKey(resourceKey);
+ short resourceIndex = (short)ClusterTraits.getResourceIndexFromResourceKey(resourceKey);
+ if (this.clusterKey != clusterKey) {
+ support.addStatementIndex(this, resourceKey, clusterUID, op);
+ short ref = clusterMap.getForeignReferenceOrCreateByResourceKey(resourceKey, clusterUID);
+ return ref;
+ }
+ support.addStatementIndex(this, resourceKey, getClusterUID(), op);
+ return resourceIndex;
+ }
+ private short getReferenceOrCreateIfForeign(int resourceKey, ClusterSupport support, byte op)
+ throws DatabaseException {
+ int clusterKey = ClusterTraits.getClusterKeyFromResourceKey(resourceKey);
+ short resourceIndex = (short)ClusterTraits.getResourceIndexFromResourceKey(resourceKey);
+ if (this.clusterKey != clusterKey) {
+ ClusterUID clusterUID = clusterSupport.getClusterUIDByResourceKey(resourceKey);
+ support.addStatementIndex(this, resourceKey, clusterUID, op);
+ short ref = clusterMap.getForeignReferenceOrCreateByResourceKey(resourceKey, clusterUID);
+ return ref;
+ }
+ support.addStatementIndex(this, resourceKey, getClusterUID(), op);
+ return resourceIndex;
+ }
+ private class ResourceReferenceAndCluster {
+ ResourceReferenceAndCluster(short reference, ClusterUID clusterUID) {
+ this.reference = reference;
+ this.clusterUID = clusterUID;
+ }
+ public final short reference;
+ public final ClusterUID clusterUID;
+ }
+ private ResourceReferenceAndCluster checkResourceKeyAndGetResourceIndexIf(int resourceKey, ClusterSupport support)
+ throws DatabaseException {
+ int clusterKey = ClusterTraits.getClusterKeyFromResourceKey(resourceKey);
+ short resourceIndex = (short)ClusterTraits.getResourceIndexFromResourceKey(resourceKey);
+ if (this.clusterKey != clusterKey) { // foreign resource
+ ClusterI foreignCluster = support.getClusterByClusterKey(clusterKey);
+ ClusterUID clusterUID = foreignCluster.getClusterUID();
+ short ref = clusterMap.getForeignReferenceOrZero(resourceKey);
+ return new ResourceReferenceAndCluster(ref, clusterUID);
+ }
+ return new ResourceReferenceAndCluster(resourceIndex, getClusterUID());
+ }
+
+ static long fTime = 0;
+
+ @Override
+ final public int execute(int resourceReference) throws DatabaseException {
+ short resourceRef = (short)resourceReference;
+ int key;
+ if (ClusterTraitsSmall.resourceRefIsLocal(resourceRef)) {
+ key = clusterBits | resourceRef;
+ } else {
+ short foreignIndex = ClusterTraitsSmall.resourceRefGetForeignIndex((short)resourceRef);
+ //long start = System.nanoTime();
+ ResourceUID resourceUID = foreignTable.getResourceUID(foreignIndex);
+ int clusterKey = clusterSupport.getClusterKeyByClusterUIDOrMake(resourceUID.asCID());
+// ClusterBase cluster = clusterSupport.getClusterByClusterUIDOrMake(resourceUID.asCID());
+ key = ClusterTraitsBase.createResourceKey(clusterKey, resourceUID.getIndex());
+ //fTime += System.nanoTime() - start;
+ //System.err.println("fTime: " + 1e-9*fTime);
+ }
+ if (DEBUG)
+ System.out.println("ClusterSmall.execute key=" + key);
+ return key;
+ }
+
+ private boolean addRelationInternal(short sReference, short pReference, short oReference, ClusterI.CompleteTypeEnum completeType)
+ throws DatabaseException {
+ int predicateIndex = resourceTable.addStatement(sReference, pReference, oReference, predicateTable, objectTable, completeType, completeTable);
+ if (0 == predicateIndex)
+ return true; // added to resourceTable
+ else if (0 > predicateIndex)
+ return false; // old complete statemenent
+ int newPredicateIndex = predicateTable.addPredicate(predicateIndex, 0xFFFF & pReference, 0xFFFF & oReference, objectTable);
+ if (0 == newPredicateIndex)
+ return false;
+ if (predicateIndex != newPredicateIndex)
+ resourceTable.setPredicateIndex(sReference, newPredicateIndex);
+ return true;
+ }
+ private boolean removeRelationInternal(int sResourceIndex, short pResourceIndex,
+ short oResourceIndex, ClusterI.CompleteTypeEnum completeType, ClusterSupport support)
+ throws DatabaseException {
+ int predicateIndex = resourceTable.getPredicateIndex(sResourceIndex);
+ if (0 == predicateIndex || ClusterI.CompleteTypeEnum.NotComplete != completeType)
+ return resourceTable.removeStatementFromCache(sResourceIndex,
+ pResourceIndex, oResourceIndex, completeType, completeTable);
+ PredicateTable.Status ret = predicateTable.removePredicate(predicateIndex, 0xFFFF & pResourceIndex, 0xFFFF & oResourceIndex, objectTable);
+ switch (ret) {
+ case NothingRemoved:
+ return false;
+ case PredicateRemoved: {
+ if (0 == predicateTable.getPredicateSetSize(predicateIndex))
+ resourceTable.setPredicateIndex(sResourceIndex, 0);
+ // intentionally dropping to next case
+ } default:
+ break;
+ }
+ resourceTable.removeStatement(sResourceIndex,
+ pResourceIndex, oResourceIndex,
+ completeType, completeTable,
+ predicateTable, objectTable, support);
+ return true;
+ }
+ @Override
+ public void load() {
+ throw new Error("Not supported.");
+ }
+
+ @Override
+ public void load(Callback<DatabaseException> r) {
+ throw new Error("Not supported.");
+ }
+
+ public boolean contains(int resourceKey) {
+ return ClusterTraitsBase.isCluster(clusterBits, resourceKey);
+ }
+ @Override
+ public void load(final ClusterSupport support, final Runnable callback) {
+
+ throw new UnsupportedOperationException();
+
+// try {
+// clusterTable.load2(clusterId, clusterKey);
+// callback.run();
+// } catch (DatabaseException e) {
+// e.printStackTrace();
+// }
+
+ }
+ @Override
+ public ClusterI getClusterByResourceKey(int resourceKey,
+ ClusterSupport support) {
+ throw new Error();
+ }
+ @Override
+ public void increaseReferenceCount(int amount) {
+ throw new Error();
+ }
+ @Override
+ public void decreaseReferenceCount(int amount) {
+ throw new Error();
+ }
+ @Override
+ public int getReferenceCount() {
+ throw new Error();
+ }
+ @Override
+ public void releaseMemory() {
+ }
+ @Override
+ public void compact() {
+ clusterMap.compact();
+ }
+ @Override
+ public boolean isLoaded() {
+ return !proxy;
+ }
+
+// public ClusterImpl tryLoad(SessionImplSocket sessionImpl) {
+//
+// throw new UnsupportedOperationException();
+// assert(Constants.ReservedClusterId != clusterId);
+//
+// return clusterTable.tryLoad(clusterId, clusterKey);
+//
+// }
+
+
+ @Override
+ public ClusterBig toBig(ClusterSupport support)
+ throws DatabaseException {
+ if (DEBUG) {
+ System.out.println("DEBUG: toBig cluster=" + clusterId);
+ new Exception().printStackTrace();
+ }
+ ClusterBig big = new ClusterBig(clusterSupport, getClusterUID(), clusterKey, (ClusterSupport2)support);
+ big.cc = this.cc;
+// if(big.cc != null)
+// big.cc.clusterImpl = this;
+ resourceTable.toBig(big, support, this);
+ big.foreignLookup = this.foreignLookup;
+ big.change = this.change;
+ this.cc = null;
+ this.foreignLookup = null;
+ this.change = null;
+ return big;
+ }
+
+ @Override
+ public ClusterTypeEnum getType() {
+ return ClusterTypeEnum.SMALL;
+ }
+ @Override
+ public boolean getImmutable() {
+ int status = resourceTable.getClusterStatus();
+ return (status & ClusterStatus.ImmutableMaskSet) == 1;
+ }
+ @Override
+ public void setImmutable(boolean immutable, ClusterSupport support) {
+ if(resourceTable != null) {
+ int status = resourceTable.getClusterStatus();
+ if (immutable)
+ status |= ClusterStatus.ImmutableMaskSet;
+ else
+ status &= ClusterStatus.ImmutableMaskClear;
+ resourceTable.setClusterStatus(status);
+ }
+ support.setImmutable(this, immutable);
+ }
+
+ @Override
+ public String toString() {
+ try {
+ final TIntHashSet set = new TIntHashSet();
+ TIntShortHashMap map = foreignTable.getResourceHashMap();
+ map.forEachKey(new TIntProcedure() {
+ @Override
+ public boolean execute(int value) {
+ set.add(value & 0xfffff000);
+ return true;
+ }
+ });
+ return "ClusterSmall[" + getClusterUID() + " - " + getClusterId() + " - " + getNumberOfResources() + " - " + foreignTable.getResourceHashMap().size() + " - " + set.size() + "]";
+ } catch (DatabaseException e) {
+ return "ClusterSmall[" + getNumberOfResources() + "]";
+ }
+ }
+
+ // Memory map
+ // bytes (b) | headers(i) | predicateTable (i) | objectTable (i) | completeTable (i) | resourceTable (l) | foreignTable (l)
+
+ @Override
+ public byte[] storeBytes() throws IOException {
+
+ int byteSize = valueTable.getTableSize();
+ int longSize = LONG_HEADER_SIZE + resourceTable.getTableSize() + foreignTable.getTableSize();
+ int intSize = INT_HEADER_SIZE + predicateTable.getTableSize() + objectTable.getTableSize() + completeTable.getTableSize();
+
+ byte[] raw = new byte[12 + byteSize + 8*longSize + 4*intSize];
+
+ int[] currentHeader = Arrays.copyOf(headerTable, INT_HEADER_SIZE);
+
+ Bytes.writeLE(raw, 0, byteSize);
+ Bytes.writeLE(raw, 4, intSize);
+ Bytes.writeLE(raw, 8, longSize);
+
+ int rawPos = valueTable.storeBytes(raw, 0, 12);
+
+ int intBase = rawPos;
+
+ rawPos += 4*INT_HEADER_SIZE;
+ rawPos = predicateTable.storeBytes(raw, (rawPos-intBase)>>2, rawPos);
+ rawPos = objectTable.storeBytes(raw, (rawPos-intBase)>>2, rawPos);
+ rawPos = completeTable.storeBytes(raw, (rawPos-intBase)>>2, rawPos);
+
+ int longBase = rawPos;
+
+ rawPos += 8*LONG_HEADER_SIZE;
+ rawPos = resourceTable.storeBytes(raw, (rawPos-longBase)>>3, rawPos);
+ rawPos = foreignTable.storeBytes(raw, (rawPos-longBase)>>3, rawPos);
+
+ Bytes.writeLE8(raw, longBase, -1);
+ Bytes.writeLE8(raw, longBase+8, LONG_HEADER_VERSION);
+ Bytes.writeLE8(raw, longBase+16, 0);
+ Bytes.writeLE8(raw, longBase+24, clusterUID.second);
+
+ // write header
+ for(int i=0;i<INT_HEADER_SIZE;i++) {
+ int v = headerTable[i];
+ Bytes.writeLE(raw, intBase, v);
+ intBase+=4;
+ }
+
+ for(int i=0;i<INT_HEADER_SIZE;i++)
+ headerTable[i] = currentHeader[i];
+
+ return raw;
+
+ }
+
+ @Override
+ public ClusterTables store() throws IOException {
+
+ ClusterTables result = new ClusterTables();
+
+ int[] currentHeader = Arrays.copyOf(headerTable, INT_HEADER_SIZE);
+
+ int byteSize = valueTable.getTableSize();
+ byte[] byteBytes = new byte[byteSize];
+ valueTable.store(byteBytes, 0);
+
+ result.bytes = byteBytes;
+
+ int longSize = LONG_HEADER_SIZE + resourceTable.getTableSize() + foreignTable.getTableSize();
+ long[] longBytes = new long[longSize];
+
+ longBytes[0] = -1;
+ longBytes[1] = LONG_HEADER_VERSION;
+ longBytes[2] = 0;
+ longBytes[3] = clusterUID.second;
+
+ int longPos = resourceTable.store(longBytes, LONG_HEADER_SIZE);
+ foreignTable.store(longBytes, longPos);
+
+ result.longs = longBytes;
+
+ int intSize = INT_HEADER_SIZE + predicateTable.getTableSize() + objectTable.getTableSize() + completeTable.getTableSize();
+ int[] intBytes = new int[intSize];
+ int intPos = INT_HEADER_SIZE;
+ intPos = predicateTable.store(intBytes, intPos);
+ intPos = objectTable.store(intBytes, intPos);
+ intPos = completeTable.store(intBytes, intPos);
+ // write header
+ for(int i=0;i<INT_HEADER_SIZE;i++) {
+ int v = headerTable[i];
+ intBytes[i] = v;
+ //Bytes.writeLE(intBytes, i<<2, v);
+ }
+
+ result.ints = intBytes;
+
+ for(int i=0;i<INT_HEADER_SIZE;i++)
+ headerTable[i] = currentHeader[i];
+
+ return result;
+
+ }
+
+ @Override
+ protected int getResourceTableCount() {
+ return resourceTable.getTableCount();
+ }
+
+ @Override
+ public boolean getDeleted() {
+ if (deleted) return true;
+ int status = resourceTable.getClusterStatus();
+ return (status & ClusterStatus.DeletedMaskSet) == ClusterStatus.DeletedMaskSet;
+ }
+ @Override
+ public void setDeleted(boolean set, ClusterSupport support) {
+ deleted = set;
+ if(resourceTable != null) {
+ int status = resourceTable.getClusterStatus();
+ if (set)
+ status |= ClusterStatus.DeletedMaskSet;
+ else
+ status &= ClusterStatus.DeletedMaskClear;
+ resourceTable.setClusterStatus(status);
+ }
+ if (null != support)
+ support.setDeleted(this, set);
+ }
+
+ @Override
+ public Table<?> getPredicateTable() {
+ return predicateTable;
+ }
+
+ @Override
+ public Table getForeignTable() {
+ return foreignTable;
+ }
+
+ @Override
+ public int makeResourceKey(int pRef) throws DatabaseException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Table<?> getCompleteTable() {
+ return completeTable;
+ }
+
+ @Override
+ public Table<?> getValueTable() {
+ return valueTable;
+ }
+
+ @Override
+ public Table<?> getObjectTable() {
+ return objectTable;
+ }
+
+}
+
+class ClusterStatus {
+ public static final int ImmutableMaskClear = 0xFFFFFFFE;
+ public static final int ImmutableMaskSet = 0x00000001;
+ public static final int DeletedMaskClear = 0xFFFFFFFD;
+ public static final int DeletedMaskSet = 0x00000002;
+}