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