/******************************************************************************* * 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 gnu.trove.map.hash.TIntIntHashMap; import gnu.trove.procedure.TIntIntProcedure; import gnu.trove.set.hash.TIntHashSet; import org.simantics.db.exception.DatabaseException; import org.simantics.db.exception.ValidationException; import org.simantics.db.impl.ClusterBase; import org.simantics.db.impl.ClusterI; 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.Modifier; import org.simantics.db.impl.Table; import org.simantics.db.impl.TableFactory; import org.simantics.db.impl.TableIntAllocatorAdapter; import org.simantics.db.impl.TableSizeListener; import org.simantics.db.procore.cluster.TableIntArraySet2.Tables; public final class PredicateTable extends Table { final TableIntAllocatorAdapter allocator; public PredicateTable(TableSizeListener sizeListener, int[] header, int headerBase) { super(TableFactory.getIntFactory(), sizeListener, header, headerBase); allocator = new TableIntAllocatorAdapter(this); } public PredicateTable(TableSizeListener sizeListener, int[] header, int headerBase, int[] ints) { super(TableFactory.getIntFactory(), sizeListener, header, headerBase, ints); allocator = new TableIntAllocatorAdapter(this); } int createPredicateSet(int[] ps, int[] os) throws DatabaseException { int hashBase = TableIntArraySet2.create(ps, os, allocator); return convertRealIndexToTableIndex(hashBase); } void deletePredicateSet(int predicateIndex) { int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0); if (TableIntArraySet2.isArraySet(getTable(), hashBase)) { int capacity = TableIntArraySet2.getAllocatedSize(getTable(), hashBase); int elementIndex = predicateIndex - TableIntArraySet2.HeaderSize; deleteOldElement(elementIndex, capacity); } else { int capacity = TableIntSet2.getAllocatedSize(getTable(), hashBase); int elementIndex = predicateIndex - TableIntSet2.HeaderSize; deleteOldElement(elementIndex, capacity); } } public int getPredicateSetSize(int predicateIndex) { int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0); if (TableIntArraySet2.isArraySet(getTable(), hashBase)) return TableIntArraySet2.getSize(getTable(), hashBase); else return TableIntSet2.getSize(getTable(), hashBase); } public int getObjectIndex(int predicateIndex, int pRef) { int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0); if (TableIntArraySet2.isArraySet(table, hashBase)) return TableIntArraySet2.get(table, hashBase, pRef); else { return TableIntSet2.get(table, hashBase, pRef); } } private int addPredicateArray(int predicateIndex, int hashBase, int pReference, int oReference, ObjectTable ot) throws DatabaseException { int newHashBase; int objectIndex = TableIntArraySet2.get(getTable(), hashBase, pReference); if (0 == objectIndex) { newHashBase = TableIntArraySet2.addInt(getTable(), hashBase, pReference, oReference, allocator); } else if (ClusterTraits.statementIndexIsDirect(objectIndex)) { int oRef = objectIndex; if (oRef == oReference) { return 0; // old direct object } objectIndex = ot.createObjectSet(oRef, oReference); assert(0 != objectIndex); int newObjectIndex = ClusterTraits.statementIndexMake(objectIndex); newHashBase = TableIntArraySet2.addInt(getTable(), hashBase, pReference, newObjectIndex, allocator); } else { int newObjectIndex = ot.addObject(ClusterTraits.statementIndexGet(objectIndex), oReference); if (0 == newObjectIndex) return 0; // old indirect object newObjectIndex = ClusterTraits.statementIndexMake(newObjectIndex); newHashBase = TableIntArraySet2.addInt(getTable(), hashBase, pReference, newObjectIndex, allocator); if (newHashBase == 0) return hashBase; } int TABLE_SIZE = TableIntArraySet2.getSize(getTable(), newHashBase); if (TABLE_SIZE > 5) return convertToPredicateSet(predicateIndex, newHashBase); return newHashBase; } private int convertToPredicateSet(int predicateIndex, int hashBase) { Tables tables = TableIntArraySet2.getInts(getTable(), hashBase); this.deletePredicateSet(predicateIndex); int newHashBase = TableIntSet2.create(tables.keys, tables.vals, allocator); assert(0 != newHashBase); return newHashBase; } private int addPredicateSet(int hashBase, int pReference, int oReference, ObjectTable ot) throws DatabaseException { int objectIndex = TableIntSet2.get(getTable(), hashBase, pReference); int newHashBase; if (0 == objectIndex) { newHashBase = TableIntSet2.addInt(getTable(), hashBase, pReference, oReference, allocator); } else if (ClusterTraits.statementIndexIsDirect(objectIndex)) { int oRef = objectIndex; if (oRef == oReference) { return 0; // old direct object } objectIndex = ot.createObjectSet(oRef, oReference); assert(0 != objectIndex); int newObjectIndex = ClusterTraits.statementIndexMake(objectIndex); newHashBase = TableIntSet2.addInt(getTable(), hashBase, pReference, newObjectIndex, allocator); assert(0 != newHashBase); } else { int newObjectIndex = ot.addObject(ClusterTraits.statementIndexGet(objectIndex), oReference); if (0 == newObjectIndex) return 0; // old indirect object int stmIndex = ClusterTraits.statementIndexMake(newObjectIndex); newHashBase = TableIntSet2.addInt(getTable(), hashBase, pReference, stmIndex, allocator); if (newHashBase == 0) return hashBase; // new object added to old predicate (set) } return newHashBase; } /** * @param predicateIndex * @param pReference * @return zero if element was not added or predicate index. * Predicate index will change if new space is allocated. */ public int addPredicate(int predicateIndex, int pReference, int oReference, ObjectTable ot) throws DatabaseException { int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0); int newHashBase; if (TableIntArraySet2.isArraySet(getTable(), hashBase)) newHashBase = addPredicateArray(predicateIndex, hashBase, pReference, oReference, ot); else newHashBase = addPredicateSet(hashBase, pReference, oReference, ot); if (0 == newHashBase) return 0; // not modified return convertRealIndexToTableIndex(newHashBase); } public enum Status { NothingRemoved, ObjectRemoved, PredicateRemoved; } /** * @param predicateIndex * @param oResourceIndex * @return null if nothing was removed. Status if either object or both * object and predicate were removed. */ public Status removePredicate(int predicateIndex, int pReference, int oReference, ObjectTable ot) throws DatabaseException { int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0); int[] table = getTable(); if (TableIntArraySet2.isArraySet(table, hashBase)) { int objectIndex = TableIntArraySet2.get(table, hashBase, pReference); if (0 == objectIndex) { return Status.NothingRemoved; } else if (ClusterTraits.statementIndexIsDirect(objectIndex)) { int oRef = objectIndex; if (oRef != oReference) return Status.NothingRemoved; if (TableIntArraySet2.removeInt(table, hashBase, pReference)) return Status.PredicateRemoved; else throw new DatabaseException("Internal error during remove."); } else { int oIndex = ClusterTraits.statementIndexGet(objectIndex); int nO = ot.getObjectSetSize(oIndex); if (nO < 1) throw new DatabaseException("Illegal object set size="+nO); int nObject = ot.removeObject(objectIndex, oReference); if (nObject == 0) { ot.deleteObjectSet(oIndex); if (TableIntArraySet2.removeInt(table, hashBase, pReference)) return Status.PredicateRemoved; else throw new DatabaseException("Internal error during remove (2)."); } else if (nO == nObject) return Status.NothingRemoved; else return Status.ObjectRemoved; } } else { int objectIndex = TableIntSet2.get(table, hashBase, pReference); if (0 == objectIndex) { return Status.NothingRemoved; } else if (ClusterTraits.statementIndexIsDirect(objectIndex)) { int oRef = objectIndex; if (oRef != oReference) return Status.NothingRemoved; if (TableIntSet2.removeInt(table, hashBase, pReference)) return Status.PredicateRemoved; else throw new DatabaseException("Internal error during remove (3)."); } else { int oIndex = ClusterTraits.statementIndexGet(objectIndex); int nO = ot.getObjectSetSize(oIndex); if (nO < 1) throw new DatabaseException("Illegal object set size="+nO); int nObject = ot.removeObject(objectIndex, oReference); if (nObject == 0) { ot.deleteObjectSet(oIndex); if (TableIntSet2.removeInt(table, hashBase, pReference)) return Status.PredicateRemoved; else throw new DatabaseException("Internal error during remove (4)."); } else if (nO == nObject) return Status.NothingRemoved; else return Status.ObjectRemoved; } } } public boolean foreachPredicate(int predicateIndex , ClusterI.PredicateProcedure procedure , Context context, ClusterSupport support, Modifier modifier) throws DatabaseException { final int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0); boolean ret; if (TableIntArraySet2.isArraySet(getTable(), hashBase)) ret = TableIntArraySet2.foreachInt(getTable(), hashBase, procedure, context, modifier); else ret = TableIntSet2.foreachInt(getTable(), hashBase, procedure, context, modifier); return ret; } private void checkEntry(ClusterBase cluster, int[] table, int index) throws DatabaseException { assert(ClusterTraits.statementIndexIsDirect(table[index])); int dr = table[index]; cluster.checkDirectReference(dr); assert(table[index+1] != 0); if (ClusterTraits.statementIndexIsDirect(table[index+1])) { cluster.checkDirectReference(table[index+1]); } else { cluster.checkObjectSetReference(table[index+1]); } } private TIntHashSet checkIndexSet = null; public void check(ClusterBase cluster) throws DatabaseException { if (null == checkIndexSet) checkIndexSet = new TIntHashSet(); else checkIndexSet.clear(); int count = 0; int[] table = getTable(); int ps = getHeader().getOffset() + ZERO_SHIFT; int pe = ps + getTableSize(); for (int p=ps; p= 0) { int use = p++; int fre = p++; int max = p++; assert(table[cap] >= table[use] + table[fre]); assert(table[max] == table[cap] >> 1); assert(table[max]+1 >= table[use]); checkIndexSet.add(p - ps); for (int e = p + table[cap]*2; p 0); boolean free = false; checkIndexSet.add(p - ps); for (int e = p + size*2; p boolean foreach(int setIndex, Procedure procedure, Context context, ClusterSupport support, Modifier modifier) throws DatabaseException { return foreachPredicate(setIndex, (PredicateProcedure)procedure, context, support, modifier); } }