1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.db.procore.cluster;
14 import org.simantics.db.exception.DatabaseException;
15 import org.simantics.db.exception.ValidationException;
16 import org.simantics.db.impl.ClusterBase;
17 import org.simantics.db.impl.ClusterI;
18 import org.simantics.db.impl.ClusterI.PredicateProcedure;
19 import org.simantics.db.impl.ClusterI.Procedure;
20 import org.simantics.db.impl.ClusterSupport;
21 import org.simantics.db.impl.Modifier;
22 import org.simantics.db.impl.Table;
23 import org.simantics.db.impl.TableFactory;
24 import org.simantics.db.impl.TableIntAllocatorAdapter;
25 import org.simantics.db.impl.TableSizeListener;
26 import org.simantics.db.procore.cluster.TableIntArraySet2.Tables;
28 import gnu.trove.map.hash.TIntIntHashMap;
29 import gnu.trove.procedure.TIntIntProcedure;
30 import gnu.trove.set.hash.TIntHashSet;
32 public final class PredicateTable extends Table<int[]> {
34 final TableIntAllocatorAdapter allocator;
36 public PredicateTable(TableSizeListener sizeListener, int[] header, int headerBase) {
37 super(TableFactory.getIntFactory(), sizeListener, header, headerBase);
38 allocator = new TableIntAllocatorAdapter(this);
40 public PredicateTable(TableSizeListener sizeListener, int[] header, int headerBase, int[] ints) {
41 super(TableFactory.getIntFactory(), sizeListener, header, headerBase, ints);
42 allocator = new TableIntAllocatorAdapter(this);
44 int createPredicateSet(int[] ps, int[] os)
45 throws DatabaseException {
46 int hashBase = TableIntArraySet2.create(ps, os, allocator);
47 return convertRealIndexToTableIndex(hashBase);
49 void deletePredicateSet(int predicateIndex) {
50 int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);
51 if (TableIntArraySet2.isArraySet(getTable(), hashBase)) {
52 int capacity = TableIntArraySet2.getAllocatedSize(getTable(), hashBase);
53 int elementIndex = predicateIndex - TableIntArraySet2.HeaderSize;
54 deleteOldElement(elementIndex, capacity);
56 int capacity = TableIntSet2.getAllocatedSize(getTable(), hashBase);
57 int elementIndex = predicateIndex - TableIntSet2.HeaderSize;
58 deleteOldElement(elementIndex, capacity);
61 public int getPredicateSetSize(int predicateIndex) {
62 int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);
63 if (TableIntArraySet2.isArraySet(getTable(), hashBase))
64 return TableIntArraySet2.getSize(getTable(), hashBase);
66 return TableIntSet2.getSize(getTable(), hashBase);
68 public int getObjectIndex(int predicateIndex, int pRef) {
69 int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);
70 if (TableIntArraySet2.isArraySet(table, hashBase))
71 return TableIntArraySet2.get(table, hashBase, pRef);
73 return TableIntSet2.get(table, hashBase, pRef);
76 private int addPredicateArray(int predicateIndex, int hashBase, int pReference, int oReference, ObjectTable ot)
77 throws DatabaseException {
79 int objectIndex = TableIntArraySet2.get(getTable(), hashBase, pReference);
80 if (0 == objectIndex) {
81 newHashBase = TableIntArraySet2.addInt(getTable(), hashBase, pReference, oReference, allocator);
82 } else if (ClusterTraits.statementIndexIsDirect(objectIndex)) {
83 int oRef = objectIndex;
84 if (oRef == oReference) {
85 return 0; // old direct object
87 objectIndex = ot.createObjectSet(oRef, oReference);
88 assert(0 != objectIndex);
89 int newObjectIndex = ClusterTraits.statementIndexMake(objectIndex);
90 newHashBase = TableIntArraySet2.addInt(getTable(), hashBase, pReference, newObjectIndex, allocator);
92 int newObjectIndex = ot.addObject(ClusterTraits.statementIndexGet(objectIndex), oReference);
93 if (0 == newObjectIndex)
94 return 0; // old indirect object
95 newObjectIndex = ClusterTraits.statementIndexMake(newObjectIndex);
96 newHashBase = TableIntArraySet2.addInt(getTable(), hashBase, pReference, newObjectIndex, allocator);
100 int TABLE_SIZE = TableIntArraySet2.getSize(getTable(), newHashBase);
102 return convertToPredicateSet(predicateIndex, newHashBase);
105 private int convertToPredicateSet(int predicateIndex, int hashBase) {
106 Tables tables = TableIntArraySet2.getInts(getTable(), hashBase);
107 this.deletePredicateSet(predicateIndex);
108 int newHashBase = TableIntSet2.create(tables.keys, tables.vals, allocator);
109 assert(0 != newHashBase);
112 private int addPredicateSet(int hashBase, int pReference, int oReference, ObjectTable ot)
113 throws DatabaseException {
114 int objectIndex = TableIntSet2.get(getTable(), hashBase, pReference);
116 if (0 == objectIndex) {
117 newHashBase = TableIntSet2.addInt(getTable(), hashBase, pReference, oReference, allocator);
118 } else if (ClusterTraits.statementIndexIsDirect(objectIndex)) {
119 int oRef = objectIndex;
120 if (oRef == oReference) {
121 return 0; // old direct object
123 objectIndex = ot.createObjectSet(oRef, oReference);
124 assert(0 != objectIndex);
125 int newObjectIndex = ClusterTraits.statementIndexMake(objectIndex);
126 newHashBase = TableIntSet2.addInt(getTable(), hashBase, pReference, newObjectIndex, allocator);
127 assert(0 != newHashBase);
129 int newObjectIndex = ot.addObject(ClusterTraits.statementIndexGet(objectIndex), oReference);
130 if (0 == newObjectIndex)
131 return 0; // old indirect object
132 int stmIndex = ClusterTraits.statementIndexMake(newObjectIndex);
133 newHashBase = TableIntSet2.addInt(getTable(), hashBase, pReference, stmIndex, allocator);
134 if (newHashBase == 0)
135 return hashBase; // new object added to old predicate (set)
140 * @param predicateIndex
142 * @return zero if element was not added or predicate index.
143 * Predicate index will change if new space is allocated.
145 public int addPredicate(int predicateIndex, int pReference, int oReference, ObjectTable ot)
146 throws DatabaseException {
147 int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);
149 if (TableIntArraySet2.isArraySet(getTable(), hashBase))
150 newHashBase = addPredicateArray(predicateIndex, hashBase, pReference, oReference, ot);
152 newHashBase = addPredicateSet(hashBase, pReference, oReference, ot);
153 if (0 == newHashBase)
154 return 0; // not modified
155 return convertRealIndexToTableIndex(newHashBase);
163 * @param predicateIndex
164 * @param oResourceIndex
165 * @return null if nothing was removed. Status if either object or both
166 * object and predicate were removed.
168 public Status removePredicate(int predicateIndex, int pReference, int oReference, ObjectTable ot)
169 throws DatabaseException {
170 int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);
171 int[] table = getTable();
172 if (TableIntArraySet2.isArraySet(table, hashBase)) {
173 int objectIndex = TableIntArraySet2.get(table, hashBase, pReference);
174 if (0 == objectIndex) {
175 return Status.NothingRemoved;
176 } else if (ClusterTraits.statementIndexIsDirect(objectIndex)) {
177 int oRef = objectIndex;
178 if (oRef != oReference)
179 return Status.NothingRemoved;
180 if (TableIntArraySet2.removeInt(table, hashBase, pReference))
181 return Status.PredicateRemoved;
183 throw new DatabaseException("Internal error during remove.");
185 int oIndex = ClusterTraits.statementIndexGet(objectIndex);
186 int nO = ot.getObjectSetSize(oIndex);
188 throw new DatabaseException("Illegal object set size="+nO);
189 int nObject = ot.removeObject(objectIndex, oReference);
191 ot.deleteObjectSet(oIndex);
192 if (TableIntArraySet2.removeInt(table, hashBase, pReference))
193 return Status.PredicateRemoved;
195 throw new DatabaseException("Internal error during remove (2).");
196 } else if (nO == nObject)
197 return Status.NothingRemoved;
199 return Status.ObjectRemoved;
202 int objectIndex = TableIntSet2.get(table, hashBase, pReference);
203 if (0 == objectIndex) {
204 return Status.NothingRemoved;
205 } else if (ClusterTraits.statementIndexIsDirect(objectIndex)) {
206 int oRef = objectIndex;
207 if (oRef != oReference)
208 return Status.NothingRemoved;
209 if (TableIntSet2.removeInt(table, hashBase, pReference))
210 return Status.PredicateRemoved;
212 throw new DatabaseException("Internal error during remove (3).");
214 int oIndex = ClusterTraits.statementIndexGet(objectIndex);
215 int nO = ot.getObjectSetSize(oIndex);
217 throw new DatabaseException("Illegal object set size="+nO);
218 int nObject = ot.removeObject(objectIndex, oReference);
220 ot.deleteObjectSet(oIndex);
221 if (TableIntSet2.removeInt(table, hashBase, pReference))
222 return Status.PredicateRemoved;
224 throw new DatabaseException("Internal error during remove (4).");
225 } else if (nO == nObject)
226 return Status.NothingRemoved;
228 return Status.ObjectRemoved;
232 public <Context> boolean foreachPredicate(int predicateIndex
233 , ClusterI.PredicateProcedure<Context> procedure
234 , Context context, ClusterSupport support, Modifier modifier)
235 throws DatabaseException {
236 final int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);
238 if (TableIntArraySet2.isArraySet(getTable(), hashBase))
239 ret = TableIntArraySet2.foreachInt(getTable(), hashBase, procedure, context, modifier);
241 ret = TableIntSet2.foreachInt(getTable(), hashBase, procedure, context, modifier);
244 private void checkEntry(ClusterBase cluster, int[] table, int index)
245 throws DatabaseException {
246 assert(ClusterTraits.statementIndexIsDirect(table[index]));
247 int dr = table[index];
248 cluster.checkDirectReference(dr);
249 assert(table[index+1] != 0);
250 if (ClusterTraits.statementIndexIsDirect(table[index+1])) {
251 cluster.checkDirectReference(table[index+1]);
253 cluster.checkObjectSetReference(table[index+1]);
256 private TIntHashSet checkIndexSet = null;
257 public void check(ClusterBase cluster)
258 throws DatabaseException {
259 if (null == checkIndexSet)
260 checkIndexSet = new TIntHashSet();
262 checkIndexSet.clear();
264 int[] table = getTable();
265 int ps = getHeader().getOffset() + ZERO_SHIFT;
266 int pe = ps + getTableSize();
267 for (int p=ps; p<pe;) {
269 if (table[cap] >= 0) {
273 assert(table[cap] >= table[use] + table[fre]);
274 assert(table[max] == table[cap] >> 1);
275 assert(table[max]+1 >= table[use]);
276 checkIndexSet.add(p - ps);
277 for (int e = p + table[cap]*2; p<e; p+=2) {
278 if (!IntHashTrait.isFull(table[p]))
279 assert(table[p+1]==0);
281 checkEntry(cluster, table, p);
284 final int size = -table[cap];
286 boolean free = false;
287 checkIndexSet.add(p - ps);
288 for (int e = p + size*2; p<e; p+=2) {
290 assert(table[p] == 0);
291 assert(table[p+1] == 0);
293 else if (table[p] == 0) {
294 assert(table[p+1] == 0);
297 checkEntry(cluster, table, p);
302 assert(getHeader().getCount() <= count); // deleted objects are not recognized
304 public final void checkPredicateSetIndex(ClusterBase cluster, int i)
305 throws DatabaseException {
306 if (null == checkIndexSet)
307 check(cluster); // builds checkIndexSet
308 if (!checkIndexSet.contains(i-ZERO_SHIFT))
309 throw new ValidationException("Illegal predicate set index=" + i);
311 public void printDebugInfo() {
313 int[] table = getTable();
314 int ps = getHeader().getOffset() + ZERO_SHIFT;
315 int pe = ps + getTableSize();
316 TIntIntHashMap stat = new TIntIntHashMap();
317 TIntIntHashMap stat2 = new TIntIntHashMap();
318 for (int p=ps; p<pe;) {
320 if (table[cap] >= 0) {
324 assert(table[cap] >= table[use] + table[fre]);
325 assert(table[max] == table[cap] >> 1);
327 int val = stat.get(table[use]) + 1;
328 stat.put(table[use], val);
330 final int size = -table[cap];
331 int val = stat2.get(size) + 1;
332 stat2.put(size, val);
337 //assert(getHeader().getCount() == count);
338 stat.forEachEntry(new TIntIntProcedure() {
340 public boolean execute(int a, int b) {
341 System.out.println("predicate set capacity " + a + " instance count " + b);
345 stat2.forEachEntry(new TIntIntProcedure() {
347 public boolean execute(int a, int b) {
348 System.out.println("predicate array set capacity " + a + " instance count " + b);
354 public <Context> boolean foreach(int setIndex, Procedure procedure, Context context,
355 ClusterSupport support, Modifier modifier) throws DatabaseException {
356 return foreachPredicate(setIndex, (PredicateProcedure<Context>)procedure, context, support, modifier);