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