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