1 package fi.vtt.simantics.procore.internal;
\r
3 import java.util.ArrayList;
\r
4 import java.util.Arrays;
\r
5 import java.util.List;
\r
7 import org.simantics.db.exception.RuntimeDatabaseException;
\r
8 import org.simantics.db.impl.ClusterTraitsBase;
\r
9 import org.simantics.db.procore.cluster.ClusterImpl;
\r
10 import org.simantics.db.procore.cluster.ClusterTraits;
\r
11 import org.simantics.db.procore.cluster.ClusterTraitsSmall;
\r
12 import org.simantics.db.service.Bytes;
\r
13 import org.simantics.db.service.ClusterUID;
\r
15 import fi.vtt.simantics.procore.DebugPolicy;
\r
16 import fi.vtt.simantics.procore.internal.ClusterStream.ClusterEnum;
\r
17 import fi.vtt.simantics.procore.internal.ClusterStream.Data;
\r
18 import fi.vtt.simantics.procore.internal.ClusterStream.DebugInfo;
\r
19 import fi.vtt.simantics.procore.internal.ClusterStream.OpEnum;
\r
20 import fi.vtt.simantics.procore.internal.ClusterStream.StmEnum;
\r
21 import gnu.trove.map.hash.TIntByteHashMap;
\r
22 import gnu.trove.map.hash.TLongIntHashMap;
\r
24 public final class ClusterChange {
\r
25 public static final int VERSION = 1;
\r
26 public static final byte ADD_OPERATION = 2;
\r
27 public static final byte REMOVE_OPERATION = 3;
\r
28 public static final byte DELETE_OPERATION = 5;
\r
30 public static final boolean DEBUG = false;
\r
31 public static final boolean DEBUG_STAT = false;
\r
32 public static final boolean DEBUG_CCS = false;
\r
34 private static DebugInfo sum = new DebugInfo();
\r
36 public final TIntByteHashMap foreignTable = new TIntByteHashMap();
\r
37 private final DebugInfo info;
\r
38 private final GraphSession graphSession;
\r
39 public final ClusterUID clusterUID;
\r
40 private final int SIZE_OFFSET;
\r
41 private final int HEADER_SIZE;
\r
42 // How much buffer is used before stream is flushed to server. The bigger the better.
\r
43 public static final int MAX_FIXED_BYTES = (1<<15) + (1<<14);
\r
44 private static final int MAX_FIXED_OPERATION_SIZE = 17 + 16;
\r
45 private static final int MAX_FIXED_OPERATION_SIZE_AND_ROOM_FOR_ERROR = MAX_FIXED_OPERATION_SIZE + 36;
\r
46 private int nextSize = MAX_FIXED_BYTES;
\r
48 private byte[] bytes = null; // Operation data.
\r
49 private final byte[] header;
\r
50 private boolean flushed = false;
\r
51 private final ClusterStream clusterStream;
\r
52 private final ClusterChange2 clusterChange2;
\r
54 public ClusterImpl clusterImpl;
\r
56 public ClusterChange(ClusterStream clusterStream, ClusterImpl clusterImpl) {
\r
57 this.clusterImpl = clusterImpl;
\r
58 clusterUID = clusterImpl.getClusterUID();
\r
59 long[] longs = new long[ClusterUID.getLongLength()];
\r
60 clusterUID.toLong(longs, 0);
\r
61 this.graphSession = clusterStream.graphSession;
\r
62 info = new DebugInfo();
\r
63 HEADER_SIZE = 8 + longs.length * 8;
\r
64 header = new byte[HEADER_SIZE];
\r
66 Bytes.writeLE(header, SIZE_OFFSET + 0, 0); // Correct byte vector size is set with setHeaderVectorSize() later.
\r
67 Bytes.writeLE(header, SIZE_OFFSET + 4, VERSION);
\r
68 for (int i=0, offset=8; i<longs.length; ++i, offset+=8)
\r
69 Bytes.writeLE(header, offset, longs[i]);
\r
71 this.clusterStream = clusterStream;
\r
72 this.clusterChange2 = new ClusterChange2(clusterUID, clusterImpl);
\r
73 clusterStream.changes.add(this);
\r
76 private void setHeaderVectorSize(int size) {
\r
78 throw new RuntimeDatabaseException("Change set size can't be negative.");
\r
79 int len = size + HEADER_SIZE - SIZE_OFFSET - 4;
\r
80 Bytes.writeLE(header, SIZE_OFFSET, len);
\r
83 public String toString() {
\r
84 return super.toString() + " cluster=" + clusterImpl.getClusterUID() + " id=" + clusterImpl.getClusterId() + " off=" + byteIndex;
\r
86 private final void initBuffer() {
\r
88 if (null == bytes || bytes.length < nextSize) {
\r
89 bytes = new byte[nextSize];
\r
90 nextSize = MAX_FIXED_BYTES;
\r
94 private final void clear() {
\r
95 if(clusterImpl != null && clusterImpl.change != null)
\r
96 clusterImpl.change.init();
\r
97 foreignTable.clear();
\r
104 private final void checkInitialization() {
\r
105 if (0 == byteIndex)
\r
106 clusterStream.changes.addChange(this);
\r
108 private final void printlnd(String s) {
\r
109 System.out.println("DEBUG: ClusterChange " + clusterUID + ": " + s);
\r
111 public final void createResource(short index) {
\r
112 checkInitialization();
\r
114 printlnd("New ri=" + index + " offset=" + byteIndex);
\r
115 if (index > ClusterTraits.getMaxNumberOfResources())
\r
116 throw new RuntimeDatabaseException("Illegal resource index=" + index + ".");
\r
117 checkBufferSpace(null);
\r
118 bytes[byteIndex++] = (byte)52;
\r
119 bytes[byteIndex++] = (byte)index;
\r
120 bytes[byteIndex++] = (byte)(index>>>8);
\r
122 void flushCollect(Change c) {
\r
123 flushInternal(graphSession, clusterUID);
\r
125 printlnd("Cluster change data was flushed.");
\r
128 printlnd("Clearing lookup for " + c.toString());
\r
132 if (null != clusterImpl) {
\r
133 clusterImpl.foreignLookup = null;
\r
137 private final boolean checkBufferSpace(Change c) {
\r
138 clusterStream.changes.checkFlush();
\r
139 if(bytes == null) initBuffer();
\r
140 if (MAX_FIXED_BYTES - byteIndex > MAX_FIXED_OPERATION_SIZE_AND_ROOM_FOR_ERROR) {
\r
148 private final void checkBufferSpace(int size) {
\r
149 if(bytes == null) initBuffer();
\r
150 if (bytes.length - byteIndex >= size)
\r
152 nextSize = Math.max(MAX_FIXED_BYTES, size);
\r
153 flushInternal(graphSession, clusterUID);
\r
157 final void addChange(Change c) {
\r
158 checkInitialization();
\r
159 checkBufferSpace(c);
\r
160 byte operation = c.op0;
\r
161 if(operation == ADD_OPERATION)
\r
162 addStm(c, StmEnum.Add);
\r
163 else if (operation == REMOVE_OPERATION)
\r
164 addStm(c, StmEnum.Remove);
\r
165 else if (operation == DELETE_OPERATION) {
\r
167 printlnd("Delete value offset=" + byteIndex + " " + c);
\r
168 addByte(OpEnum.Delete.getOrMask());
\r
169 addShort(ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(c.key0));
\r
174 private final void addForeignLong(short index, ClusterUID clusterUID) {
\r
175 byteIndex = clusterUID.toByte(bytes, byteIndex);
\r
176 bytes[byteIndex++] = (byte)(index & 0xFF);
\r
177 bytes[byteIndex++] = (byte)(index >>> 8);
\r
180 private final ClusterEnum addIndexAndCluster(int key, ClusterUID clusterUID, byte lookIndex, byte[] lookup) {
\r
181 assert(!clusterUID.equals(ClusterUID.Null));
\r
182 short resourceIndex = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(key);
\r
183 if (clusterUID.equals(this.clusterUID)) {
\r
184 bytes[byteIndex++] = (byte)(resourceIndex & 0xFF);
\r
185 bytes[byteIndex++] = (byte)(resourceIndex >>> 8);
\r
186 return ClusterEnum.Local;
\r
190 if(lookIndex > 0) {
\r
192 foreign = lookup[lookIndex];
\r
194 foreign = foreignTable.get(key);
\r
196 if (0 != foreign) {
\r
198 throw new RuntimeDatabaseException("Internal error, contact application support." +
\r
199 "Too big foreing index=" + foreign + " max=256");
\r
201 bytes[byteIndex++] = foreign;
\r
202 return ClusterEnum.ForeignShort;
\r
204 byte position = (byte) (foreignTable.size() + 1);
\r
206 lookup[lookIndex] = position;
\r
207 foreignTable.put(key, position);
\r
209 info.sForeign = foreignTable.size();
\r
210 if (clusterUID.equals(ClusterUID.Null))
\r
211 throw new RuntimeDatabaseException("Internal error, contact application support." +
\r
212 "Cluster unique id not defined for foreing cluster.");
\r
213 addForeignLong(resourceIndex, clusterUID);
\r
214 return ClusterEnum.ForeignLong;
\r
218 private final void addByte(byte b) {
\r
219 bytes[byteIndex++] = b;
\r
222 private final void addShort(short s) {
\r
223 bytes[byteIndex++] = (byte)(s & 0xFF);
\r
224 bytes[byteIndex++] = (byte)(s >>> 8);
\r
227 // private final void addShort(int s) {
\r
228 // bytes[byteIndex++] = (byte) (s & 0xFF);
\r
229 // bytes[byteIndex++] = (byte) ((s >>> 8) & 0xFF);
\r
232 private final void addInt(int i) {
\r
233 // System.err.println("addInt " + i + " " + i);
\r
234 bytes[byteIndex++] = (byte) (i & 0xFF);
\r
235 bytes[byteIndex++] = (byte) ((i >>> 8) & 0xFF);
\r
236 bytes[byteIndex++] = (byte) ((i >>> 16) & 0xFF);
\r
237 bytes[byteIndex++] = (byte) ((i >>> 24) & 0xFF);
\r
238 // buffer.asIntBuffer().put(i);
\r
239 // buffer.position(buffer.position()+4);
\r
242 // private void addLong6(long l) {
\r
243 //// System.err.println("addLong " + l);
\r
244 // bytes[byteIndex++] = (byte) (l & 0xFF);
\r
245 // bytes[byteIndex++] = (byte) ((l >>> 8) & 0xFF);
\r
246 // bytes[byteIndex++] = (byte) ((l >>> 16) & 0xFF);
\r
247 // bytes[byteIndex++] = (byte) ((l >>> 24) & 0xFF);
\r
248 // bytes[byteIndex++] = (byte) ((l >>> 32) & 0xFF);
\r
249 // bytes[byteIndex++] = (byte) ((l >>> 40) & 0xFF);
\r
250 // // buffer.asLongBuffer().put(l);
\r
251 // // buffer.position(buffer.position() + 6);
\r
254 private void addLong7(long l) {
\r
255 bytes[byteIndex++] = (byte) (l & 0xFF);
\r
256 bytes[byteIndex++] = (byte) ((l >>> 8) & 0xFF);
\r
257 bytes[byteIndex++] = (byte) ((l >>> 16) & 0xFF);
\r
258 bytes[byteIndex++] = (byte) ((l >>> 24) & 0xFF);
\r
259 bytes[byteIndex++] = (byte) ((l >>> 32) & 0xFF);
\r
260 bytes[byteIndex++] = (byte) ((l >>> 40) & 0xFF);
\r
261 bytes[byteIndex++] = (byte) ((l >>> 48) & 0xFF);
\r
262 // buffer.asLongBuffer().put(l);
\r
263 // buffer.position(buffer.position() + 7);
\r
266 // private void addLong(long l) {
\r
267 // bytes[byteIndex++] = (byte) (l & 0xFF);
\r
268 // bytes[byteIndex++] = (byte) ((l >>> 8) & 0xFF);
\r
269 // bytes[byteIndex++] = (byte) ((l >>> 16) & 0xFF);
\r
270 // bytes[byteIndex++] = (byte) ((l >>> 24) & 0xFF);
\r
271 // bytes[byteIndex++] = (byte) ((l >>> 32) & 0xFF);
\r
272 // bytes[byteIndex++] = (byte) ((l >>> 40) & 0xFF);
\r
273 // bytes[byteIndex++] = (byte) ((l >>> 48) & 0xFF);
\r
274 // bytes[byteIndex++] = (byte) ((l >>> 56) & 0xFF);
\r
276 private final byte bufferPop() {
\r
277 return bytes[--byteIndex];
\r
280 final class DebugStm {
\r
288 DebugStm(StmEnum e, int r, int p, ClusterUID pc, int o, ClusterUID oc) {
\r
298 public String toString() {
\r
299 short ri = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(r);
\r
300 short pi = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(p);
\r
301 short oi = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(o);
\r
302 return "" + e + " rk=" + r + " ri=" + ri + " rc=" + clusterUID
\r
303 + " pk=" + p + " pi=" + pi + " pc=" + pc
\r
304 + " ok=" + o + " oi=" + oi + " oc=" + oc;
\r
307 public String toString2() {
\r
308 return "" + e + " r=" + r + " rc=" + clusterUID + " p=" + p
\r
309 + " pc=" + pc + " o=" + o + " oc=" + oc;
\r
312 public String toString3() {
\r
313 short ri = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(r);
\r
314 short pi = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(p);
\r
315 short oi = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(o);
\r
316 return "" + e + " ri=" + ri
\r
317 + " pi=" + pi + " pc=" + pc
\r
318 + " oi=" + oi + " oc=" + oc;
\r
322 private List<DebugStm> debugStms = new ArrayList<DebugStm>();
\r
324 @SuppressWarnings("unused")
\r
325 private final void addStm(Change c, StmEnum stmEnum) {
\r
329 if (DEBUG || DEBUG_CCS) {
\r
330 DebugStm d = new DebugStm(stmEnum, c.key0, c.key1, c.clusterUID1, c.key2, c.clusterUID2);
\r
334 printlnd(d.toString3() + " offset=" + byteIndex);
\r
337 // int opPos = buffer.position();
\r
338 int opPos = byteIndex++;
\r
339 // buffer.put((byte)0); // operation code
\r
340 // addByte((byte)0);
\r
342 boolean done = true;
\r
344 ClusterEnum a = addIndexAndCluster(c.key1, c.clusterUID1, c.lookIndex1, c.lookup1);
\r
347 // ForeignShort = byte
\r
349 // ForeignLong = 8 byte
\r
350 if (a != ClusterEnum.ForeignShort) {
\r
355 ClusterEnum b = addIndexAndCluster(c.key2, c.clusterUID2, c.lookIndex2, c.lookup2);
\r
357 if (b != ClusterEnum.ForeignShort) {
\r
362 int ri = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(c.key0);
\r
363 if (ClusterTraitsSmall.isIllegalResourceIndex(ri))
\r
364 throw new RuntimeDatabaseException("Assertion error. Illegal resource index=" + ri);
\r
365 bytes[byteIndex++] = (byte)ri; // index low byte
\r
367 Data data = ClusterEnum.getData(stmEnum, a, b);
\r
368 int left = 6 - data.bits;
\r
369 int op = ri >>> (8 + left);
\r
371 ri &= (1 << left) - 1;
\r
372 if (a != ClusterEnum.ForeignShort) {
\r
376 if (b != ClusterEnum.ForeignShort) {
\r
380 switch (data.bytes) {
\r
382 throw new RuntimeDatabaseException("Assertion error. Illegal number of bytes=" + data.bytes);
\r
384 bytes[byteIndex++] = (byte)(ri & 0xFF);
\r
385 bytes[byteIndex++] = (byte)((ri >>> 8) & 0xFF);
\r
388 bytes[byteIndex++] = (byte)(ri & 0xFF);
\r
394 this.bytes[opPos] = (byte)op;
\r
396 if (stmEnum == StmEnum.Add)
\r
397 bytes[opPos] = (byte)((ri >>> 8) + 64);
\r
399 bytes[opPos] = (byte)((ri >>> 8) + 128);
\r
402 if (a == ClusterEnum.Local && b == ClusterEnum.Local) {
\r
404 } else if (a == ClusterEnum.Local || b == ClusterEnum.Local) {
\r
410 if (foreignTable.size() > 252)
\r
411 flushInternal(graphSession, clusterUID);
\r
414 private final int modiValue(int ri, long value_offset, byte[] bytes, int offset, int size) {
\r
416 printlnd("Modify value ri=" + ri + " vo=" + value_offset + " size=" + size + " total=" + bytes.length);
\r
417 if (ClusterTraitsBase.isIllegalResourceIndex(ri))
\r
418 throw new RuntimeDatabaseException("Assertion error. Illegal resource index=" + ri);
\r
419 if (value_offset > (1L << 58 - 1))
\r
420 throw new RuntimeDatabaseException("Illegal value offset="
\r
422 if (size < 0 || size > MAX_FIXED_BYTES - 1)
\r
423 throw new RuntimeDatabaseException("Illegal value size=" + size);
\r
424 if (offset + size > bytes.length)
\r
425 throw new RuntimeDatabaseException("Illegal value size=" + size);
\r
426 checkBufferSpace(12 + size);
\r
427 addByte(OpEnum.Modify.getOrMask());
\r
428 ri |= (value_offset >>> 56) << 14; // add top two bits
\r
429 addShort((short) ri);
\r
430 value_offset &= (1L << 56) - 1;
\r
431 addLong7(value_offset);
\r
432 addShort((short) size);
\r
434 System.out.println("Modify value fixed part end offset=" + byteIndex);
\r
435 int copied = Math.min(size, this.bytes.length - byteIndex);
\r
436 System.arraycopy(bytes, offset, this.bytes, byteIndex, copied);
\r
441 private final void modiValueBig(int ri, long voffset, int left, byte[] bytes, int offset) {
\r
442 checkBufferSpace(0);
\r
443 int current = Math.min(this.bytes.length - byteIndex - 12, left);
\r
445 int written = modiValue(ri, voffset, bytes, offset, current);
\r
446 voffset += written;
\r
450 flushInternal(graphSession, clusterUID);
\r
452 int length = Math.min(left, (1 << 16) - 1);
\r
454 printlnd("Modify big value ri=" + ri + " vo=" + voffset + " len=" + length);
\r
455 int psize = length + 12;
\r
456 setHeaderVectorSize(psize);
\r
457 byte[] message = new byte[psize+HEADER_SIZE];
\r
458 System.arraycopy(header, 0, message, 0, HEADER_SIZE);
\r
459 int to = HEADER_SIZE;
\r
460 Bytes.write(message, to++, OpEnum.Modify.getOrMask());
\r
461 short index = (short)(ri | (voffset >>> 56)<<14); // add top two bits
\r
462 Bytes.writeLE(message, to, index); to += 2;
\r
463 Bytes.writeLE7(message, to, voffset & ((1L << 56) - 1)); to += 7;
\r
464 Bytes.writeLE(message, to, (short)length); to += 2;
\r
465 System.arraycopy(bytes, offset, message, to, length);
\r
466 graphSession.updateCluster(new UpdateClusterFunction(message));
\r
473 private final int setValueBig(int ri, byte[] bytes, int length_) {
\r
474 checkBufferSpace(12);
\r
478 int left = length_;
\r
480 int length = Math.min(left, MAX_FIXED_BYTES - 12 - byteIndex);
\r
482 printlnd("Set big value ri=" + ri + " vo=" + voffset + " len=" + length);
\r
483 int written = modiValue(ri, voffset, bytes, offset, length);
\r
485 voffset += written;
\r
488 checkBufferSpace(12);
\r
493 private final int setValueSmall(int ri, byte[] bytes, int length) {
\r
494 checkBufferSpace(5 + length);
\r
495 int pos = byteIndex;
\r
496 int i = length << 14 | ri;
\r
498 byte op = (byte) (OpEnum.SetShort.getOrMask() | length >>> 2);
\r
500 short s = (short) i;
\r
503 addByte(OpEnum.Set.getOrMask());
\r
506 System.arraycopy(bytes, 0, this.bytes, byteIndex, length);
\r
507 byteIndex += length;
\r
508 int len = byteIndex - pos;
\r
512 final void setValue(short index, byte[] bytes) {
\r
513 setValue(index, bytes, bytes.length);
\r
516 final void setValue(short index, byte[] bytes, int length) {
\r
517 checkInitialization();
\r
518 if (ClusterTraitsBase.isIllegalResourceIndex(index))
\r
519 throw new RuntimeDatabaseException("Assertion error. Illegal resource index=" + index);
\r
521 printlnd("Set value ri=" + index
\r
523 + " bytes=" + Arrays.toString(Arrays.copyOfRange(bytes, 0, Math.min(10, length))));
\r
526 * The limit for the cluster stream is (1<18)-1 but this avoids the
\r
527 * conversion to big cluster.
\r
529 if (length > ClusterTraitsSmall.VALUE_SIZE_MAX)
\r
530 len = setValueBig(index, bytes, length);
\r
532 len = setValueSmall(index, bytes, length);
\r
535 info.sValues += len + length;
\r
539 final void setValue(Change c, byte[] bytes, int length) {
\r
540 short ri = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(c.key0);
\r
541 setValue(ri, bytes, length);
\r
545 final void modiValue(Change c, long voffset, int length, byte[] bytes, int offset) {
\r
546 checkInitialization();
\r
547 int ri = ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(c.key0);
\r
549 printlnd("Modify value ri=" + ri
\r
550 + " voff=" + voffset
\r
551 + " vlen=" + length
\r
552 + " blen=" + bytes.length
\r
553 + " boff=" + offset
\r
554 + " bytes=" + Arrays.toString(Arrays.copyOfRange(bytes, 0, Math.min(10, bytes.length))));
\r
555 modiValueBig(ri, voffset, length, bytes, offset);
\r
559 info.sValues += length;
\r
562 final void setImmutable(boolean immutable) {
\r
563 checkInitialization();
\r
564 clusterChange2.setImmutable(immutable);
\r
566 final void undoValueEx(int resourceIndex) {
\r
567 checkInitialization();
\r
568 clusterChange2.undoValueEx(resourceIndex);
\r
570 final void setDeleted(boolean deleted) {
\r
571 checkInitialization();
\r
572 clusterChange2.setDeleted(deleted);
\r
574 final void corrupt() {
\r
575 checkInitialization();
\r
579 * @param graphSession
\r
581 * @return true if actually flushed something
\r
583 final boolean flush(GraphSession graphSession, ClusterUID clusterUID) {
\r
584 if (byteIndex > 0) {
\r
585 if(DebugPolicy.REPORT_CLUSTER_STREAM)
\r
586 System.err.println("Flush cluster change set stream " + this);
\r
587 setHeaderVectorSize(byteIndex);
\r
588 byte[] copy = new byte[byteIndex + HEADER_SIZE];
\r
589 System.arraycopy(header, 0, copy, 0, HEADER_SIZE);
\r
590 System.arraycopy(bytes, 0, copy, HEADER_SIZE, byteIndex);
\r
591 UpdateClusterFunction updateClusterFunction = new UpdateClusterFunction(copy);
\r
593 for (DebugStm stm : debugStms)
\r
594 printlnd(stm.toString2());
\r
598 info.tot = updateClusterFunction.operation.length;
\r
599 printlnd("ReallyFlush: " + info.toString());
\r
601 printlnd("ReallyFlush sum: " + sum.toString());
\r
603 // long start = System.nanoTime();
\r
604 graphSession.updateCluster(updateClusterFunction);
\r
605 // long duration = System.nanoTime() - start;
\r
606 // duration2 += duration;
\r
607 // System.err.println("updateCluster " + 1e-9*duration);
\r
608 // System.err.println("updateCluster total " + 1e-9*duration2);
\r
610 clusterChange2.flush(graphSession);
\r
612 } else if (clusterChange2.isDirty()) {
\r
613 clusterChange2.flush(graphSession);
\r
616 } else if (flushed) {
\r
624 final void flushInternal(GraphSession graphSession, ClusterUID clusterUID) {
\r
625 flush(graphSession, clusterUID);
\r
629 final class ForeignTable {
\r
630 private final TLongIntHashMap table = new TLongIntHashMap();
\r
632 private long createKey(short index, long cluster) {
\r
633 assert (cluster <= (1L << 48) - 1);
\r
634 return (cluster << 14) | index;
\r
637 public int get(short index, long cluster) {
\r
638 int value = table.get(createKey(index, cluster));
\r
640 printlnd("ForeignTable get c=" + clusterUID + " i="
\r
641 + (value - 1) + " r=" + index + " rc=" + cluster);
\r
645 public int put(short index, long cluster, int value) {
\r
647 printlnd("ForeignTable put c=" + clusterUID + " i="
\r
648 + (value - 1) + " r=" + index + " rc=" + cluster);
\r
649 return table.put(createKey(index, cluster), value);
\r
652 public int size() {
\r
653 return table.size();
\r
656 public void clear() {
\r
662 public int hashCode() {
\r
663 return 31*clusterImpl.getClusterKey();
\r
667 public boolean equals(Object object) {
\r
668 if (this == object)
\r
670 else if (object == null)
\r
672 else if (!(object instanceof ClusterChange))
\r
674 ClusterChange r = (ClusterChange)object;
\r
675 return r.clusterImpl.getClusterKey() == clusterImpl.getClusterKey();
\r