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