/******************************************************************************* * 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.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.ClusterTraitsBase; import org.simantics.db.impl.Modifier; 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; public final class ResourceTableSmall extends Table { public ResourceTableSmall(TableSizeListener sizeListener, int[] header, int headerBase) { super(TableFactory.getLongFactory(), sizeListener, header, headerBase); } public ResourceTableSmall(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 = ResourceElementSmall.getSizeOf(); int resourceIndex = createNewElement(SIZE); assert (0 != resourceIndex); final int REAL_INDEX = checkIndexAndGetRealIndex(resourceIndex, SIZE); ResourceElementSmall.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 (ResourceElementSmall.isEmpty(getTable(), realIndex)) return; } if (resourceIndex == tableCount+1) { createResource(); return; } throw new InternalError("Trying to create resource with illegal index=" + resourceIndex); } public short getCompleteObjectRef(int resourceIndex) { int realIndex = checkIndexAndGetRealIndex(resourceIndex); return ResourceElementSmall.getCompleteObjectRef(getTable(), realIndex); } public ClusterI.CompleteTypeEnum getCompleteType(int resourceIndex) { int realIndex = checkIndexAndGetRealIndex(resourceIndex); return ResourceElementSmall.getCompleteType(getTable(), realIndex); } public int getPredicateIndex(int resourceIndex) { int realIndex = checkIndexAndGetRealIndex(resourceIndex); return ResourceElementSmall.getPredicateIndex(table, realIndex); } public void setPredicateIndex(int resourceIndex, int predicateIndex) { int realIndex = checkIndexAndGetRealIndex(resourceIndex); ResourceElementSmall.setPredicateIndex(getTable(), realIndex, predicateIndex); } public byte[] getValue(ValueTableSmall valueTable, int resourceIndex) throws DatabaseException { int realIndex = checkIndexAndGetRealIndex(resourceIndex); return ResourceElementSmall.getValue(valueTable, getTable(), realIndex); } //KRAA: // char[] getString(ValueTableSmall valueTable, int resourceIndex) { // int realIndex = checkIndexAndGetRealIndex(resourceIndex); // return ResourceElementSmall.getString(valueTable, getTable(), realIndex); // } public boolean hasValue(int resourceIndex) { int realIndex = checkIndexAndGetRealIndex(resourceIndex); return ResourceElementSmall.hasValue(getTable(), realIndex); } // boolean hasValue(ValueTable valueTable, int resourceIndex, byte[] value) { // int realIndex = checkIndexAndGetRealIndex(resourceIndex); // return ResourceElementSmall.hasValue(valueTable, getTable(), realIndex, value); // } public boolean removeValue(ValueTableSmall valueTable, int resourceIndex) { int realIndex = checkIndexAndGetRealIndex(resourceIndex); boolean ret = ResourceElementSmall.removeValue(valueTable, getTable(), realIndex); // if (ret && !ResourceElementSmall.isUsed(getTable(), realIndex)) // decResourceCount(); return ret; } public void setValue(ValueTableSmall valueTable, int resourceIndex, byte[] value, int length) throws OutOfSpaceException { int realIndex = checkIndexAndGetRealIndex(resourceIndex); ResourceElementSmall.setValue(valueTable, getTable(), realIndex, value, length); } public boolean isValueEx(ValueTableSmall valueTable, int resourceIndex) { int realIndex = checkIndexAndGetRealIndex(resourceIndex); return ResourceElementSmall.isValueEx(valueTable, getTable(), realIndex); } public void setValueEx(ValueTableSmall valueTable, int resourceIndex) { int realIndex = checkIndexAndGetRealIndex(resourceIndex); ResourceElementSmall.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); } boolean foreachResource(ClusterI.ObjectProcedure procedure, Context context, ClusterSupport support, Modifier modifier) throws DatabaseException { final int tsize = getTableSize(); // final int rsize = getResourceCount(); final int esize = ResourceElementSmall.getSizeOf(); //int count = 0; int key = ZERO_SHIFT; for (int i = getTableBase(); i < getTableBase() + tsize; i += esize, ++key) { if (ResourceElementSmall.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 ResourceElementSmall.foreachPredicate(getTable(), realIndex , procedure, context, support, modifier, ct); } public int getSingleObject(int resourceIndex, ClusterSupport support, short pRef, ClusterI.CompleteTypeEnum completeType, CompleteTable ct, Modifier modifier) throws DatabaseException { int realIndex = checkIndexAndGetRealIndex(resourceIndex); return ResourceElementSmall.getSingleObject(table, realIndex, support, pRef, completeType, ct, modifier); } public void foreachObject(int resourceIndex, ReadGraphImpl graph, SyncMultiProcedure procedure, ClusterSupport support, int pRef, ClusterI.CompleteTypeEnum completeType, CompleteTable ct, Modifier modifier) throws DatabaseException { int realIndex = checkIndexAndGetRealIndex(resourceIndex); ResourceElementSmall.foreachObject(table, realIndex, graph, procedure, support, pRef, completeType, ct, modifier); } public void foreachObject(int resourceIndex, ReadGraphImpl graph, C context, SyncContextMultiProcedure procedure, ClusterSupport support, int pRef, ClusterI.CompleteTypeEnum completeType, CompleteTable ct, Modifier modifier) throws DatabaseException { int realIndex = checkIndexAndGetRealIndex(resourceIndex); ResourceElementSmall.foreachObject(table, realIndex, graph, context, procedure, support, pRef, completeType, ct, modifier); } public boolean foreachObject(int resourceIndex , ClusterI.ObjectProcedure procedure, Context context , ClusterSupport support, Modifier modifier, short pRef, ClusterI.CompleteTypeEnum completeType, CompleteTable ct) throws DatabaseException { int realIndex = checkIndexAndGetRealIndex(resourceIndex); return ResourceElementSmall.foreachObject(table, realIndex , procedure, context, support, modifier , pRef, completeType, ct); } public int addStatement(int resourceIndex, short pRef, short oRef, PredicateTable pt, ObjectTable ot , ClusterI.CompleteTypeEnum completeType, CompleteTable ct) throws DatabaseException { int realIndex = checkIndexAndGetRealIndex(resourceIndex); return ResourceElementSmall.addStatement(getTable(), realIndex, pRef, oRef, pt, ot, completeType, ct); } public boolean removeStatementFromCache(int resourceIndex, short pRef, short oRef, ClusterI.CompleteTypeEnum completeType, CompleteTable ct) throws DatabaseException { int realIndex = checkIndexAndGetRealIndex(resourceIndex); boolean ret = ResourceElementSmall.removeStatement(getTable(), realIndex, pRef, oRef, completeType, ct); // if (ret && !ResourceElementSmall.isUsed(getTable(), realIndex)) // decResourceCount(); return ret; } public void removeStatement(int resourceIndex, short pRef, short oRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, PredicateTable pt, ObjectTable ot, ClusterSupport support) throws DatabaseException { int realIndex = checkIndexAndGetRealIndex(resourceIndex); boolean removed = ResourceElementSmall.removeStatement(getTable(), realIndex, pRef, oRef, pCompleteType, ct); if (!removed) return; int predicateIndex = ResourceElementSmall.getPredicateIndex(getTable(), realIndex); if (0 == predicateIndex) { // if (!ResourceElementSmall.isUsed(getTable(), realIndex)) // decResourceCount(); return; } else if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) return; // Complete type statements are not kept in statement cache. // We have one more statements in predicate table. // Here we check if statement cache needs fixing. GetStatementsSmall gs = new GetStatementsSmall(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)."); assert(stm.pRef < (1<<16)); assert(stm.oIndex < 1<<16); int pi = ResourceElementSmall.addStatement(getTable(), realIndex, (short)stm.pRef, (short)stm.oIndex, pt, ot, ClusterI.CompleteTypeEnum.NotComplete, ct); assert(0 >= pi); } assert(0 == pt.getPredicateSetSize(predicateIndex)); ResourceElementSmall.setPredicateIndex(getTable(), realIndex, 0); } else { for (int i = 0; i < SIZE; ++i) { Statement stm = stms.get(i); assert(stm.pRef < (1<<16)); assert(stm.oIndex < 1<<16); int pIndex = ResourceElementSmall.addStatement(getTable(), realIndex, (short)stm.pRef, (short)stm.oIndex, pt, ot, ClusterI.CompleteTypeEnum.NotComplete, 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 (!ResourceElementSmall.isUsed(getTable(), realIndex)) // decResourceCount(); } private int checkIndexAndGetRealIndex(final int resourceIndex) { if (ClusterTraitsBase.isIllegalResourceIndex(resourceIndex)) throw new RuntimeException("Illegal resource index. index=" + resourceIndex + "."); if(resourceIndex > getTableCount()) throw new RuntimeException("Illegal resource index. index=" + resourceIndex + " table count=" + getTableCount()); final int SIZE = ResourceElementSmall.getSizeOf(); final int REAL_INDEX = resourceIndex * SIZE - (SIZE - ZERO_SHIFT) + offset; return REAL_INDEX; } void check(ClusterImpl cluster) throws DatabaseException { // throw new Error("Not implemented.//KRAA:"); } public void toBig(ClusterBase big, final ClusterSupport support, final ClusterBase small) throws DatabaseException { int resourceIndex = 1; long[] table = getTable(); int ps = getHeader().getOffset() + ZERO_SHIFT; final int TABLE_SIZE = getTableSize(); int pe = ps + TABLE_SIZE; for (int p=ps; p implements ClusterI.ObjectProcedure { int sKey; ClusterBase big; public ForeachObject(int sKey, ClusterBase big) { this.sKey = sKey; this.big = big; } @Override public boolean execute(Context context, int completeRef) throws DatabaseException { ClusterI.CompleteTypeEnum ct = ClusterTraitsSmall.completeRefAndTypeGetType(completeRef); int p = ClusterTraitsBase.getCompleteTypeResourceKeyFromEnum(ct); int o = small.execute(completeRef & 0xFFFF); big.addRelation(sKey, p, o, support); return false; // Continue looping. } } ForeachObject op = new ForeachObject(subjectKey, big); small.getCompleteTable().foreach(cr & 0xFFFF, op, null, support, null); } } int pi = ResourceElementSmall.getPredicateIndex(table, p); if (0 != pi) { ToBigStatements tbs = new ToBigStatements(small, big, support, subjectKey); small.getPredicateTable().foreach(pi, tbs, null, null, null); } else { int p1 = ResourceElementSmall.getStm1Predicate(table, p); int o1 = ResourceElementSmall.getStm1Object(table, p); if (p1 != 0) { int pk1 = small.execute(p1); int ok1 = small.execute(o1); big.addRelation(subjectKey, pk1, ok1, support); int p2 = ResourceElementSmall.getStm2Predicate(table, p); int o2 = ResourceElementSmall.getStm2Object(table, p); if (p2 != 0) { int pk2 = small.execute(p2); int ok2 = small.execute(o2); big.addRelation(subjectKey, pk2, ok2, support); } } } int valueIndex = ResourceElementSmall.getValueIndex(table, p); if (ClusterTraitsSmall.VALUE_INDEX_EX == valueIndex) big.setValueEx(subjectKey); else { byte[] value = ResourceElementSmall.getValue((ValueTableSmall)small.getValueTable(), table, p); if (null != value) big.setValue(subjectKey, value, value.length, support); } } } @Override public boolean foreach(int setIndex, Procedure procedure, Context context, ClusterSupport support, Modifier modifier) throws DatabaseException { throw new UnsupportedOperationException(); } } class CalculateStatementsSmall implements ClusterI.PredicateProcedure { private static final Logger LOGGER = LoggerFactory.getLogger(CalculateStatementsSmall.class); private ObjectTable ot; private final int sRef; CalculateStatementsSmall(int sRef, ObjectTable ot) { this.sRef = sRef; this.ot = ot; } @Override public boolean execute(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 GetStatementsSmall implements ClusterI.PredicateProcedure, ClusterI.ObjectProcedure { private ObjectTable ot; private final ArrayList stms = new ArrayList(); GetStatementsSmall(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 } } class ToBigStatements implements PredicateProcedure, ObjectProcedure { private ClusterBase small; private ClusterBase big; private ClusterSupport support; private int subjectKey; ToBigStatements(ClusterBase small, ClusterBase big, ClusterSupport support, int subjectKey) { this.small = small; this.big = big; this.support = support; this.subjectKey = subjectKey; } @Override public boolean execute(Object context, int pRef, int oIndex) { try { small.getObjectTable().foreach(oIndex, this, pRef, null, null); } catch (DatabaseException e) { e.printStackTrace(); return false; // continue looping } return false; // continue looping } @Override public boolean execute(Integer pRef, int oRef) throws DatabaseException { int pKey = small.execute(pRef); int oKey = small.execute(oRef); big.addRelation(subjectKey, pKey, oKey, support); return false; // continue looping } }