]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.procore/src/org/simantics/db/procore/cluster/ClusterSmall.java
Removed contact application support prints
[simantics/platform.git] / bundles / org.simantics.db.procore / src / org / simantics / db / procore / cluster / ClusterSmall.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
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
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.db.procore.cluster;
13
14 import java.io.ByteArrayInputStream;
15 import java.io.InputStream;
16 import java.util.function.Consumer;
17
18 import org.simantics.db.Resource;
19 import org.simantics.db.exception.DatabaseException;
20 import org.simantics.db.exception.ExternalValueException;
21 import org.simantics.db.exception.ValidationException;
22 import org.simantics.db.impl.ClusterI;
23 import org.simantics.db.impl.ClusterSupport;
24 import org.simantics.db.impl.ClusterTraitsBase;
25 import org.simantics.db.impl.ForEachObjectContextProcedure;
26 import org.simantics.db.impl.ForEachObjectProcedure;
27 import org.simantics.db.impl.ForPossibleRelatedValueContextProcedure;
28 import org.simantics.db.impl.ForPossibleRelatedValueProcedure;
29 import org.simantics.db.impl.Table;
30 import org.simantics.db.impl.TableHeader;
31 import org.simantics.db.impl.graph.ReadGraphImpl;
32 import org.simantics.db.procedure.SyncContextMultiProcedure;
33 import org.simantics.db.procedure.SyncMultiProcedure;
34 import org.simantics.db.service.ClusterUID;
35 import org.simantics.db.service.ResourceUID;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 import fi.vtt.simantics.procore.DebugPolicy;
40 import fi.vtt.simantics.procore.internal.ClusterChange;
41 import fi.vtt.simantics.procore.internal.ClusterStream;
42 import fi.vtt.simantics.procore.internal.ClusterTable;
43 import fi.vtt.simantics.procore.internal.SessionImplSocket;
44 import gnu.trove.map.hash.TIntShortHashMap;
45 import gnu.trove.set.hash.TIntHashSet;
46
47 final public class ClusterSmall extends ClusterImpl {
48         
49         private static final Logger LOGGER = LoggerFactory.getLogger(ClusterSmall.class);
50     
51     private static final int TABLE_HEADER_SIZE = TableHeader.HEADER_SIZE + TableHeader.EXTRA_SIZE;
52     private static final int RESOURCE_TABLE_OFFSET = 0;
53     private static final int PREDICATE_TABLE_OFFSET = RESOURCE_TABLE_OFFSET + TABLE_HEADER_SIZE;
54     private static final int OBJECT_TABLE_OFFSET = PREDICATE_TABLE_OFFSET + TABLE_HEADER_SIZE;
55     private static final int VALUE_TABLE_OFFSET = OBJECT_TABLE_OFFSET + TABLE_HEADER_SIZE;
56     private static final int FLAT_TABLE_OFFSET = VALUE_TABLE_OFFSET + TABLE_HEADER_SIZE;
57     private static final int COMPLETE_TABLE_OFFSET = FLAT_TABLE_OFFSET + TABLE_HEADER_SIZE;
58     private static final int FOREIGN_TABLE_OFFSET = COMPLETE_TABLE_OFFSET + TABLE_HEADER_SIZE;
59     private static final int INT_HEADER_SIZE = FOREIGN_TABLE_OFFSET + TABLE_HEADER_SIZE;
60     private final int clusterBits;
61     public final ResourceTableSmall resourceTable;
62     private PredicateTable predicateTable;
63     final ObjectTable objectTable;
64     public final ValueTableSmall valueTable;
65     public final ForeignTableSmall foreignTable;
66     private final CompleteTableSmall completeTable;
67     private final ClusterMapSmall clusterMap;
68     private final int[] headerTable;
69     private final ClusterSupport clusterSupport;
70     private boolean proxy;
71     private boolean deleted = false;
72     
73     public ClusterSmall(ClusterUID clusterUID, int clusterKey, ClusterTable clusterTable, ClusterSupport support) {
74         super(clusterUID, clusterKey, support);
75         if(DebugPolicy.REPORT_CLUSTER_EVENTS)
76             new Exception(clusterUID.toString()).printStackTrace();
77         this.proxy = true;
78         this.headerTable = null;
79         this.resourceTable = null;
80         this.foreignTable = null;
81         this.predicateTable = null;
82         this.objectTable = null;
83         this.valueTable = null;
84         this.completeTable = null;
85         this.clusterMap = null;
86         this.clusterSupport = null;
87         this.clusterBits = 0;
88         this.importance = 0;
89     }
90     public ClusterSmall(ClusterUID clusterUID, int clusterKey, ClusterSupport support) {
91         super(clusterUID, clusterKey, support);
92         if(DebugPolicy.REPORT_CLUSTER_EVENTS)
93             new Exception(clusterUID.toString()).printStackTrace();
94         this.proxy = false;
95         this.headerTable = new int[INT_HEADER_SIZE];
96         this.resourceTable = new ResourceTableSmall(this, headerTable, RESOURCE_TABLE_OFFSET);
97         this.foreignTable = new ForeignTableSmall(this, headerTable, FOREIGN_TABLE_OFFSET);
98         this.predicateTable = new PredicateTable(this, headerTable, PREDICATE_TABLE_OFFSET);
99         this.objectTable = new ObjectTable(this, headerTable, OBJECT_TABLE_OFFSET);
100         this.valueTable = new ValueTableSmall(this, headerTable, VALUE_TABLE_OFFSET);
101         this.completeTable = new CompleteTableSmall(this, headerTable, COMPLETE_TABLE_OFFSET);
102         this.clusterMap = new ClusterMapSmall(this, foreignTable);
103         this.clusterSupport = support;
104         this.clusterBits = ClusterTraitsBase.getClusterBits(clusterKey);
105         this.importance = -clusterTable.timeCounter();
106     }
107     protected ClusterSmall(long[] longs, int[] ints, byte[] bytes, ClusterSupport support, int clusterKey)
108     throws DatabaseException {
109         super(checkValidity(-1, longs, ints, bytes), clusterKey, support);
110         this.proxy = false;
111         if (ints.length < INT_HEADER_SIZE)
112             throw new IllegalArgumentException("Too small integer table for cluster.");
113         this.headerTable = ints;
114         if(DebugPolicy.REPORT_CLUSTER_EVENTS) new Exception(Long.toString(clusterId)).printStackTrace();
115         this.resourceTable = new ResourceTableSmall(this, ints, RESOURCE_TABLE_OFFSET, longs);
116         this.foreignTable = new ForeignTableSmall(this, headerTable, FOREIGN_TABLE_OFFSET, longs);
117         this.predicateTable = new PredicateTable(this, ints, PREDICATE_TABLE_OFFSET, ints);
118         this.objectTable = new ObjectTable(this, ints, OBJECT_TABLE_OFFSET, ints);
119         this.valueTable = new ValueTableSmall(this, ints, VALUE_TABLE_OFFSET, bytes);
120         this.completeTable = new CompleteTableSmall(this, headerTable, COMPLETE_TABLE_OFFSET, ints);
121         this.clusterMap = new ClusterMapSmall(this, foreignTable);
122         this.clusterSupport = support;
123         this.clusterBits = ClusterTraitsBase.getClusterBits(clusterKey);
124         this.importance = clusterTable.timeCounter();
125         clusterTable.markImmutable(this, getImmutable());
126     }
127     void analyse() {
128         System.out.println("Cluster " + clusterId);
129         System.out.println("-size:" + getUsedSpace());
130         System.out.println(" -rt:" + (resourceTable.getTableCapacity() * 8 + 8));
131         System.out.println(" -ft:" + foreignTable.getTableCapacity() * 8);
132         System.out.println(" -pt:" + predicateTable.getTableCapacity() * 4);
133         System.out.println(" -ot:" + objectTable.getTableCapacity() * 4);
134         System.out.println(" -ct:" + completeTable.getTableCapacity() * 4);
135         System.out.println(" -vt:" + valueTable.getTableCapacity());
136
137         System.out.println("-resourceTable:");
138         System.out.println(" -resourceCount=" + resourceTable.getResourceCount());
139         System.out.println(" -size=" + resourceTable.getTableSize());
140         System.out.println(" -capacity=" + resourceTable.getTableCapacity());
141         System.out.println(" -count=" + resourceTable.getTableCount());
142         System.out.println(" -size=" + resourceTable.getTableSize());
143         //resourceTable.analyse();
144     }
145     public void checkDirectReference(int dr)
146     throws DatabaseException {
147         if (deleted) return;
148         if (!ClusterTraits.statementIndexIsDirect(dr))
149             throw new ValidationException("Reference is not direct. Reference=" + dr);
150         if (ClusterTraits.isFlat(dr))
151             throw new ValidationException("Reference is flat. Reference=" + dr);
152         if (ClusterTraits.isLocal(dr)) {
153             if (dr < 1 || dr > resourceTable.getUsedSize())
154                 throw new ValidationException("Illegal local reference. Reference=" + dr);
155         } else {
156             int fi = ClusterTraits.getForeignIndexFromReference(dr);
157             int ri = ClusterTraits.getResourceIndexFromForeignReference(dr);
158             if (fi < 1 || fi > foreignTable.getUsedSize())
159                 throw new ValidationException("Illegal foreign reference. Reference=" + dr + " foreign index=" + fi);
160             if (ri < 1 || ri > ClusterTraits.getMaxNumberOfResources())
161                 throw new ValidationException("Illegal foreign reference. Reference=" + dr + " resource index=" + ri);
162         }
163     }
164     public void checkPredicateIndex(int pi)
165     throws DatabaseException {
166         if (deleted) return;
167         //        predicateTable.checkPredicateSetIndex(this, pi);
168     }
169     public void checkObjectSetReference(int or)
170     throws DatabaseException {
171         if (deleted) return;
172         if (ClusterTraits.statementIndexIsDirect(or))
173             throw new ValidationException("Illegal object set reference. Reference=" + or);
174         int oi = ClusterTraits.statementIndexGet(or);
175         this.objectTable.checkObjectSetIndex(this, oi);
176     }
177
178     public void checkValueInit()
179     throws DatabaseException {
180         valueTable.checkValueInit();
181     }
182     public void checkValue(int capacity, int index)
183     throws DatabaseException {
184         valueTable.checkValue(capacity, index);
185     }
186     public void checkValueFini()
187     throws DatabaseException {
188         valueTable.checkValueFini();
189     }
190     public void checkForeingIndex(int fi)
191     throws DatabaseException {
192         if (deleted) return;
193         if (fi<1 || fi > foreignTable.getUsedSize())
194             throw new ValidationException("Illegal foreign index=" + fi);
195     }
196     public void checkCompleteSetReference(int cr)
197     throws DatabaseException {
198         if (!ClusterTraits.completeReferenceIsMultiple(cr))
199             throw new ValidationException("Illegal complete set reference. Reference=" + cr);
200         int ci = cr;
201         this.completeTable.checkCompleteSetIndex(this, ci);
202     }
203     public void check()
204     throws DatabaseException {
205         if (deleted) return;
206 //        this.completeTable.check(this);
207 //        this.objectTable.check(this);
208 //        // Must be after object table check.
209 //        this.predicateTable.check(this);
210 //        this.resourceTable.check(this);
211     }
212     @Override
213     public CompleteTypeEnum getCompleteType(int resourceKey, ClusterSupport support)
214     throws DatabaseException {
215         if (deleted) return CompleteTypeEnum.NotComplete;
216         final int resourceRef = getLocalReference(resourceKey);
217         CompleteTypeEnum ct = resourceTable.getCompleteType(resourceRef);
218         if (DEBUG)
219             System.out.println("ClusterSmall.getCompleteType rk=" + resourceKey + " ct=" + ct);
220         return ct;
221     }
222
223     @Override
224     public int getCompleteObjectKey(int resourceKey, ClusterSupport support)
225     throws DatabaseException {
226         if (deleted) return 0;
227         final int resourceIndexOld = getLocalReference(resourceKey);
228         short completeRef = resourceTable.getCompleteObjectRef(resourceIndexOld);
229         int clusterIndex;
230         int resourceIndex;
231         if (0 == completeRef)
232             throw new DatabaseException("Resource's complete object refernce is null. Resource key=" + resourceKey + ".");
233         ClusterI.CompleteTypeEnum completeType = resourceTable.getCompleteType(resourceIndexOld);
234         if (completeType == ClusterI.CompleteTypeEnum.NotComplete)
235             throw new DatabaseException("Resource has multiple complete objects. Resource key=" + resourceKey + ".");
236         if (ClusterTraitsSmall.resourceRefIsLocal(completeRef)) {
237             clusterIndex = clusterKey;
238             resourceIndex = completeRef;
239         } else { // Resource has one complete statement.
240             ResourceUID resourceUID = clusterMap.getForeignResourceUID(completeRef);
241             ClusterI c = support.getClusterByClusterUIDOrMake(resourceUID.asCID());
242             clusterIndex = c.getClusterKey();
243             resourceIndex = resourceUID.getIndex();
244         }
245         int key = ClusterTraits.createResourceKey(clusterIndex, resourceIndex);
246         if (DEBUG)
247             System.out.println("ClusterSmall.complete object rk=" + resourceKey + " ck=" + key);
248         return key;
249     }
250
251     @Override
252     public boolean isComplete(int resourceKey, ClusterSupport support)
253     throws DatabaseException {
254         if (deleted) return false;
255         final int resourceRef = getLocalReference(resourceKey);
256         final ClusterI.CompleteTypeEnum completeType = resourceTable.getCompleteType(resourceRef);
257         boolean complete = completeType != ClusterI.CompleteTypeEnum.NotComplete;
258         if (DEBUG)
259             System.out.println("ClusterSmall.key=" + resourceKey + " isComplete=" + complete);
260         return complete;
261     }
262     public int getSingleObject(int resourceKey, int predicateKey, int objectIndex, ClusterSupport support) throws DatabaseException {
263         if (DEBUG)
264             System.out.println("ClusterSmall.getSingleObject: rk=" + resourceKey + " pk=" + predicateKey);
265         if (deleted) return 0;
266         if (0 == objectIndex) {
267             final int resourceIndex = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(resourceKey);
268             final short pRef = getInternalReferenceOrZero2(predicateKey, support);
269             final ClusterI.CompleteTypeEnum pCompleteType = ClusterTraitsBase.getCompleteTypeFromResourceKey(predicateKey);
270             return resourceTable.getSingleObject(resourceIndex, support, pRef, pCompleteType, completeTable, this);
271         }
272         return objectTable.getSingleObject(objectIndex, support, this);
273     }
274
275     public void forObjects(ReadGraphImpl graph, int resourceKey, int predicateKey, int objectIndex, SyncMultiProcedure<Resource> procedure,
276             ClusterSupport support) throws DatabaseException {
277         if (deleted) return;
278         if (DEBUG)
279             System.out.println("ClusterSmall.forObjects1: rk=" + resourceKey + " pk=" + predicateKey);
280         if (0 == objectIndex) {
281             final int resourceIndex = ClusterTraitsBase.getResourceIndexFromResourceKey(resourceKey);
282             final int pRef = getInternalReferenceOrZero2(predicateKey, support);
283             final ClusterI.CompleteTypeEnum pCompleteType = ClusterTraitsBase.getCompleteTypeFromResourceKey(predicateKey);
284             resourceTable.foreachObject(resourceIndex, graph, procedure, support, pRef, pCompleteType, completeTable, this);
285             return;
286         }
287         objectTable.foreachObject(graph, objectIndex, procedure, this);
288     }
289
290     public <C> void forObjects(ReadGraphImpl graph, int resourceKey, int predicateKey, int objectIndex, C context, SyncContextMultiProcedure<C, Resource> procedure,
291             ClusterSupport support) throws DatabaseException {
292         if (DEBUG)
293             System.out.println("ClusterSmall.forObjects1: rk=" + resourceKey + " pk=" + predicateKey);
294         if (deleted) return;
295         if (0 == objectIndex) {
296             final int resourceIndex = ClusterTraitsBase.getResourceIndexFromResourceKey(resourceKey);
297             final int pRef = getInternalReferenceOrZero2(predicateKey, support);
298             final ClusterI.CompleteTypeEnum pCompleteType = ClusterTraitsBase.getCompleteTypeFromResourceKey(predicateKey);
299             resourceTable.foreachObject(resourceIndex, graph, context, procedure, support, pRef, pCompleteType, completeTable, this);
300             return;
301         }
302         objectTable.foreachObject(graph, objectIndex, context, procedure, this);
303     }
304
305     @Override
306     public <Context> boolean forObjects(int resourceKey, int predicateKey, int objectIndex, ObjectProcedure<Context> procedure,
307             Context context, ClusterSupport support) throws DatabaseException {
308         if (DEBUG)
309             System.out.println("ClusterSmall.forObjects2: rk=" + resourceKey + " pk=" + predicateKey);
310         if (deleted) return false;
311         if (0 == objectIndex) {
312             final int resourceIndex = ClusterTraitsBase.getResourceIndexFromResourceKey(resourceKey);
313             final short pRef = getInternalReferenceOrZero2(predicateKey, support);
314             final ClusterI.CompleteTypeEnum pCompleteType = ClusterTraitsBase.getCompleteTypeFromResourceKey(predicateKey);
315             return resourceTable.foreachObject(resourceIndex, procedure, context, support, this, pRef, pCompleteType, completeTable);
316         }
317         return objectTable.foreachObject(objectIndex, procedure, context, support, this);
318     }
319
320     @Override
321     public int getSingleObject(int resourceKey, int predicateKey, ClusterSupport support) throws DatabaseException {
322         if (DEBUG)
323             System.out.println("ClusterSmall.getSingleObject2: rk=" + resourceKey + " pk=" + predicateKey);
324         if (deleted) return 0;
325         final int resourceIndex = ClusterTraitsBase.getResourceIndexFromResourceKey(resourceKey);
326         final short pRef = getInternalReferenceOrZero2(predicateKey, support);
327         final int completeType = ClusterTraitsBase.getCompleteTypeIntFromResourceKey(predicateKey);
328         final ClusterI.CompleteTypeEnum pCompleteType = CompleteTypeEnum.make(completeType);
329         if (completeType > 0)
330             return resourceTable.getSingleObject(resourceIndex, support, pRef, pCompleteType, completeTable, this);
331         final int predicateIndex = (int)resourceTable.table[(resourceIndex<<1) - 1 + resourceTable.offset] & 0xFFFFFF;
332         if (0 == predicateIndex) // All relevant data is in resource table.
333             return resourceTable.getSingleObject(resourceIndex, support, pRef, pCompleteType, completeTable, this);
334         int objectIndex = predicateTable.getObjectIndex(predicateIndex, pRef & 0xFFFF);
335         return getSingleObject(resourceKey, predicateKey, objectIndex, support);
336     }
337
338     @Override
339     public <T> int getSingleObject(int resourceKey, ForPossibleRelatedValueProcedure<T> procedure, ClusterSupport support) throws DatabaseException {
340         if (deleted) return 0;
341         final short resourceIndex = (short)ClusterTraitsBase.getResourceIndexFromResourceKey(resourceKey);
342         final int predicateKey = procedure.predicateKey;
343         int clusterKey = ClusterTraitsBase.getClusterMaskFromResourceKey(resourceKey);
344         short pRef = 0;
345         if(procedure.clusterKey[0] == clusterKey) {
346             pRef = (short)procedure.predicateReference[0];
347         } else {
348             pRef = getInternalReferenceOrZero2(predicateKey, support);
349             procedure.clusterKey[0] = clusterKey;
350             procedure.predicateReference[0] = pRef;
351         }
352
353         final ClusterI.CompleteTypeEnum pCompleteType = procedure.completeType;
354         if (CompleteTypeEnum.NotComplete != pCompleteType)
355             return resourceTable.getSingleObject(resourceIndex, support, pRef, pCompleteType, completeTable, this);
356         final int predicateIndex = (int)resourceTable.table[(resourceIndex<<1) - 1 + resourceTable.offset] & 0xFFFFFF;
357         if (0 == predicateIndex) // All relevant data is in resource table.
358             return resourceTable.getSingleObject(resourceIndex, support, pRef, pCompleteType, completeTable, this);
359         int objectIndex = predicateTable.getObjectIndex(predicateIndex, pRef & 0xFFFF);
360         return getSingleObject(resourceKey, predicateKey, objectIndex, support);
361     }
362
363     @Override
364     public <C, T> int getSingleObject(int resourceKey, ForPossibleRelatedValueContextProcedure<C, T> procedure, ClusterSupport support) throws DatabaseException {
365         if (deleted) return 0;
366         final short resourceIndex = (short)ClusterTraitsBase.getResourceIndexFromResourceKey(resourceKey);
367         final int predicateKey = procedure.predicateKey;
368         int clusterKey = ClusterTraitsBase.getClusterMaskFromResourceKey(resourceKey);
369         short pRef = 0;
370         if(procedure.clusterKey[0] == clusterKey) {
371             pRef = (short)procedure.predicateReference[0];
372         } else {
373             pRef = getInternalReferenceOrZero2(predicateKey, support);
374             procedure.clusterKey[0] = clusterKey;
375             procedure.predicateReference[0] = pRef;
376         }
377         final ClusterI.CompleteTypeEnum pCompleteType = procedure.completeType;
378         if (CompleteTypeEnum.NotComplete != pCompleteType)
379             return resourceTable.getSingleObject(resourceIndex, support, pRef, pCompleteType, completeTable, this);
380         final int predicateIndex = (int)resourceTable.table[(resourceIndex<<1) - 1 + resourceTable.offset] & 0xFFFFFF;
381         if (0 == predicateIndex) // All relevant data is in resource table.
382             return resourceTable.getSingleObject(resourceIndex, support, pRef, pCompleteType, completeTable, this);
383         int objectIndex = predicateTable.getObjectIndex(predicateIndex, pRef & 0xFFFF);
384         return getSingleObject(resourceKey, predicateKey, objectIndex, support);
385     }
386
387     @Override
388     public void forObjects(ReadGraphImpl graph, int resourceKey,
389             int predicateKey, SyncMultiProcedure<Resource> procedure) throws DatabaseException {
390         if (deleted) return;
391         SessionImplSocket session = (SessionImplSocket)graph.getSession();
392         ClusterSupport support = session.clusterTranslator;
393         if (DEBUG)
394             System.out.println("ClusterSmall.forObjects3: rk=" + resourceKey + " pk=" + predicateKey);
395         final int resourceIndex = ClusterTraitsBase.getResourceIndexFromResourceKey(resourceKey);
396         final int pRef = getInternalReferenceOrZero2(predicateKey, support);
397         final int completeType = ClusterTraitsBase.getCompleteTypeIntFromResourceKey(predicateKey);
398         final ClusterI.CompleteTypeEnum pCompleteType = CompleteTypeEnum.make(completeType);
399         if (completeType > 0) {
400             resourceTable.foreachObject(resourceIndex, graph, procedure, support, pRef, pCompleteType, completeTable, this);
401             return;
402         }
403         final int predicateIndex = (int)resourceTable.table[(resourceIndex<<1) - 1 + resourceTable.offset] & 0xFFFFFF;
404         if (0 == predicateIndex) {
405             resourceTable.foreachObject(resourceIndex, graph, procedure, support, pRef, pCompleteType, completeTable, this);
406             return;
407         }
408         int objectIndex = predicateTable.getObjectIndex(predicateIndex, pRef & 0xFFFF);
409         forObjects(graph, resourceKey, predicateKey, objectIndex, procedure, support);
410     }
411
412     public void forObjects(ReadGraphImpl graph, int resourceKey, ForEachObjectProcedure procedure) throws DatabaseException {
413         if (deleted) return;
414         final int resourceIndex = ClusterTraitsBase.getResourceIndexFromResourceKey(resourceKey);
415         final int predicateKey = procedure.predicateKey;
416         int clusterKey = ClusterTraitsBase.getClusterMaskFromResourceKey(resourceKey);
417         int pRef = 0;
418         if(procedure.clusterKey[0] == clusterKey) {
419             pRef = procedure.predicateReference[0];
420         } else {
421             SessionImplSocket session = (SessionImplSocket)graph.getSession();
422             ClusterSupport support = session.clusterTranslator;
423             pRef = getInternalReferenceOrZero2(predicateKey, support);
424             procedure.clusterKey[0] = clusterKey;
425             procedure.predicateReference[0] = pRef;
426         }
427         final ClusterI.CompleteTypeEnum pCompleteType = procedure.completeType;
428         if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {
429             SessionImplSocket session = (SessionImplSocket)graph.getSession();
430             ClusterSupport support = session.clusterTranslator;
431             resourceTable.foreachObject(resourceIndex, graph, procedure, support, pRef, pCompleteType, completeTable, this);
432             return;
433         }
434         final int predicateIndex = (int)resourceTable.table[(resourceIndex<<1) - 1 + resourceTable.offset] & 0xFFFFFF;
435         if (0 == predicateIndex) {
436             SessionImplSocket session = (SessionImplSocket)graph.getSession();
437             ClusterSupport support = session.clusterTranslator;
438             resourceTable.foreachObject(resourceIndex, graph, procedure, support, pRef, pCompleteType, completeTable, this);
439             return;
440         }
441         int hashBase = predicateIndex + predicateTable.offset;
442         if (predicateTable.table[hashBase-1] < 0) {
443             int objectIndex = TableIntArraySet2.get(predicateTable.table, hashBase, pRef & 0xFFFF);
444             //int objectIndex = predicateTable.getObjectIndex(predicateIndex, pRef & 0xFFFF);
445             SessionImplSocket session = (SessionImplSocket)graph.getSession();
446             ClusterSupport support = session.clusterTranslator;
447             forObjects(graph, resourceKey, predicateKey, objectIndex, procedure, support);
448         } else {
449             procedure.finished(graph);
450 //            graph.dec();
451         }
452 }
453
454     public <C> void forObjects(ReadGraphImpl graph, int resourceKey, C context, ForEachObjectContextProcedure<C> procedure) throws DatabaseException {
455         if (deleted) return;
456         final int resourceIndex = ClusterTraitsBase.getResourceIndexFromResourceKey(resourceKey);
457         final int predicateKey = procedure.predicateKey;
458         int clusterKey = ClusterTraitsBase.getClusterMaskFromResourceKey(resourceKey);
459         int pRef = 0;
460         if(procedure.clusterKey[0] == clusterKey) {
461             pRef = procedure.predicateReference[0];
462         } else {
463             SessionImplSocket session = (SessionImplSocket)graph.getSession();
464             ClusterSupport support = session.clusterTranslator;
465             pRef = getInternalReferenceOrZero2(predicateKey, support);
466             procedure.clusterKey[0] = clusterKey;
467             procedure.predicateReference[0] = pRef;
468         }
469
470         final ClusterI.CompleteTypeEnum pCompleteType = procedure.completeType;
471         if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {
472             SessionImplSocket session = (SessionImplSocket)graph.getSession();
473             ClusterSupport support = session.clusterTranslator;
474             resourceTable.foreachObject(resourceIndex, graph, context, procedure, support, pRef, pCompleteType, completeTable, this);
475             return;
476         }
477         final int predicateIndex = (int)resourceTable.table[(resourceIndex<<1) - 1 + resourceTable.offset] & 0xFFFFFF;
478         if (0 == predicateIndex) {
479             SessionImplSocket session = (SessionImplSocket)graph.getSession();
480             ClusterSupport support = session.clusterTranslator;
481             resourceTable.foreachObject(resourceIndex, graph, context, procedure, support, pRef, pCompleteType, completeTable, this);
482             return;
483         }
484         int hashBase = predicateIndex + predicateTable.offset;
485         if(predicateTable.table[hashBase-1] < 0) {
486             int objectIndex = TableIntArraySet2.get(predicateTable.table, hashBase, pRef & 0xFFFF);
487             SessionImplSocket session = (SessionImplSocket)graph.getSession();
488             ClusterSupport support = session.clusterTranslator;
489             forObjects(graph, resourceKey, predicateKey, objectIndex, context, procedure, support);
490         } else {
491             int objectIndex = TableIntSet2.get(predicateTable.table, hashBase, pRef & 0xFFFF);
492             SessionImplSocket session = (SessionImplSocket)graph.getSession();
493             ClusterSupport support = session.clusterTranslator;
494             forObjects(graph, resourceKey, predicateKey, objectIndex, context, procedure, support);
495         }
496     }
497     @Override
498     public <Context> boolean forObjects(int resourceKey, int predicateKey,
499             ObjectProcedure<Context> procedure, Context context, ClusterSupport support)
500     throws DatabaseException {
501         if (DEBUG)
502             System.out.println("ClusterSmall.forObjects4: rk=" + resourceKey + " pk=" + predicateKey);
503         if (deleted) return false;
504         final short resourceIndex = (short)ClusterTraitsBase.getResourceIndexFromResourceKey(resourceKey);
505         final short pRef = getInternalReferenceOrZero2(predicateKey, support);
506         final ClusterI.CompleteTypeEnum pCompleteType = ClusterTraitsBase.getCompleteTypeFromResourceKey(predicateKey);
507         // PredicateType is complete i.e. all relevant data is in resource table.
508         if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {
509             if (DEBUG)
510                 System.out.println("ClusterSmall.forObjects: complete type was " + pCompleteType + " cluster=" + getClusterUID());
511             return resourceTable.foreachObject(resourceIndex, procedure, context, support, this, pRef, pCompleteType, completeTable);
512         }
513         final int predicateIndex = resourceTable.getPredicateIndex(resourceIndex);
514         if (0 == predicateIndex) { // All relevant data is in resource table.
515             if (DEBUG)
516                 System.out.println("ClusterSmall.forObjects: no predicate table " + pCompleteType);
517             return resourceTable.foreachObject(resourceIndex, procedure, context, support, this, pRef, pCompleteType, completeTable);
518         }
519         int objectIndex = predicateTable.getObjectIndex(predicateIndex, pRef & 0xFFFF);
520         return forObjects(resourceKey, predicateKey, objectIndex, procedure, context, support);
521     }
522     @Override
523     public <Context> boolean forPredicates(int resourceKey,
524             PredicateProcedure<Context> procedure, Context context, ClusterSupport support)
525     throws DatabaseException {
526         if (DEBUG)
527             System.out.println("ClusterSmall.forPredicates: rk=" + resourceKey );
528         if (deleted) return false;
529         if(proxy) {
530             ClusterImpl cluster = clusterTable.load2(clusterId, clusterKey);
531             return cluster.forPredicates(resourceKey, procedure, context, support);
532         }
533
534         final int resourceIndex = getLocalReference(resourceKey);
535         final int predicateIndex = resourceTable.getPredicateIndex(resourceIndex);
536         if (0 == predicateIndex)
537             return resourceTable.foreachPredicate(resourceIndex,
538                     procedure, context, support, this, completeTable);
539         else {
540             boolean broken = resourceTable.foreachPredicate(resourceIndex,
541                     procedure, context, support, this, completeTable);
542             if (broken)
543                 return true;
544         }
545         return predicateTable.foreachPredicate(predicateIndex,
546                 procedure, context, support, this);
547     }
548     @Override
549     public ClusterI addRelation(int sResourceKey, int pResourceKey, int oResourceKey, ClusterSupport support)
550     throws DatabaseException {
551         if (DEBUG)
552             System.out.println("add rk=" + sResourceKey + " pk=" + pResourceKey + " ok=" + oResourceKey);
553         if (deleted) return null;
554         if(proxy) {
555             ClusterImpl cluster = clusterTable.load2(clusterId, clusterKey);
556             return cluster.addRelation(sResourceKey, pResourceKey, oResourceKey, support);
557         }
558
559         //        check();
560         boolean ret;
561         try {
562             short sri = getLocalReferenceAnd(sResourceKey, support, ClusterChange.ADD_OPERATION);
563             short pri = getReferenceOrCreateIfForeign(pResourceKey, support, ClusterStream.NULL_OPERATION);
564             short ori = getReferenceOrCreateIfForeign(oResourceKey, support, ClusterStream.NULL_OPERATION);
565             ClusterI.CompleteTypeEnum completeType = ClusterTraitsBase.getCompleteTypeFromResourceKey(pResourceKey);
566             ret = addRelationInternal(sri, pri, ori, completeType);
567             calculateModifiedId();
568         } catch (OutOfSpaceException e) {
569             boolean streamOff = support.getStreamOff();
570             if (!streamOff) {
571                 support.cancelStatement(this);
572                 support.setStreamOff(true);
573             }
574             ClusterI cluster = toBig(support);
575             if (!streamOff)
576                 support.setStreamOff(false);
577             ClusterI cluster2 = cluster.addRelation(sResourceKey, pResourceKey, oResourceKey, support);
578             if (cluster != cluster2)
579                 throw new DatabaseException("Internal error, cluster mismatch.");
580             return cluster;
581         }
582 //        check();
583         if (ret) {
584             support.addStatement(this);
585             return this;
586         } else {
587             support.cancelStatement(this);
588             return null;
589         }
590     }
591     @Override
592     public boolean removeRelation(int sResourceKey, int pResourceKey, int oResourceKey, ClusterSupport support)
593     throws DatabaseException {
594         if (deleted) return false;
595         short sri = getLocalReferenceAnd(sResourceKey, support, ClusterChange.REMOVE_OPERATION);
596         short pri = getInternalReferenceOrZeroAnd(pResourceKey, support, ClusterStream.NULL_OPERATION);
597         short ori = getInternalReferenceOrZeroAnd(oResourceKey, support, ClusterStream.NULL_OPERATION);
598         boolean ret = false;
599         if (0 != pri && 0 != ori) {
600             ClusterI.CompleteTypeEnum completeType = ClusterTraitsBase.getCompleteTypeFromResourceKey(pResourceKey);
601             ret = removeRelationInternal(sri, pri, ori, completeType, support);
602             calculateModifiedId();
603         }
604         if (ret)
605             support.removeStatement(this);
606         else
607             support.cancelStatement(this);
608         //        check();
609         return ret;
610     }
611     @Override
612     public void denyRelation(int sResourceKey, int pResourceKey, int oResourceKey, ClusterSupport support)
613     throws DatabaseException {
614         if (deleted) return;
615         short s = checkResourceKeyIsOursAndGetResourceIndexIf(sResourceKey, support);
616         ResourceReferenceAndCluster p = checkResourceKeyAndGetResourceIndexIf(pResourceKey, support);
617         ResourceReferenceAndCluster o = checkResourceKeyAndGetResourceIndexIf(oResourceKey, support);
618         if (0 == s || 0 == p.reference || 0 == o.reference)
619             return;
620         //        check();
621         ClusterI.CompleteTypeEnum completeType = ClusterTraitsBase.getCompleteTypeFromResourceKey(pResourceKey);
622         boolean ret = removeRelationInternal(s, p.reference, o.reference, completeType, support);
623         if (ret) {
624             support.addStatementIndex(this, sResourceKey, getClusterUID(), ClusterChange.REMOVE_OPERATION);
625             support.addStatementIndex(this, pResourceKey, p.clusterUID, ClusterStream.NULL_OPERATION);
626             support.addStatementIndex(this, oResourceKey, o.clusterUID, ClusterStream.NULL_OPERATION);
627             support.removeStatement(this);
628         }
629         calculateModifiedId();
630         //        check();
631         return;
632     }
633     @Override
634     public InputStream getValueStream(int resourceKey, ClusterSupport support) throws DatabaseException {
635         if (DEBUG)
636             System.out.println("ClusterSmall.getValue " + resourceKey);
637         if (deleted) return null;
638         int resourceIndex = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(resourceKey);
639         try {
640             byte[] buffer = resourceTable.getValue(valueTable, resourceIndex);
641             if(buffer == null) return null;
642             return new ByteArrayInputStream(buffer);
643         } catch (ExternalValueException e) {
644             return support.getValueStreamEx(resourceIndex, clusterId);
645         }
646     }
647     @Override
648     public byte[] getValue(int resourceKey, ClusterSupport support)
649     throws DatabaseException {
650         if (DEBUG)
651             System.out.println("ClusterSmall.getValue " + resourceKey);
652         if (deleted) return null;
653         int resourceIndex = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(resourceKey);
654         try {
655             return resourceTable.getValue(valueTable, resourceIndex);
656         } catch (ExternalValueException e) {
657             return support.getValueEx(resourceIndex, clusterId);
658         }
659     }
660     @Override
661     public boolean hasValue(int resourceKey, ClusterSupport support)
662     throws DatabaseException {
663         if (deleted) return false;
664         if(proxy) {
665             ClusterImpl cluster = clusterTable.load2(clusterId, clusterKey);
666             return cluster.hasValue(resourceKey, support);
667         }
668         int resourceIndex = getLocalReference(resourceKey);
669         return resourceTable.hasValue(resourceIndex);
670     }
671     @Override
672     public boolean removeValue(int resourceKey, ClusterSupport support)
673     throws DatabaseException {
674         if (deleted) return false;
675         int resourceIndex = getLocalReferenceAnd(resourceKey, support, ClusterChange.DELETE_OPERATION);
676         support.removeValue(this);
677         calculateModifiedId();
678         return resourceTable.removeValue(valueTable, resourceIndex);
679     }
680     @Override
681     public ClusterI setValue(int rResourceId, byte[] value, int length, ClusterSupport support)
682     throws DatabaseException {
683         if (deleted) return null;
684         int resourceIndex = getLocalReferenceAnd(rResourceId, support, ClusterStream.SET_OPERATION);
685         support.setValue(this, getClusterId(), value, length);
686         try {
687             resourceTable.setValue(valueTable, resourceIndex, value, length);
688             calculateModifiedId();
689             return this;
690         } catch (OutOfSpaceException e) {
691             boolean streamOff = support.getStreamOff();
692             if (!streamOff)
693                 support.setStreamOff(true);
694             ClusterI cluster = toBig(support);
695             cluster.setValue(rResourceId, value, length, support);
696             if (!streamOff)
697                 support.setStreamOff(false);
698             return cluster;
699         }
700     }
701     @Override
702     public ClusterI modiValueEx(int rResourceId, long voffset, int length, byte[] value, int offset, ClusterSupport support)
703     throws DatabaseException {
704         if (deleted) return null;
705         int resourceIndex = getLocalReferenceAnd(rResourceId, support, ClusterStream.MODI_OPERATION);
706         support.modiValue(this, getClusterId(), voffset, length, value, offset);
707         resourceTable.setValueEx(valueTable, resourceIndex);
708         calculateModifiedId();
709         return this;
710     }
711     @Override
712     public byte[] readValueEx(int rResourceId, long voffset, int length, ClusterSupport support)
713     throws DatabaseException {
714         if (deleted) return null;
715         int resourceIndex = getLocalReference(rResourceId);
716         boolean isExternal = resourceTable.isValueEx(valueTable, resourceIndex);
717         if (!isExternal)
718             throw new DatabaseException("ClusterI.readValue supported only for external value. Resource key=" + rResourceId);
719         return support.getValueEx(resourceIndex, getClusterId(), voffset, length);
720     }
721     @Override
722     public long getValueSizeEx(int rResourceId, ClusterSupport support)
723     throws DatabaseException, ExternalValueException {
724         if (deleted) return 0;
725         int resourceIndex = getLocalReference(rResourceId);
726         boolean isExternal = resourceTable.isValueEx(valueTable, resourceIndex);
727         if (!isExternal)
728             throw new ExternalValueException("ClusterI.getValueSizeEx supported only for external value. Resource key=" + rResourceId);
729         return support.getValueSizeEx(resourceIndex, getClusterId());
730     }
731     @Override
732     public void setValueEx(int rResourceId)
733     throws DatabaseException {
734         int resourceIndex = getLocalReference(rResourceId);
735         resourceTable.setValueEx(valueTable, resourceIndex);
736     }
737     @Override
738     public int createResource(ClusterSupport support)
739     throws DatabaseException {
740         if (deleted) return 0;
741         if(proxy) {
742             ClusterImpl cluster = clusterTable.load2(clusterId, clusterKey);
743             return cluster.createResource(support);
744         }
745
746         short resourceIndex = resourceTable.createResource();
747         calculateModifiedId();
748         if(DebugPolicy.REPORT_RESOURCE_ID_ALLOCATION)
749             System.out.println("[RID_ALLOCATION]: ClusterSmall[" + clusterId + "] allocates " + resourceIndex);
750         support.createResource(this, resourceIndex, getClusterId());
751         return ClusterTraits.createResourceKey(clusterKey, resourceIndex);
752     }
753     @Override
754     public boolean hasResource(int resourceKey, ClusterSupport support) {
755         if(proxy) {
756                         try {
757                                 ClusterImpl cluster = clusterTable.load2(clusterId, clusterKey);
758                     return cluster.hasResource(resourceKey, support);
759                         } catch (DatabaseException e) {
760                                 LOGGER.error("Failed to load cluster with clusterId " + clusterId);
761                                 return false;
762                         }
763         }
764         if (deleted) return false;
765         int clusterKey = ClusterTraitsBase.getClusterKeyFromResourceKeyNoThrow(resourceKey);
766         if (this.clusterKey != clusterKey) // foreign resource
767             return false;
768         int resourceIndex;
769         try {
770             resourceIndex = ClusterTraits.getResourceIndexFromResourceKey(resourceKey);
771         } catch (DatabaseException e) {
772             return false;
773         }
774         if (resourceIndex > 0 & resourceIndex <= resourceTable.getTableCount())
775             return true;
776         else
777             return false;
778     }
779     @Override
780     public int getNumberOfResources(ClusterSupport support)
781     throws DatabaseException  {
782         if (deleted) return 0;
783         if(proxy) {
784             ClusterImpl cluster = clusterTable.load2(clusterId, clusterKey);
785             return cluster.getNumberOfResources(support);
786         }
787
788         return resourceTable.getUsedSize();
789     }
790
791     public int getNumberOfResources() {
792         if (deleted || proxy)
793             return 0;
794         return resourceTable.getUsedSize();
795     }
796
797     @Override
798     public long getUsedSpace() {
799         if (deleted) return 0;
800         if(isEmpty()) return 0;
801         long rt = resourceTable.getTableCapacity() * 8 + 8; // (8 = cluster id)
802         long ft = foreignTable.getTableCapacity() * 8;
803         long pt = predicateTable.getTableCapacity() * 4;
804         long ot = objectTable.getTableCapacity() * 4;
805         long ct = completeTable.getTableCapacity() * 4;
806         long vt = valueTable.getTableCapacity() * 1;
807         long cm = clusterMap.getUsedSpace();
808         return rt + ft + pt + ot + ct + vt + cm;
809     }
810     @Override
811     public boolean isEmpty() {
812         if (deleted) return true; // Deleted cluster is always empty.
813         if(resourceTable == null) return true;
814         return resourceTable.getTableCount() == 0;
815     }
816     @Override
817     public void printDebugInfo(String message, ClusterSupport support)
818     throws DatabaseException {
819         if (deleted) return;
820         throw new DatabaseException("Not implemented!");
821     }
822     private short getInternalReferenceOrZero2(int resourceKey, ClusterSupport support) throws DatabaseException {
823         int resourceIndex = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(resourceKey);
824         if (!ClusterTraitsBase.isCluster(clusterBits, resourceKey)) {
825             return clusterMap.getForeignReferenceOrZero(resourceKey);
826         } else {
827             return (short)resourceIndex;
828         }
829     }
830     private short getInternalReferenceOrZeroAnd(int resourceKey, ClusterSupport support, byte op)
831     throws DatabaseException {
832         int clusterKey = ClusterTraits.getClusterKeyFromResourceKey(resourceKey);
833         int resourceIndex = ClusterTraits.getResourceIndexFromResourceKey(resourceKey);
834         if (this.clusterKey != clusterKey) { // foreign resource
835             ClusterI foreignCluster = support.getClusterByClusterKey(clusterKey);
836             ClusterUID clusterUID = foreignCluster.getClusterUID();
837             short foreignRef = clusterMap.getForeignReferenceOrZero(resourceKey);
838             support.addStatementIndex(this, resourceKey, clusterUID, op);
839             return foreignRef;
840         }
841         support.addStatementIndex(this, resourceKey, getClusterUID(), op);
842         return (short)resourceIndex;
843     }
844     private final short getLocalReference(int resourceKey) throws DatabaseException {
845         return ClusterTraits.getResourceIndexFromResourceKeyNoThrow(resourceKey);
846     }
847     private final short getLocalReferenceAnd(int resourceKey, ClusterSupport support, byte op)
848     throws DatabaseException {
849         short resourceIndex = getLocalReference(resourceKey);
850         support.addStatementIndex(this, resourceKey, getClusterUID(), op);
851         return resourceIndex;
852     }
853     private short checkResourceKeyIsOursAndGetResourceIndexIf(int resourceKey, ClusterSupport support)
854     throws DatabaseException {
855         int clusterShortId = ClusterTraits.getClusterKeyFromResourceKey(resourceKey);
856         if (this.clusterKey != clusterShortId)
857             return 0;
858         int resourceIndex = ClusterTraits.getResourceIndexFromResourceKey(resourceKey);
859         return (short)resourceIndex;
860     }
861     private short getReferenceOrCreateIfForeign(int resourceKey, ClusterSupport support, byte op)
862     throws DatabaseException {
863         int clusterKey = ClusterTraits.getClusterKeyFromResourceKey(resourceKey);
864         short resourceIndex = (short)ClusterTraits.getResourceIndexFromResourceKey(resourceKey);
865         if (this.clusterKey != clusterKey) {
866             ClusterI foreignCluster = support.getClusterByClusterKey(clusterKey);
867             ClusterUID clusterUID = foreignCluster.getClusterUID();
868             support.addStatementIndex(this, resourceKey, clusterUID, op);
869             short ref = clusterMap.getForeignReferenceOrCreateByResourceKey(resourceKey, clusterUID);
870             return ref;
871         }
872         support.addStatementIndex(this, resourceKey, getClusterUID(), op);
873         return resourceIndex;
874     }
875     private class ResourceReferenceAndCluster {
876         ResourceReferenceAndCluster(short reference, ClusterUID clusterUID) {
877             this.reference = reference;
878             this.clusterUID = clusterUID;
879         }
880         public final short reference;
881         public final ClusterUID clusterUID;
882     }
883     private ResourceReferenceAndCluster checkResourceKeyAndGetResourceIndexIf(int resourceKey, ClusterSupport support)
884     throws DatabaseException {
885         int clusterKey = ClusterTraits.getClusterKeyFromResourceKey(resourceKey);
886         short resourceIndex = (short)ClusterTraits.getResourceIndexFromResourceKey(resourceKey);
887         if (this.clusterKey != clusterKey) { // foreign resource
888             ClusterI foreignCluster = support.getClusterByClusterKey(clusterKey);
889             ClusterUID clusterUID = foreignCluster.getClusterUID();
890             short ref = clusterMap.getForeignReferenceOrZero(resourceKey);
891             return new ResourceReferenceAndCluster(ref, clusterUID);
892         }
893         return new ResourceReferenceAndCluster(resourceIndex, getClusterUID());
894     }
895
896     static long fTime = 0;
897     
898     int executeIndex = 0;
899     long clusterUID1 = 0;
900     long clusterUID2 = 0;
901
902     @Override
903     final public int execute(int resourceReference) throws DatabaseException {
904         
905         if (deleted) return 0;
906         short resourceRef = (short)resourceReference;
907         int key;
908         if (ClusterTraitsSmall.resourceRefIsLocal(resourceRef)) {
909             key = clusterBits | resourceRef;
910         } else {
911             // TODO: not so nice
912             synchronized(this) {
913                 foreignTable.fillResourceUID(ClusterTraitsSmall.resourceRefGetForeignIndex((short)resourceRef), this);
914                 key = ClusterTraitsBase.createResourceKey(clusterSupport.getClusterKeyByClusterUIDOrMake(clusterUID1, clusterUID2), executeIndex);
915             }
916         }
917         if (DEBUG)
918             System.out.println("ClusterSmall.execute key=" + key);
919         return key;
920     }
921
922     private boolean addRelationInternal(short sReference, short pReference, short oReference, ClusterI.CompleteTypeEnum completeType)
923     throws DatabaseException {
924         int predicateIndex = resourceTable.addStatement(sReference, pReference, oReference, predicateTable, objectTable, completeType, completeTable);
925         if (0 == predicateIndex)
926             return true; // added to resourceTable
927         else if (0 > predicateIndex)
928             return false; // old complete statemenent
929         int newPredicateIndex = predicateTable.addPredicate(predicateIndex, 0xFFFF & pReference, 0xFFFF & oReference, objectTable);
930         if (0 == newPredicateIndex)
931             return false;
932         if (predicateIndex != newPredicateIndex)
933             resourceTable.setPredicateIndex(sReference, newPredicateIndex);
934         return true;
935     }
936     private boolean removeRelationInternal(int sResourceIndex, short pResourceIndex,
937             short oResourceIndex, ClusterI.CompleteTypeEnum completeType, ClusterSupport support)
938     throws DatabaseException {
939         int predicateIndex = resourceTable.getPredicateIndex(sResourceIndex);
940         if (0 == predicateIndex || ClusterI.CompleteTypeEnum.NotComplete != completeType)
941             return resourceTable.removeStatementFromCache(sResourceIndex,
942                     pResourceIndex, oResourceIndex, completeType, completeTable);
943         PredicateTable.Status ret = predicateTable.removePredicate(predicateIndex, 0xFFFF & pResourceIndex, 0xFFFF & oResourceIndex, objectTable);
944         switch (ret) {
945         case NothingRemoved:
946             return false;
947         case PredicateRemoved: {
948             if (0 == predicateTable.getPredicateSetSize(predicateIndex))
949                 resourceTable.setPredicateIndex(sResourceIndex, 0);
950             // intentionally dropping to next case
951         } default:
952             break;
953         }
954         resourceTable.removeStatement(sResourceIndex,
955                 pResourceIndex, oResourceIndex,
956                 completeType, completeTable,
957                 predicateTable, objectTable, support);
958         return true;
959     }
960     @Override
961     public void load() {
962         if (deleted) return;
963         try {
964                 clusterTable.load2(clusterId, clusterKey);
965         } catch (DatabaseException e) {
966                 LOGGER.error("Failed to load cluster with clusterId " + clusterId, e);
967         }
968     }
969
970     @Override
971     public void load(Consumer<DatabaseException> r) {
972         if (deleted) return;
973         try {
974                 clusterTable.load2(clusterId, clusterKey);
975         } catch (DatabaseException e) {
976                 r.accept(e);
977         }
978     }
979
980     public boolean contains(int resourceKey) {
981         if (deleted) return false;
982         return ClusterTraitsBase.isCluster(clusterBits, resourceKey);
983     }
984     @Override
985     public void load(final ClusterSupport support, final Runnable callback) {
986         if (deleted) return;
987         try {
988             clusterTable.load2(clusterId, clusterKey);
989             callback.run();
990         } catch (DatabaseException e) {
991                 LOGGER.error("Failed to load cluster with clusterId " + clusterId, e);
992         }
993
994     }
995     @Override
996     public ClusterI getClusterByResourceKey(int resourceKey,
997             ClusterSupport support) {
998         if (deleted) return null;
999         throw new Error();
1000     }
1001     @Override
1002     public void increaseReferenceCount(int amount) {
1003         if (deleted) return;
1004         throw new Error();
1005     }
1006     @Override
1007     public void decreaseReferenceCount(int amount) {
1008         if (deleted) return;
1009         throw new Error();
1010     }
1011     @Override
1012     public int getReferenceCount() {
1013         if (deleted) return 0;
1014         throw new Error();
1015     }
1016     @Override
1017     public void releaseMemory() {
1018     }
1019     @Override
1020     public void compact() {
1021         if (deleted) return;
1022         clusterMap.compact();
1023     }
1024     @Override
1025     public boolean isLoaded() {
1026         return !proxy || deleted; // Deleted cluster is always loaded.
1027     }
1028
1029     public ClusterImpl tryLoad(SessionImplSocket sessionImpl) throws DatabaseException {
1030         if (deleted) return this; // Never load deleted cluster.
1031         return clusterTable.tryLoad(clusterId, clusterKey);
1032     }
1033
1034
1035     @Override
1036     public ClusterBig toBig(ClusterSupport support)
1037     throws DatabaseException {
1038         if (DEBUG) {
1039             System.out.println("DEBUG: toBig cluster=" + clusterId);
1040             new Exception().printStackTrace();
1041         }
1042         if (deleted) return null; // Can't convert deleted cluster to big.
1043         ClusterBig big = new ClusterBig(getClusterUID(), clusterKey, support);
1044         big.setImportance(importance);
1045         big.cc = this.cc;
1046         big.cc.clusterImpl = this;
1047         resourceTable.toBig(big, support, this);
1048         big.foreignLookup = this.foreignLookup;
1049         big.change = this.change;
1050         this.cc = null;
1051         this.foreignLookup = null;
1052         this.change = null;
1053         return big;
1054     }
1055
1056     @Override
1057     public ClusterTypeEnum getType() {
1058         return ClusterTypeEnum.SMALL;
1059     }
1060     @Override
1061     public boolean getImmutable() {
1062         if (deleted) return false;
1063         if (null == resourceTable)
1064             return false;
1065         int status = resourceTable.getClusterStatus();
1066         return (status & ClusterStatus.ImmutableMaskSet) == ClusterStatus.ImmutableMaskSet;
1067     }
1068     @Override
1069     public void setImmutable(boolean immutable, ClusterSupport support) {
1070         if (deleted) return;
1071         if(resourceTable != null) {
1072             int status = resourceTable.getClusterStatus();
1073             if (immutable)
1074                 status |= ClusterStatus.ImmutableMaskSet;
1075             else
1076                 status &= ClusterStatus.ImmutableMaskClear;
1077             resourceTable.setClusterStatus(status);
1078         }
1079         support.setImmutable(this, immutable);
1080     }
1081     @Override
1082     public boolean getDeleted() {
1083         if (deleted) return true;
1084         int status = resourceTable.getClusterStatus();
1085         return (status & ClusterStatus.DeletedMaskSet) == ClusterStatus.DeletedMaskSet;
1086     }
1087     @Override
1088     public void setDeleted(boolean set, ClusterSupport support) {
1089         deleted = set;
1090         if(resourceTable != null) {
1091             int status = resourceTable.getClusterStatus();
1092             if (set)
1093                 status |= ClusterStatus.DeletedMaskSet;
1094             else
1095                 status &= ClusterStatus.DeletedMaskClear;
1096             resourceTable.setClusterStatus(status);
1097         }
1098         if (null != support)
1099             support.setDeleted(this, set);
1100     }
1101     @Override
1102     public String toString() {
1103         if (deleted) return "ClusterSmall[" + getClusterId() + " - has been deleted or hasn't been created.]";
1104         try {
1105             ForeignTableSmall ft = foreignTable;
1106             if (ft == null)
1107                 return "ClusterSmall[" + getClusterId() + " - " + getNumberOfResources() + "]";
1108             TIntShortHashMap map = ft.getResourceHashMap();
1109             TIntHashSet set = new TIntHashSet();
1110             map.forEachKey(value -> {
1111                 set.add(value & 0xfffff000);
1112                 return true;
1113             });
1114             return "ClusterSmall[" + getClusterId() + " - " + getNumberOfResources() + " - " + foreignTable.getResourceHashMap().size() + " - " + set.size() + "]";
1115         } catch (Throwable e) {
1116             return "ClusterSmall[" + getNumberOfResources() + "]";
1117         }
1118     }
1119     @Override
1120     public Table<?> getPredicateTable() {
1121         return predicateTable;
1122     }
1123     @Override
1124     public Table<?> getForeignTable() {
1125         return foreignTable;
1126     }
1127     @Override
1128     public int makeResourceKey(int pRef) throws DatabaseException {
1129         throw new UnsupportedOperationException();
1130     }
1131     @Override
1132     public Table<?> getCompleteTable() {
1133         return completeTable;
1134     }
1135     @Override
1136     public Table<?> getValueTable() {
1137         return valueTable;
1138     }
1139     @Override
1140     public Table<?> getObjectTable() {
1141         return objectTable;
1142     }
1143
1144 }
1145
1146 class ClusterStatus {
1147     public static final int ImmutableMaskClear = 0xFFFFFFFE;
1148     public static final int ImmutableMaskSet = 0x00000001;
1149     public static final int DeletedMaskClear = 0xFFFFFFFD;
1150     public static final int DeletedMaskSet = 0x00000002;
1151 }