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 gnu.trove.map.hash.TIntIntHashMap;
15 import gnu.trove.procedure.TIntIntProcedure;
16 import gnu.trove.set.hash.TIntHashSet;
18 import org.simantics.db.exception.DatabaseException;
19 import org.simantics.db.exception.ValidationException;
20 import org.simantics.db.impl.ClusterBase;
21 import org.simantics.db.impl.ClusterI;
22 import org.simantics.db.impl.ClusterI.ObjectProcedure;
23 import org.simantics.db.impl.ClusterI.PredicateProcedure;
24 import org.simantics.db.impl.ClusterI.Procedure;
25 import org.simantics.db.impl.ClusterSupport;
26 import org.simantics.db.impl.Modifier;
27 import org.simantics.db.impl.Table;
28 import org.simantics.db.impl.TableFactory;
29 import org.simantics.db.impl.TableIntAllocatorAdapter;
30 import org.simantics.db.impl.TableSizeListener;
31 import org.simantics.db.procore.cluster.TableIntArraySet2.Tables;
33 public final class PredicateTable extends Table<int[]> {
35 final TableIntAllocatorAdapter allocator;
37 public PredicateTable(TableSizeListener sizeListener, int[] header, int headerBase) {
38 super(TableFactory.getIntFactory(), sizeListener, header, headerBase);
39 allocator = new TableIntAllocatorAdapter(this);
41 public PredicateTable(TableSizeListener sizeListener, int[] header, int headerBase, int[] ints) {
42 super(TableFactory.getIntFactory(), sizeListener, header, headerBase, ints);
43 allocator = new TableIntAllocatorAdapter(this);
45 int createPredicateSet(int[] ps, int[] os)
46 throws DatabaseException {
47 int hashBase = TableIntArraySet2.create(ps, os, allocator);
48 return convertRealIndexToTableIndex(hashBase);
50 void deletePredicateSet(int predicateIndex) {
51 int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);
52 if (TableIntArraySet2.isArraySet(getTable(), hashBase)) {
53 int capacity = TableIntArraySet2.getAllocatedSize(getTable(), hashBase);
54 int elementIndex = predicateIndex - TableIntArraySet2.HeaderSize;
55 deleteOldElement(elementIndex, capacity);
57 int capacity = TableIntSet2.getAllocatedSize(getTable(), hashBase);
58 int elementIndex = predicateIndex - TableIntSet2.HeaderSize;
59 deleteOldElement(elementIndex, capacity);
62 public int getPredicateSetSize(int predicateIndex) {
63 int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);
64 if (TableIntArraySet2.isArraySet(getTable(), hashBase))
65 return TableIntArraySet2.getSize(getTable(), hashBase);
67 return TableIntSet2.getSize(getTable(), hashBase);
69 public int getObjectIndex(int predicateIndex, int pRef) {
70 int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);
71 if (TableIntArraySet2.isArraySet(table, hashBase))
72 return TableIntArraySet2.get(table, hashBase, pRef);
74 return TableIntSet2.get(table, hashBase, pRef);
77 private int addPredicateArray(int predicateIndex, int hashBase, int pReference, int oReference, ObjectTable ot)
78 throws DatabaseException {
80 int objectIndex = TableIntArraySet2.get(getTable(), hashBase, pReference);
81 if (0 == objectIndex) {
82 newHashBase = TableIntArraySet2.addInt(getTable(), hashBase, pReference, oReference, allocator);
83 } else if (ClusterTraits.statementIndexIsDirect(objectIndex)) {
84 int oRef = objectIndex;
85 if (oRef == oReference) {
86 return 0; // old direct object
88 objectIndex = ot.createObjectSet(oRef, oReference);
89 assert(0 != objectIndex);
90 int newObjectIndex = ClusterTraits.statementIndexMake(objectIndex);
91 newHashBase = TableIntArraySet2.addInt(getTable(), hashBase, pReference, newObjectIndex, allocator);
93 int newObjectIndex = ot.addObject(ClusterTraits.statementIndexGet(objectIndex), oReference);
94 if (0 == newObjectIndex)
95 return 0; // old indirect object
96 newObjectIndex = ClusterTraits.statementIndexMake(newObjectIndex);
97 newHashBase = TableIntArraySet2.addInt(getTable(), hashBase, pReference, newObjectIndex, allocator);
101 int TABLE_SIZE = TableIntArraySet2.getSize(getTable(), newHashBase);
103 return convertToPredicateSet(predicateIndex, newHashBase);
106 private int convertToPredicateSet(int predicateIndex, int hashBase) {
107 Tables tables = TableIntArraySet2.getInts(getTable(), hashBase);
108 this.deletePredicateSet(predicateIndex);
109 int newHashBase = TableIntSet2.create(tables.keys, tables.vals, allocator);
110 assert(0 != newHashBase);
113 private int addPredicateSet(int hashBase, int pReference, int oReference, ObjectTable ot)
114 throws DatabaseException {
115 int objectIndex = TableIntSet2.get(getTable(), hashBase, pReference);
117 if (0 == objectIndex) {
118 newHashBase = TableIntSet2.addInt(getTable(), hashBase, pReference, oReference, allocator);
119 } else if (ClusterTraits.statementIndexIsDirect(objectIndex)) {
120 int oRef = objectIndex;
121 if (oRef == oReference) {
122 return 0; // old direct object
124 objectIndex = ot.createObjectSet(oRef, oReference);
125 assert(0 != objectIndex);
126 int newObjectIndex = ClusterTraits.statementIndexMake(objectIndex);
127 newHashBase = TableIntSet2.addInt(getTable(), hashBase, pReference, newObjectIndex, allocator);
128 assert(0 != newHashBase);
130 int newObjectIndex = ot.addObject(ClusterTraits.statementIndexGet(objectIndex), oReference);
131 if (0 == newObjectIndex)
132 return 0; // old indirect object
133 int stmIndex = ClusterTraits.statementIndexMake(newObjectIndex);
134 newHashBase = TableIntSet2.addInt(getTable(), hashBase, pReference, stmIndex, allocator);
135 if (newHashBase == 0)
136 return hashBase; // new object added to old predicate (set)
141 * @param predicateIndex
143 * @return zero if element was not added or predicate index.
144 * Predicate index will change if new space is allocated.
146 public int addPredicate(int predicateIndex, int pReference, int oReference, ObjectTable ot)
147 throws DatabaseException {
148 int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);
150 if (TableIntArraySet2.isArraySet(getTable(), hashBase))
151 newHashBase = addPredicateArray(predicateIndex, hashBase, pReference, oReference, ot);
153 newHashBase = addPredicateSet(hashBase, pReference, oReference, ot);
154 if (0 == newHashBase)
155 return 0; // not modified
156 return convertRealIndexToTableIndex(newHashBase);
164 * @param predicateIndex
165 * @param oResourceIndex
166 * @return null if nothing was removed. Status if either object or both
167 * object and predicate were removed.
169 public Status removePredicate(int predicateIndex, int pReference, int oReference, ObjectTable ot)
170 throws DatabaseException {
171 int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);
172 int[] table = getTable();
173 if (TableIntArraySet2.isArraySet(table, hashBase)) {
174 int objectIndex = TableIntArraySet2.get(table, hashBase, pReference);
175 if (0 == objectIndex) {
176 return Status.NothingRemoved;
177 } else if (ClusterTraits.statementIndexIsDirect(objectIndex)) {
178 int oRef = objectIndex;
179 if (oRef != oReference)
180 return Status.NothingRemoved;
181 if (TableIntArraySet2.removeInt(table, hashBase, pReference))
182 return Status.PredicateRemoved;
184 throw new DatabaseException("Internal error during remove.");
186 int oIndex = ClusterTraits.statementIndexGet(objectIndex);
187 int nO = ot.getObjectSetSize(oIndex);
189 throw new DatabaseException("Illegal object set size="+nO);
190 int nObject = ot.removeObject(objectIndex, oReference);
192 ot.deleteObjectSet(oIndex);
193 if (TableIntArraySet2.removeInt(table, hashBase, pReference))
194 return Status.PredicateRemoved;
196 throw new DatabaseException("Internal error during remove (2).");
197 } else if (nO == nObject)
198 return Status.NothingRemoved;
200 return Status.ObjectRemoved;
203 int objectIndex = TableIntSet2.get(table, hashBase, pReference);
204 if (0 == objectIndex) {
205 return Status.NothingRemoved;
206 } else if (ClusterTraits.statementIndexIsDirect(objectIndex)) {
207 int oRef = objectIndex;
208 if (oRef != oReference)
209 return Status.NothingRemoved;
210 if (TableIntSet2.removeInt(table, hashBase, pReference))
211 return Status.PredicateRemoved;
213 throw new DatabaseException("Internal error during remove (3).");
215 int oIndex = ClusterTraits.statementIndexGet(objectIndex);
216 int nO = ot.getObjectSetSize(oIndex);
218 throw new DatabaseException("Illegal object set size="+nO);
219 int nObject = ot.removeObject(objectIndex, oReference);
221 ot.deleteObjectSet(oIndex);
222 if (TableIntSet2.removeInt(table, hashBase, pReference))
223 return Status.PredicateRemoved;
225 throw new DatabaseException("Internal error during remove (4).");
226 } else if (nO == nObject)
227 return Status.NothingRemoved;
229 return Status.ObjectRemoved;
233 public <Context> boolean foreachPredicate(int predicateIndex
234 , ClusterI.PredicateProcedure<Context> procedure
235 , Context context, ClusterSupport support, Modifier modifier)
236 throws DatabaseException {
237 final int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);
239 if (TableIntArraySet2.isArraySet(getTable(), hashBase))
240 ret = TableIntArraySet2.foreachInt(getTable(), hashBase, procedure, context, modifier);
242 ret = TableIntSet2.foreachInt(getTable(), hashBase, procedure, context, modifier);
245 private void checkEntry(ClusterBase cluster, int[] table, int index)
246 throws DatabaseException {
247 assert(ClusterTraits.statementIndexIsDirect(table[index]));
248 int dr = table[index];
249 cluster.checkDirectReference(dr);
250 assert(table[index+1] != 0);
251 if (ClusterTraits.statementIndexIsDirect(table[index+1])) {
252 cluster.checkDirectReference(table[index+1]);
254 cluster.checkObjectSetReference(table[index+1]);
257 private TIntHashSet checkIndexSet = null;
258 public void check(ClusterBase cluster)
259 throws DatabaseException {
260 if (null == checkIndexSet)
261 checkIndexSet = new TIntHashSet();
263 checkIndexSet.clear();
265 int[] table = getTable();
266 int ps = getHeader().getOffset() + ZERO_SHIFT;
267 int pe = ps + getTableSize();
268 for (int p=ps; p<pe;) {
270 if (table[cap] >= 0) {
274 assert(table[cap] >= table[use] + table[fre]);
275 assert(table[max] == table[cap] >> 1);
276 assert(table[max]+1 >= table[use]);
277 checkIndexSet.add(p - ps);
278 for (int e = p + table[cap]*2; p<e; p+=2) {
279 if (!IntHashTrait.isFull(table[p]))
280 assert(table[p+1]==0);
282 checkEntry(cluster, table, p);
285 final int size = -table[cap];
287 boolean free = false;
288 checkIndexSet.add(p - ps);
289 for (int e = p + size*2; p<e; p+=2) {
291 assert(table[p] == 0);
292 assert(table[p+1] == 0);
294 else if (table[p] == 0) {
295 assert(table[p+1] == 0);
298 checkEntry(cluster, table, p);
303 assert(getHeader().getCount() <= count); // deleted objects are not recognized
305 public final void checkPredicateSetIndex(ClusterBase cluster, int i)
306 throws DatabaseException {
307 if (null == checkIndexSet)
308 check(cluster); // builds checkIndexSet
309 if (!checkIndexSet.contains(i-ZERO_SHIFT))
310 throw new ValidationException("Illegal predicate set index=" + i);
312 public void printDebugInfo() {
314 int[] table = getTable();
315 int ps = getHeader().getOffset() + ZERO_SHIFT;
316 int pe = ps + getTableSize();
317 TIntIntHashMap stat = new TIntIntHashMap();
318 TIntIntHashMap stat2 = new TIntIntHashMap();
319 for (int p=ps; p<pe;) {
321 if (table[cap] >= 0) {
325 assert(table[cap] >= table[use] + table[fre]);
326 assert(table[max] == table[cap] >> 1);
328 int val = stat.get(table[use]) + 1;
329 stat.put(table[use], val);
331 final int size = -table[cap];
332 int val = stat2.get(size) + 1;
333 stat2.put(size, val);
338 //assert(getHeader().getCount() == count);
339 stat.forEachEntry(new TIntIntProcedure() {
341 public boolean execute(int a, int b) {
342 System.out.println("predicate set capacity " + a + " instance count " + b);
346 stat2.forEachEntry(new TIntIntProcedure() {
348 public boolean execute(int a, int b) {
349 System.out.println("predicate array set capacity " + a + " instance count " + b);
355 public <Context> boolean foreach(int setIndex, Procedure procedure, Context context,
356 ClusterSupport support, Modifier modifier) throws DatabaseException {
357 return foreachPredicate(setIndex, (PredicateProcedure<Context>)procedure, context, support, modifier);