]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/ClusterChange.java
Better emptying of trash bin
[simantics/platform.git] / bundles / org.simantics.db.procore / src / fi / vtt / simantics / procore / internal / ClusterChange.java
1 package fi.vtt.simantics.procore.internal;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.List;
6
7 import org.simantics.db.exception.RuntimeDatabaseException;
8 import org.simantics.db.impl.ClusterTraitsBase;
9 import org.simantics.db.procore.cluster.ClusterImpl;
10 import org.simantics.db.procore.cluster.ClusterTraits;
11 import org.simantics.db.procore.cluster.ClusterTraitsSmall;
12 import org.simantics.db.service.Bytes;
13 import org.simantics.db.service.ClusterUID;
14
15 import fi.vtt.simantics.procore.DebugPolicy;
16 import fi.vtt.simantics.procore.internal.ClusterStream.ClusterEnum;
17 import fi.vtt.simantics.procore.internal.ClusterStream.Data;
18 import fi.vtt.simantics.procore.internal.ClusterStream.DebugInfo;
19 import fi.vtt.simantics.procore.internal.ClusterStream.OpEnum;
20 import fi.vtt.simantics.procore.internal.ClusterStream.StmEnum;
21 import gnu.trove.map.hash.TIntByteHashMap;
22 import gnu.trove.map.hash.TLongIntHashMap;
23
24 public final class ClusterChange {
25     public static final int VERSION = 1;
26     public static final byte ADD_OPERATION = 2;
27     public static final byte REMOVE_OPERATION = 3;
28     public static final byte DELETE_OPERATION = 5;
29
30     public static final boolean DEBUG = false;
31     public static final boolean DEBUG_STAT = false;
32     public static final boolean DEBUG_CCS = false;
33
34     private static DebugInfo sum = new DebugInfo();
35
36     public final TIntByteHashMap foreignTable = new TIntByteHashMap();
37     private final DebugInfo info;
38     private final GraphSession graphSession;
39     public final ClusterUID clusterUID;
40     private final int SIZE_OFFSET;
41     private final int HEADER_SIZE;
42     // How much buffer is used before stream is flushed to server. The bigger the better.
43     public static final int MAX_FIXED_BYTES = (1<<15) + (1<<14);
44     private static final int MAX_FIXED_OPERATION_SIZE = 17 + 16;
45     private static final int MAX_FIXED_OPERATION_SIZE_AND_ROOM_FOR_ERROR = MAX_FIXED_OPERATION_SIZE + 36;
46     private int nextSize = MAX_FIXED_BYTES;
47     int byteIndex = 0;
48     private byte[] bytes = null; // Operation data.
49     private final byte[] header;
50     private boolean flushed = false;
51     private final ClusterStream clusterStream;
52     private final ClusterChange2 clusterChange2;
53
54     public ClusterImpl clusterImpl;
55
56     public ClusterChange(ClusterStream clusterStream, ClusterImpl clusterImpl) {
57         
58         this.clusterImpl = clusterImpl;
59
60         if (!clusterImpl.isLoaded())
61             new IllegalStateException("Change to proxy cluster " + clusterImpl.getClusterUID()).printStackTrace();
62
63         clusterUID = clusterImpl.getClusterUID();
64         long[] longs = new long[ClusterUID.getLongLength()];
65         clusterUID.toLong(longs, 0);
66         this.graphSession = clusterStream.graphSession;
67         info = new DebugInfo();
68         HEADER_SIZE = 8 + longs.length * 8;
69         header = new byte[HEADER_SIZE];
70         SIZE_OFFSET = 0;
71         Bytes.writeLE(header, SIZE_OFFSET + 0, 0); // Correct byte vector size is set with setHeaderVectorSize() later.
72         Bytes.writeLE(header, SIZE_OFFSET + 4, VERSION);
73         for (int i=0, offset=8; i<longs.length; ++i, offset+=8)
74             Bytes.writeLE(header, offset, longs[i]);
75         //initBuffer();
76         this.clusterStream = clusterStream;
77         this.clusterChange2 = new ClusterChange2(clusterUID);
78         clusterStream.changes.add(this);
79     }
80     
81     public void adopt(ClusterImpl impl) {
82         this.clusterImpl = impl;
83     }
84
85     private void setHeaderVectorSize(int size) {
86         if (size < 0)
87             throw new RuntimeDatabaseException("Change set size can't be negative.");
88         int len = size + HEADER_SIZE - SIZE_OFFSET - 4;
89         Bytes.writeLE(header, SIZE_OFFSET, len);
90     }
91     @Override
92     public String toString() {
93         return super.toString() + " cluster=" + clusterUID + " id=" + clusterImpl.getClusterId() + " off=" + byteIndex;
94     }
95     private final void initBuffer() {
96         flushed = false;
97         if (null == bytes || bytes.length < nextSize) {
98             bytes = new byte[nextSize];
99             nextSize = MAX_FIXED_BYTES;
100         }
101         byteIndex = 0;
102     }
103     private final void clear() {
104         if(clusterImpl != null && clusterImpl.change != null)
105                 clusterImpl.change.init();
106         foreignTable.clear();
107         //initBuffer();
108         bytes = null;
109         byteIndex = 0;
110         if (DEBUG_STAT)
111             info.clear();
112     }
113     private final void checkInitialization() {
114         if (0 == byteIndex)
115             clusterStream.changes.addChange(this);
116     }
117     private final void printlnd(String s) {
118         System.out.println("DEBUG: ClusterChange " + clusterUID + ": " + s);
119     }
120     public final void createResource(short index) {
121         checkInitialization();
122         if (DEBUG)
123             printlnd("New ri=" + index + " offset=" + byteIndex);
124         if (index > ClusterTraits.getMaxNumberOfResources())
125             throw new RuntimeDatabaseException("Illegal resource index=" + index + ".");
126         checkBufferSpace(null);
127         bytes[byteIndex++] = (byte)52;
128         bytes[byteIndex++] = (byte)index;
129         bytes[byteIndex++] = (byte)(index>>>8);
130     }
131     void flushCollect(Change c) {
132         flushInternal(graphSession, clusterUID);
133         if (DEBUG)
134             printlnd("Cluster change data was flushed.");
135         if (null != c) {
136             if (DEBUG)
137                 printlnd("Clearing lookup for " + c.toString());
138             c.lookup1 = null;
139             c.lookup2 = null;
140         }
141         if (null != clusterImpl) {
142             clusterImpl.foreignLookup = null;
143         }
144     }
145
146     private final boolean checkBufferSpace(Change c) {
147         clusterStream.changes.checkFlush();
148         if(bytes == null) initBuffer();
149         if (MAX_FIXED_BYTES - byteIndex > MAX_FIXED_OPERATION_SIZE_AND_ROOM_FOR_ERROR) {
150             return false;
151         }
152         flushCollect(c);
153         initBuffer();
154         return true;
155     }
156
157     private final void checkBufferSpace(int size) {
158         if(bytes == null) initBuffer();
159         if (bytes.length - byteIndex >= size)
160             return;
161         nextSize = Math.max(MAX_FIXED_BYTES, size);
162         flushInternal(graphSession, clusterUID);
163         initBuffer();
164     }
165
166     final void addChange(Change c) {
167         checkInitialization();
168         checkBufferSpace(c);
169         byte operation = c.op0;
170         if(operation == ADD_OPERATION)
171             addStm(c, StmEnum.Add);
172         else if (operation == REMOVE_OPERATION)
173             addStm(c, StmEnum.Remove);
174         else if (operation == DELETE_OPERATION) {
175             if (DEBUG)
176                 printlnd("Delete value offset=" + byteIndex + " " + c);
177             addByte(OpEnum.Delete.getOrMask());
178             addShort(ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(c.key0));
179         }
180         c.lastArg = 0;
181     }
182
183     private final void addForeignLong(short index, ClusterUID clusterUID) {
184         byteIndex = clusterUID.toByte(bytes, byteIndex);
185         bytes[byteIndex++] = (byte)(index & 0xFF);
186         bytes[byteIndex++] = (byte)(index >>> 8);
187     }
188
189     private final ClusterEnum addIndexAndCluster(int key, ClusterUID clusterUID, byte lookIndex, byte[] lookup) {
190         assert(!clusterUID.equals(ClusterUID.Null));
191         short resourceIndex = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(key);
192         if (clusterUID.equals(this.clusterUID)) {
193             bytes[byteIndex++] = (byte)(resourceIndex & 0xFF);
194             bytes[byteIndex++] = (byte)(resourceIndex >>> 8);
195             return ClusterEnum.Local;
196         }
197
198         byte foreign = 0;
199         if(lookIndex > 0) {
200             if(lookup != null)
201                 foreign = lookup[lookIndex];
202         } else {
203             foreign = foreignTable.get(key);
204         }
205         if (0 != foreign) {
206             if (foreign > 256)
207                 throw new RuntimeDatabaseException("Internal error, contact application support." +
208                 "Too big foreing index=" + foreign + " max=256");
209             --foreign;
210             bytes[byteIndex++] = foreign;
211             return ClusterEnum.ForeignShort;
212         } else {
213             byte position = (byte) (foreignTable.size() + 1);
214             if(lookup != null)
215                 lookup[lookIndex] = position;
216             foreignTable.put(key, position);
217             if (DEBUG_STAT)
218                 info.sForeign = foreignTable.size();
219             if (clusterUID.equals(ClusterUID.Null))
220                 throw new RuntimeDatabaseException("Internal error, contact application support." +
221                 "Cluster unique id not defined for foreing cluster.");
222             addForeignLong(resourceIndex, clusterUID);
223             return ClusterEnum.ForeignLong;
224         }
225     }
226
227     private final void addByte(byte b) {
228         bytes[byteIndex++] = b;
229     }
230
231     private final void addShort(short s) {
232         bytes[byteIndex++] = (byte)(s & 0xFF);
233         bytes[byteIndex++] = (byte)(s >>> 8);
234     }
235
236 //    private final void addShort(int s) {
237 //        bytes[byteIndex++] = (byte) (s & 0xFF);
238 //        bytes[byteIndex++] = (byte) ((s >>> 8) & 0xFF);
239 //    }
240
241     private final void addInt(int i) {
242 //        System.err.println("addInt " + i + " " + i);
243         bytes[byteIndex++] = (byte) (i & 0xFF);
244         bytes[byteIndex++] = (byte) ((i >>> 8) & 0xFF);
245         bytes[byteIndex++] = (byte) ((i >>> 16) & 0xFF);
246         bytes[byteIndex++] = (byte) ((i >>> 24) & 0xFF);
247         // buffer.asIntBuffer().put(i);
248         // buffer.position(buffer.position()+4);
249     }
250
251 //    private void addLong6(long l) {
252 ////        System.err.println("addLong " + l);
253 //        bytes[byteIndex++] = (byte) (l & 0xFF);
254 //        bytes[byteIndex++] = (byte) ((l >>> 8) & 0xFF);
255 //        bytes[byteIndex++] = (byte) ((l >>> 16) & 0xFF);
256 //        bytes[byteIndex++] = (byte) ((l >>> 24) & 0xFF);
257 //        bytes[byteIndex++] = (byte) ((l >>> 32) & 0xFF);
258 //        bytes[byteIndex++] = (byte) ((l >>> 40) & 0xFF);
259 //        // buffer.asLongBuffer().put(l);
260 //        // buffer.position(buffer.position() + 6);
261 //    }
262
263     private void addLong7(long l) {
264         bytes[byteIndex++] = (byte) (l & 0xFF);
265         bytes[byteIndex++] = (byte) ((l >>> 8) & 0xFF);
266         bytes[byteIndex++] = (byte) ((l >>> 16) & 0xFF);
267         bytes[byteIndex++] = (byte) ((l >>> 24) & 0xFF);
268         bytes[byteIndex++] = (byte) ((l >>> 32) & 0xFF);
269         bytes[byteIndex++] = (byte) ((l >>> 40) & 0xFF);
270         bytes[byteIndex++] = (byte) ((l >>> 48) & 0xFF);
271         // buffer.asLongBuffer().put(l);
272         // buffer.position(buffer.position() + 7);
273     }
274
275 //    private void addLong(long l) {
276 //        bytes[byteIndex++] = (byte) (l & 0xFF);
277 //        bytes[byteIndex++] = (byte) ((l >>> 8) & 0xFF);
278 //        bytes[byteIndex++] = (byte) ((l >>> 16) & 0xFF);
279 //        bytes[byteIndex++] = (byte) ((l >>> 24) & 0xFF);
280 //        bytes[byteIndex++] = (byte) ((l >>> 32) & 0xFF);
281 //        bytes[byteIndex++] = (byte) ((l >>> 40) & 0xFF);
282 //        bytes[byteIndex++] = (byte) ((l >>> 48) & 0xFF);
283 //        bytes[byteIndex++] = (byte) ((l >>> 56) & 0xFF);
284 //    }
285     private final byte bufferPop() {
286         return bytes[--byteIndex];
287     }
288
289     final class DebugStm {
290         StmEnum e;
291         int r;
292         int p;
293         int o;
294         ClusterUID pc;
295         ClusterUID oc;
296
297         DebugStm(StmEnum e, int r, int p, ClusterUID pc, int o, ClusterUID oc) {
298             this.e = e;
299             this.r = r;
300             this.p = p;
301             this.o = o;
302             this.pc = pc;
303             this.oc = oc;
304         }
305
306         @Override
307         public String toString() {
308             short ri = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(r);
309             short pi = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(p);
310             short oi = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(o);
311             return "" + e + " rk=" + r + " ri=" + ri + " rc=" + clusterUID
312             + " pk=" + p + " pi=" + pi + " pc=" + pc
313             + " ok=" + o + " oi=" + oi + " oc=" + oc;
314         }
315
316         public String toString2() {
317             return "" + e + " r=" + r + " rc=" + clusterUID + " p=" + p
318                     + " pc=" + pc + " o=" + o + " oc=" + oc;
319         }
320
321         public String toString3() {
322             short ri = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(r);
323             short pi = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(p);
324             short oi = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(o);
325             return "" + e + " ri=" + ri
326             + " pi=" + pi + " pc=" + pc
327             + " oi=" + oi + " oc=" + oc;
328         }
329     }
330
331     private List<DebugStm> debugStms = new ArrayList<DebugStm>();
332
333     @SuppressWarnings("unused")
334     private final void addStm(Change c, StmEnum stmEnum) {
335
336         if (DEBUG_STAT)
337             ++info.nStms;
338         if (DEBUG || DEBUG_CCS) {
339             DebugStm d = new DebugStm(stmEnum, c.key0, c.key1, c.clusterUID1, c.key2, c.clusterUID2);
340             if (DEBUG_CCS)
341                 debugStms.add(d);
342             if (DEBUG) {
343                 printlnd(d.toString3() + " offset=" + byteIndex);
344             }
345         }
346         // int opPos = buffer.position();
347         int opPos = byteIndex++;
348         // buffer.put((byte)0); // operation code
349         // addByte((byte)0);
350
351         boolean done = true;
352
353         ClusterEnum a = addIndexAndCluster(c.key1, c.clusterUID1, c.lookIndex1, c.lookup1);
354         byte ab = 0;
355
356         // ForeignShort = byte
357         // Local = short
358         // ForeignLong = 8 byte
359         if (a != ClusterEnum.ForeignShort) {
360             ab = bufferPop();
361             done = false;
362         }
363
364         ClusterEnum b = addIndexAndCluster(c.key2, c.clusterUID2, c.lookIndex2, c.lookup2);
365         byte bb = 0;
366         if (b != ClusterEnum.ForeignShort) {
367             bb = bufferPop();
368             done = false;
369         }
370
371         int ri = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(c.key0);
372         if (ClusterTraitsSmall.isIllegalResourceIndex(ri))
373             throw new RuntimeDatabaseException("Assertion error. Illegal resource index=" + ri);
374         bytes[byteIndex++] = (byte)ri; // index low byte
375         if(!done) {
376             Data data = ClusterEnum.getData(stmEnum, a, b);
377             int left = 6 - data.bits;
378             int op = ri >>> (8 + left);
379             ri >>>= 8;
380             ri &= (1 << left) - 1;
381             if (a != ClusterEnum.ForeignShort) {
382                 ri |= ab << left;
383                 left += 6;
384             }
385             if (b != ClusterEnum.ForeignShort) {
386                 ri |= bb << left;
387                 left += 6;
388             }
389             switch (data.bytes) {
390                 default:
391                     throw new RuntimeDatabaseException("Assertion error. Illegal number of bytes=" + data.bytes);
392                 case 2:
393                     bytes[byteIndex++] = (byte)(ri & 0xFF);
394                     bytes[byteIndex++] = (byte)((ri >>> 8) & 0xFF);
395                     break;
396                 case 1:
397                     bytes[byteIndex++] = (byte)(ri & 0xFF);
398                     break;
399                 case 0:
400                     break;
401             }
402             op |= data.mask;
403             this.bytes[opPos] = (byte)op;
404         } else {
405             if (stmEnum == StmEnum.Add)
406                 bytes[opPos] = (byte)((ri >>> 8) + 64);
407             else
408                 bytes[opPos] = (byte)((ri >>> 8) + 128);
409         }
410         if (DEBUG_STAT) {
411             if (a == ClusterEnum.Local && b == ClusterEnum.Local) {
412                 ++info.nLocal;
413             } else if (a == ClusterEnum.Local || b == ClusterEnum.Local) {
414                 ++info.nPartly;
415             } else {
416                 ++info.nForeign;
417             }
418         }
419         if (foreignTable.size() > 252)
420             flushInternal(graphSession, clusterUID);
421     }
422
423     private final int modiValue(int ri, long value_offset, byte[] bytes, int offset, int size) {
424         if (DEBUG)
425             printlnd("Modify value ri=" + ri + " vo=" + value_offset + " size=" + size + " total=" + bytes.length);
426         if (ClusterTraitsBase.isIllegalResourceIndex(ri))
427             throw new RuntimeDatabaseException("Assertion error. Illegal resource index=" + ri);
428         if (value_offset > (1L << 58 - 1))
429             throw new RuntimeDatabaseException("Illegal value offset="
430                     + value_offset);
431         if (size < 0 || size > MAX_FIXED_BYTES - 1)
432             throw new RuntimeDatabaseException("Illegal value size=" + size);
433         if (offset + size > bytes.length)
434             throw new RuntimeDatabaseException("Illegal value size=" + size);
435         checkBufferSpace(12 + size);
436         addByte(OpEnum.Modify.getOrMask());
437         ri |= (value_offset >>> 56) << 14; // add top two bits
438         addShort((short) ri);
439         value_offset &= (1L << 56) - 1;
440         addLong7(value_offset);
441         addShort((short) size);
442         if (DEBUG)
443             System.out.println("Modify value fixed part end offset=" + byteIndex);
444         int copied = Math.min(size, this.bytes.length - byteIndex);
445         System.arraycopy(bytes, offset, this.bytes, byteIndex, copied);
446         byteIndex += size;
447         return copied;
448     }
449
450     private final void modiValueBig(int ri, long voffset, int left, byte[] bytes, int offset) {
451         checkBufferSpace(0);
452         int current = Math.min(this.bytes.length - byteIndex - 12, left);
453         if(current >= 0) {
454             int written = modiValue(ri, voffset, bytes, offset, current);
455             voffset += written;
456             offset += written;
457             left -= written;
458         }
459         flushInternal(graphSession, clusterUID);
460         while (left > 0) {
461             int length = Math.min(left, (1 << 16) - 1);
462             if (DEBUG)
463                 printlnd("Modify big value ri=" + ri + " vo=" + voffset + " len=" + length);
464             int psize = length + 12;
465             setHeaderVectorSize(psize);
466             byte[] message = new byte[psize+HEADER_SIZE];
467             System.arraycopy(header, 0, message, 0, HEADER_SIZE);
468             int to = HEADER_SIZE;
469             Bytes.write(message, to++, OpEnum.Modify.getOrMask());
470             short index = (short)(ri | (voffset >>> 56)<<14); // add top two bits
471             Bytes.writeLE(message, to, index); to += 2;
472             Bytes.writeLE7(message, to, voffset & ((1L << 56) - 1)); to += 7;
473             Bytes.writeLE(message, to, (short)length); to += 2;
474             System.arraycopy(bytes, offset, message, to, length);
475             graphSession.updateCluster(new UpdateClusterFunction(message));
476             voffset += length;
477             offset += length;
478             left -= length;
479         }
480     }
481
482     private final int setValueBig(int ri, byte[] bytes, int length_) {
483         checkBufferSpace(12);
484         int sum = 0;
485         int voffset = 0;
486         int offset = 0;
487         int left = length_;
488         while (left > 0) {
489             int length = Math.min(left, MAX_FIXED_BYTES - 12 - byteIndex);
490             if (DEBUG)
491                 printlnd("Set big value ri=" + ri + " vo=" + voffset + " len=" + length);
492             int written = modiValue(ri, voffset, bytes, offset, length);
493             sum += written;
494             voffset += written;
495             offset += written;
496             left -= written;
497             checkBufferSpace(12);
498         }
499         return sum;
500     }
501
502     private final int setValueSmall(int ri, byte[] bytes, int length) {
503         checkBufferSpace(5 + length);
504         int pos = byteIndex;
505         int i = length << 14 | ri;
506         if (length < 32) {
507             byte op = (byte) (OpEnum.SetShort.getOrMask() | length >>> 2);
508             addByte(op);
509             short s = (short) i;
510             addShort(s);
511         } else {
512             addByte(OpEnum.Set.getOrMask());
513             addInt(i);
514         }
515         System.arraycopy(bytes, 0, this.bytes, byteIndex, length);
516         byteIndex += length;
517         int len = byteIndex - pos;
518         return len;
519     }
520
521     final void setValue(short index, byte[] bytes) {
522         setValue(index, bytes, bytes.length);
523     }
524
525     final void setValue(short index, byte[] bytes, int length) {
526         checkInitialization();
527         if (ClusterTraitsBase.isIllegalResourceIndex(index))
528             throw new RuntimeDatabaseException("Assertion error. Illegal resource index=" + index);
529         if (DEBUG)
530             printlnd("Set value ri=" + index
531                     + " len=" + length
532                     + " bytes=" + Arrays.toString(Arrays.copyOfRange(bytes, 0, Math.min(10, length))));
533         int len;
534         /*
535          * The limit for the cluster stream is (1<18)-1 but this avoids the
536          * conversion to big cluster.
537          */
538         if (length > ClusterTraitsSmall.VALUE_SIZE_MAX)
539             len = setValueBig(index, bytes, length);
540         else
541             len = setValueSmall(index, bytes, length);
542         if (DEBUG_STAT) {
543             ++info.nValues;
544             info.sValues += len + length;
545         }
546     }
547
548     final void setValue(Change c, byte[] bytes, int length) {
549         short ri = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(c.key0);
550         setValue(ri, bytes, length);
551         c.initValue();
552     }
553
554     final void modiValue(Change c, long voffset, int length, byte[] bytes, int offset) {
555         checkInitialization();
556         int ri = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(c.key0);
557         if (DEBUG)
558             printlnd("Modify value ri=" + ri
559                     + " voff=" + voffset
560                     + " vlen=" + length
561                     + " blen=" + bytes.length
562                     + " boff=" + offset
563                     + " bytes=" + Arrays.toString(Arrays.copyOfRange(bytes, 0, Math.min(10, bytes.length))));
564         modiValueBig(ri, voffset, length, bytes, offset);
565         c.init();
566         if (DEBUG_STAT) {
567             ++info.nValues;
568             info.sValues += length;
569         }
570     }
571     final void setImmutable(boolean immutable) {
572         checkInitialization();
573         clusterChange2.setImmutable(immutable);
574     }
575     final void undoValueEx(int resourceIndex) {
576         checkInitialization();
577         clusterChange2.undoValueEx(resourceIndex);
578     }
579     final void setDeleted(boolean deleted) {
580         checkInitialization();
581         clusterChange2.setDeleted(deleted);
582     }
583     final void corrupt() {
584         checkInitialization();
585         addByte((byte)0);
586     }
587     /**
588      * @param graphSession
589      * @param clusterId
590      * @return true if actually flushed something
591      */
592     final boolean flush(GraphSession graphSession, ClusterUID clusterUID) {
593         if (byteIndex > 0) {
594             if(DebugPolicy.REPORT_CLUSTER_STREAM)
595                 System.err.println("Flush cluster change set stream " + this);
596             setHeaderVectorSize(byteIndex);
597             byte[] copy = new byte[byteIndex + HEADER_SIZE];
598             System.arraycopy(header, 0, copy, 0, HEADER_SIZE);
599             System.arraycopy(bytes, 0, copy, HEADER_SIZE, byteIndex);
600             UpdateClusterFunction updateClusterFunction = new UpdateClusterFunction(copy);
601             if (DEBUG_CCS) {
602                 for (DebugStm stm : debugStms)
603                     printlnd(stm.toString2());
604                 debugStms.clear();
605             }
606             if (DEBUG_STAT) {
607                 info.tot = updateClusterFunction.operation.length;
608                 printlnd("ReallyFlush: " + info.toString());
609                 sum.add(info);
610                 printlnd("ReallyFlush sum: " + sum.toString());
611             }
612             // long start = System.nanoTime();
613             graphSession.updateCluster(updateClusterFunction);
614             // long duration = System.nanoTime() - start;
615             // duration2 += duration;
616             // System.err.println("updateCluster " + 1e-9*duration);
617             // System.err.println("updateCluster total " + 1e-9*duration2);
618             clear();
619             clusterChange2.flush(graphSession);
620             return true;
621         } else if (clusterChange2.isDirty()) {
622             clusterChange2.flush(graphSession);
623             clear();
624             return true;
625         } else if (flushed) {
626             flushed = false;
627             return true;
628         } else {
629             return true;
630         }
631     }
632
633     final void flushInternal(GraphSession graphSession, ClusterUID clusterUID) {
634         flush(graphSession, clusterUID);
635         flushed = true;
636     }
637
638     final class ForeignTable {
639         private final TLongIntHashMap table = new TLongIntHashMap();
640
641         private long createKey(short index, long cluster) {
642             assert (cluster <= (1L << 48) - 1);
643             return (cluster << 14) | index;
644         }
645
646         public int get(short index, long cluster) {
647             int value = table.get(createKey(index, cluster));
648             if (DEBUG)
649                 printlnd("ForeignTable get c=" + clusterUID + " i="
650                         + (value - 1) + " r=" + index + " rc=" + cluster);
651             return value;
652         }
653
654         public int put(short index, long cluster, int value) {
655             if (DEBUG)
656                 printlnd("ForeignTable put c=" + clusterUID + " i="
657                         + (value - 1) + " r=" + index + " rc=" + cluster);
658             return table.put(createKey(index, cluster), value);
659         }
660
661         public int size() {
662             return table.size();
663         }
664
665         public void clear() {
666             table.clear();
667         }
668     }
669
670     @Override
671     public int hashCode() {
672         return 31*clusterImpl.getClusterKey();
673     }
674
675     @Override
676     public boolean equals(Object object) {
677         if (this == object)
678             return true;
679         else if (object == null)
680             return false;
681         else if (!(object instanceof ClusterChange))
682             return false;
683         ClusterChange r = (ClusterChange)object;
684         return r.clusterImpl.getClusterKey() == clusterImpl.getClusterKey();
685     }
686
687
688 }