1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.db.procore.cluster;
\r
14 import java.util.Vector;
\r
16 import org.simantics.db.exception.InternalException;
\r
17 import org.simantics.db.exception.RuntimeDatabaseException;
\r
18 import org.simantics.db.procore.cluster.CCSParser.ReferenceType;
\r
19 import org.simantics.db.procore.cluster.CCSParser.StmEnum;
\r
20 import org.simantics.db.service.ClusterUID;
\r
22 public class ClusterChangeSet implements ClusterChangeSetI {
\r
23 static interface IteratorI {
\r
25 static private final boolean DEBUG = false;
\r
26 static private final int HEADER_SIZE = 20;
\r
27 private final int version;
\r
28 private final ClusterUID clusterUID;
\r
29 private final byte[] bytes;
\r
31 public static ClusterChangeSetI create(byte[] rawData, String compressionCodec)
\r
32 throws InternalException {
\r
34 // TODO: Find maybe a better way to do this
\r
36 if (compressionCodec.equals("LZ4")) {
\r
37 LZ4.DecompressStruct data = LZ4.decompress(rawData);
\r
39 } else if (compressionCodec.equals("FLZ")) {
\r
40 FastLZ.DecompressStruct data = FastLZ.decompress(rawData);
\r
43 throw new RuntimeDatabaseException("No compressionCodec given!");
\r
45 return new ClusterChangeSet(bytes);
\r
48 public String toString() {
\r
49 return "cid=" + clusterUID + " len=" + bytes.length;
\r
51 private ClusterChangeSet(byte[] abytes) {
\r
52 this.bytes = abytes;
\r
53 if (bytes.length < HEADER_SIZE + 4)
\r
54 throw new RuntimeDatabaseException("Cluster change must contain header and size. length=" + bytes.length);
\r
55 version = CCSParser.getInt(bytes, 0);
\r
56 if (version <1 || version > 2)
\r
57 throw new RuntimeDatabaseException("Unsupported cluster change set version=" + version);
\r
58 clusterUID = ClusterUID.make(abytes, 4);
\r
59 if (ClusterUID.Null.equals(clusterUID))
\r
60 throw new RuntimeDatabaseException("Cluster uid can not be null.");
\r
62 System.out.println("DEBUG: Cluster uid=" + clusterUID);
\r
63 int p = HEADER_SIZE;
\r
64 int size = CCSParser.getInt(bytes, p);
\r
66 System.out.println("Cluster change set version=2 is not supported. skipping...");
\r
69 for (; size > 0; size = CCSParser.getInt(bytes, p)) {
\r
70 mBlocks.push_back(new ClusterChangeSetBlock(p+=4, size, bytes));
\r
71 p += size; // skip block data
\r
75 public ClusterUID getClusterUID() {
\r
78 private boolean updateRequired() {
\r
81 private void update() {
\r
84 public void getNextOperation(Operation ar) {
\r
85 Iterator pIterator = null;
\r
86 if (null == ar.iterator) {
\r
87 if (updateRequired())
\r
89 int N = mBlocks.size();
\r
91 ar.type = OperationEnum.EndOf;
\r
94 pIterator = new Iterator(N-1);
\r
95 ar.iterator = pIterator;
\r
97 pIterator = (Iterator)ar.iterator;
\r
98 if (pIterator.block > pIterator.lastBlock) {
\r
99 ar.type = OperationEnum.EndOf;
\r
100 ar.iterator = null;
\r
102 } else if (pIterator.offset >= mBlocks.get(pIterator.block).size) {
\r
104 pIterator.foreignTable.init();
\r
105 pIterator.offset = 0;
\r
106 if (pIterator.block > pIterator.lastBlock) {
\r
107 ar.type = OperationEnum.EndOf;
\r
108 ar.iterator = null;
\r
112 if (pIterator.offset >= mBlocks.get(pIterator.block).size) {
\r
114 pIterator.foreignTable.init();
\r
115 pIterator.offset = 0;
\r
116 if (pIterator.block > pIterator.lastBlock) {
\r
117 ar.type = OperationEnum.EndOf;
\r
118 ar.iterator = null;
\r
122 ClusterChangeSetBlock r = mBlocks.get(pIterator.block);
\r
123 int inc = next(ar, pIterator, r.bytes, r.offset + pIterator.offset, r.offset + r.size);
\r
126 System.out.println("Iterarto offset increment is negative!");
\r
127 ar.type = OperationEnum.EndOf;
\r
128 ar.iterator = null;
\r
130 pIterator.offset += inc;
\r
132 private int next(Operation ar, Iterator pIterator, byte[] bytes, int ab, int ae) {
\r
133 CCSParser.Args args = new CCSParser.Args(clusterUID, pIterator.foreignTable, ar);
\r
139 System.out.println("CCS.next offset=" + p);
\r
140 short ri = 0; // resource index
\r
141 short kraa = (short)(bytes[p] & 0xFF);
\r
143 case 0: case 1: case 2: case 3:
\r
144 //0x000000?? add - ri12 + pi14 + oi14 = 40 / 8 = 5
\r
145 p = CCSParser.parseStm(StmEnum.Add, args, bytes, p, 2, ReferenceType.Local, ReferenceType.Local);
\r
147 case 4: case 5: case 6: case 7:
\r
148 //0x000001?? rem - ri12 + pi14 + oi14 = 40 / 8 = 5
\r
149 p = CCSParser.parseStm(StmEnum.Remove, args, bytes, p, 2, ReferenceType.Local, ReferenceType.Local);
\r
151 case 8: case 9: case 10: case 11:
\r
152 //0x000010?? add - ri12 + pi14 + oc62 = 88 / 8 = 11
\r
153 p = CCSParser.parseStm(StmEnum.Add, args, bytes, p, 2, ReferenceType.Local, ReferenceType.ForeignLong);
\r
155 case 12: case 13: case 14: case 15:
\r
156 //0x000011?? rem - ri12 + pi14 + oc62 = 88 / 8 = 11
\r
157 p = CCSParser.parseStm(StmEnum.Remove, args, bytes, p, 2, ReferenceType.Local, ReferenceType.ForeignLong);
\r
159 case 16: case 17: case 18: case 19:
\r
160 //0x000100?? add - ri12 + pc62 + oi14 = 88 / 8 = 11
\r
161 p = CCSParser.parseStm(StmEnum.Add, args, bytes, p, 2, ReferenceType.ForeignLong, ReferenceType.Local);
\r
163 case 20: case 21: case 22: case 23:
\r
164 //0x000101?? rem - ri12 + pc62 + oi14 = 88 / 8 = 11
\r
165 p = CCSParser.parseStm(StmEnum.Remove, args, bytes, p, 2, ReferenceType.ForeignLong, ReferenceType.Local);
\r
167 case 24: case 25: case 26: case 27:
\r
168 //0x000110?? add - ri12 + pc62 + oc62 = 136 / 8 = 17
\r
169 p = CCSParser.parseStm(StmEnum.Add, args, bytes, p, 2, ReferenceType.ForeignLong, ReferenceType.ForeignLong);
\r
171 case 28: case 29: case 30: case 31:
\r
172 //0x000111?? rem - ri12 + pc62 + oc62 = 136 / 8 = 17
\r
173 p = CCSParser.parseStm(StmEnum.Remove, args, bytes, p, 2, ReferenceType.ForeignLong, ReferenceType.ForeignLong);
\r
175 case 32: case 33: case 34: case 35:
\r
176 case 36: case 37: case 38: case 39:
\r
177 case 40: case 41: case 42: case 43:
\r
178 case 44: case 45: case 46: case 47: case 48:
\r
179 //0x0010???? rem - ri10 + pr08 + oi14 = 32 / 8 = 4
\r
180 p = CCSParser.parseStm(StmEnum.Remove, args, bytes, p, 4, ReferenceType.ForeignShort, ReferenceType.Local);
\r
183 //0x00110001 rem - ri14 + pi14 + pr08 + pad4 = 40 / 8 = 5
\r
184 p = CCSParser.parseStm(StmEnum.Remove, args, bytes, p, 0, ReferenceType.Local, ReferenceType.ForeignShort);
\r
187 //0x00110010 rem - ri14 + pr08 + oc62 + pad4 = 88 / 8 = 11
\r
188 p = CCSParser.parseStm(StmEnum.Remove, args, bytes, p, 0, ReferenceType.ForeignShort, ReferenceType.ForeignLong);
\r
191 //0x00110011 rem - ri14 + pc62 + or08 + pad4 = 88 / 8 = 11
\r
192 p = CCSParser.parseStm(StmEnum.Remove, args, bytes, p, 0, ReferenceType.ForeignLong, ReferenceType.ForeignShort);
\r
194 case 52: //0x00110100 cre - ri14 + pad2 = 16 / 8 = 2
\r
195 ri = CCSParser.getShort(bytes, p+1);
\r
197 System.out.println("Creating resource r=" + ri + " rc=" + clusterUID);
\r
198 args.createResource(ri);
\r
202 //0x00110101 set - ri14 + sz18 = 32 / 8 = 4 + sz * bytes
\r
203 int t = CCSParser.getInt(bytes, p + 1);
\r
204 ri = (short)(t & 0x3FFF);
\r
206 args.setValue(ri, bytes, p + 5, s);
\r
209 case 54: //0x00110110 del - ri14 + pad2 = 16 / 8 = 2
\r
210 ri = CCSParser.getShort(bytes, p+1);
\r
211 args.deleteValue(ri);
\r
215 //0x00110111 mod - ri14 + of58 + sz16 = 88 / 8 = 11 + sz * bytes
\r
216 ri = CCSParser.getShort(bytes, p+1);
\r
217 ri &= (1<<14)-1; // mask top 2 bits
\r
218 long vo = CCSParser.getLongN(bytes, p+3, 7); // get low 7 bytes
\r
219 vo |= (long)(bytes[p+2] & 0xC0) << (56-6); // add the top 2 bits
\r
221 int vsize = CCSParser.getShort(bytes, p);
\r
226 System.out.println("Modifying value r=" + ri + " rc=" + args.clusterUID +
\r
227 " value offset=" + vo + " size=" + vsize);
\r
228 if (pe - p < vsize)
\r
229 throw new RuntimeException("Illegal size=" + vsize + " limit=" + (pe - p));
\r
230 args.modifyValue(ri, vo, vsize, bytes, p);
\r
233 case 56: case 57: case 58: case 59:
\r
234 case 60: case 61: case 62: case 63: {
\r
235 //0x00111??? set - ri14 + sz2 = 16 / 8 = 2 + sz * bytes;
\r
236 byte s = (byte)(bytes[p] & 0x7);
\r
238 ri = CCSParser.getShort(bytes, p+1);
\r
240 byte t = bytes[p + 2];
\r
241 s |= (t &0xFF) >> 6;
\r
242 args.setValue(ri, bytes, p + 3, s);
\r
245 case 64: case 65: case 66: case 67:
\r
246 case 68: case 69: case 70: case 71:
\r
247 case 72: case 73: case 74: case 75:
\r
248 case 76: case 77: case 78: case 79:
\r
249 case 80: case 81: case 82: case 83:
\r
250 case 84: case 85: case 86: case 87:
\r
251 case 88: case 89: case 90: case 91:
\r
252 case 92: case 93: case 94: case 95:
\r
253 case 96: case 97: case 98: case 99:
\r
254 case 100: case 101: case 102: case 103:
\r
255 case 104: case 105: case 106: case 107:
\r
256 case 108: case 109: case 110: case 111:
\r
257 case 112: case 113: case 114: case 115:
\r
258 case 116: case 117: case 118: case 119:
\r
259 case 120: case 121: case 122: case 123:
\r
260 case 124: case 125: case 126: case 127:
\r
261 //0x01?????? add - ri08 + pr08 + or08 = 24 / 8 = 3
\r
262 p = CCSParser.parseStm(StmEnum.Add, args, bytes, p, 6, ReferenceType.ForeignShort, ReferenceType.ForeignShort);
\r
264 case 128: case 129: case 130: case 131:
\r
265 case 132: case 133: case 134: case 135:
\r
266 case 136: case 137: case 138: case 139:
\r
267 case 140: case 141: case 142: case 143:
\r
268 case 144: case 145: case 146: case 147:
\r
269 case 148: case 149: case 150: case 151:
\r
270 case 152: case 153: case 154: case 155:
\r
271 case 156: case 157: case 158: case 159:
\r
272 case 160: case 161: case 162: case 163:
\r
273 case 164: case 165: case 166: case 167:
\r
274 case 168: case 169: case 170: case 171:
\r
275 case 172: case 173: case 174: case 175:
\r
276 case 176: case 177: case 178: case 179:
\r
277 case 180: case 181: case 182: case 183:
\r
278 case 184: case 185: case 186: case 187:
\r
279 case 188: case 189: case 190:case 191:
\r
280 //0x10?????? rem - ri08 + pr08 + or08 = 24 / 8 = 3
\r
281 p = CCSParser.parseStm(StmEnum.Remove, args, bytes, p, 6, ReferenceType.ForeignShort, ReferenceType.ForeignShort);
\r
283 case 192: case 193: case 194: case 195:
\r
284 case 196: case 197: case 198: case 199:
\r
285 case 200: case 201: case 202: case 203:
\r
286 case 204: case 205: case 206: case 207:
\r
287 //0x1100???? add - ri10 + pi14 + pr08 = 32 / 8 = 4
\r
288 p = CCSParser.parseStm(StmEnum.Add, args, bytes, p, 4, ReferenceType.Local, ReferenceType.ForeignShort);
\r
290 case 208: case 209: case 210: case 211:
\r
291 case 212: case 213: case 214: case 215:
\r
292 case 216: case 217: case 218: case 219:
\r
293 case 220: case 221: case 222: case 223:
\r
294 //0x1101???? add - ri10 + pr08 + oi14 = 32 / 8 = 4
\r
295 p = CCSParser.parseStm(StmEnum.Add, args, bytes, p, 4, ReferenceType.ForeignShort, ReferenceType.Local);
\r
297 case 224: case 225: case 226: case 227:
\r
298 case 228: case 229: case 230: case 231:
\r
299 case 232: case 233: case 234: case 235:
\r
300 case 236: case 237: case 238: case 239:
\r
301 //0x1110???? add - ri10 + pr08 + oc62 = 80 / 8 = 10
\r
302 p = CCSParser.parseStm(StmEnum.Add, args, bytes, p, 4, ReferenceType.ForeignShort, ReferenceType.ForeignLong);
\r
304 case 240: case 241: case 242: case 243:
\r
305 case 244: case 245: case 246: case 247:
\r
306 case 248: case 249: case 250: case 251:
\r
307 case 252: case 253: case 254: case 255:
\r
308 //0x1111???? add - ri10 + pc62 + or08 = 80 / 8 = 10
\r
309 p = CCSParser.parseStm(StmEnum.Add, args, bytes, p, 4, ReferenceType.ForeignLong, ReferenceType.ForeignShort);
\r
312 throw new RuntimeException("Internal error, contact application support.");
\r
317 private static class ClusterChangeSetBlock {
\r
318 ClusterChangeSetBlock(int offset, int size, byte[] bytes) {
\r
319 this.bytes = bytes;
\r
320 this.offset = offset;
\r
327 private static class Blocks {
\r
329 mBlocks = new Vector<ClusterChangeSetBlock>();
\r
330 mBlocks.ensureCapacity(BLOCK_INCREMENT);
\r
333 return mBlocks.size();
\r
335 void push_back(ClusterChangeSetBlock ar) {
\r
336 if (mBlocks.size() == mBlocks.capacity())
\r
337 mBlocks.ensureCapacity(mBlocks.size() + BLOCK_INCREMENT);
\r
340 ClusterChangeSetBlock get(int i) {
\r
341 return mBlocks.get(i);
\r
343 // How many block elements are allocated when out of space.
\r
344 private static final int BLOCK_INCREMENT = 10;
\r
345 private Vector<ClusterChangeSetBlock> mBlocks;
\r
347 private static class Iterator implements IteratorI {
\r
348 Iterator(int lastBlock) {
\r
349 this.lastBlock = lastBlock;
\r
350 this.foreignTable = new CCSParser.ForeignTable();
\r
355 CCSParser.ForeignTable foreignTable;
\r
357 private Blocks mBlocks = new Blocks();
\r