1 package org.simantics.acorn.internal;
3 import java.util.Arrays;
4 import java.util.HashMap;
7 import org.simantics.acorn.ClusterManager;
8 import org.simantics.acorn.exception.IllegalAcornStateException;
9 import org.simantics.acorn.internal.ClusterStream.ClusterEnum;
10 import org.simantics.acorn.internal.ClusterStream.Data;
11 import org.simantics.acorn.internal.ClusterStream.StmEnum;
12 import org.simantics.db.exception.DatabaseException;
13 import org.simantics.db.service.Bytes;
14 import org.simantics.db.service.ClusterUID;
15 import org.slf4j.Logger;
16 import org.slf4j.LoggerFactory;
18 import fi.vtt.simantics.procore.internal.ClusterChange2;
20 abstract public class ClusterUpdateProcessorBase {
22 private static final Logger LOGGER = LoggerFactory.getLogger(ClusterUpdateProcessorBase.class);
24 public final static boolean DEBUG = false;
26 final protected ClusterManager manager;
27 final public byte[] bytes;
29 final private int len;
30 final private ClusterUID uid;
31 final private int clusterKey;
32 final public int version;
34 final Map<ClusterUID, Integer> clusterKeyCache = new HashMap<>();
36 public int getResourceKey(ClusterUID uid, int index) throws IllegalAcornStateException {
37 Integer match = clusterKeyCache.get(uid);
38 if(match != null) return match+index;
39 int key = manager.getResourceKeyWitoutMutex(uid, 0);
40 clusterKeyCache.put(uid, key);
45 public ClusterUpdateProcessorBase(ClusterManager client, byte[] operations) throws DatabaseException {
46 this.manager = client;
47 this.bytes = operations;
48 this.len = Bytes.readLE4(bytes, 0)+4; // whatta?
49 this.version = Bytes.readLE4(bytes, 4);
50 long cuid1 = Bytes.readLE8(bytes, 8);
51 long cuid2 = Bytes.readLE8(bytes, 16);
52 uid = ClusterUID.make(cuid1, cuid2);
54 client.clusterLRU.acquireMutex();
56 clusterKey = client.clusterLRU.getClusterKeyByUID(cuid1, cuid2) << 12;
57 } catch (Throwable t) {
58 throw new IllegalStateException(t);
60 client.clusterLRU.releaseMutex();
64 public ClusterUID getClusterUID() {
68 private void processCreate() {
69 int r = Bytes.readLE2(bytes, pos);
71 if(DEBUG) System.err.println("DEBUG: New ri=" + r + " offset=" + (pos-3-24));
74 } catch (DatabaseException e) {
75 LOGGER.error("resource create failed", e);
79 private void processDelete() {
80 int ri = Bytes.readLE2(bytes, pos);
83 if(DEBUG) System.err.println("DEBUG: Delete " + ri);
87 } catch (DatabaseException e) {
88 LOGGER.error("resource {} value delete failed", ri, e);
92 private void processModify(int op) {
94 int ri = Bytes.readLE2(bytes, pos);
96 long offset = Bytes.readLE7(bytes, pos);
98 int size = Bytes.readLE2(bytes, pos);
101 offset += (ri>>14) << 56;
105 throw new IllegalStateException();
107 throw new IllegalStateException();
109 throw new IllegalStateException();
111 if(DEBUG) System.err.println("DEBUG: Modify " + ri + " " + offset + " " + size + " offset=" + (pos-1-24) + " " + Arrays.toString(Arrays.copyOf(valueBuffer,size)));
114 modify(clusterKey + ri, offset, size, bytes, pos);
115 } catch (DatabaseException e) {
116 LOGGER.error("resource value modify(clusterKey: {}, ri: {}, offset: {}, size: {}, pos: {}) failed",
117 clusterKey, ri, offset, size, pos, e);
124 private void processSet(int op) {
126 int s = Bytes.readLE4(bytes, pos);
127 int length = (s >> 14);
129 throw new IllegalStateException();
133 System.arraycopy(bytes, pos, valueBuffer, 0, length);
136 if(DEBUG) System.err.println("DEBUG: Set " + r + " " + length + " offset=" + (pos-1-24) + " " + Arrays.toString(Arrays.copyOf(valueBuffer,length)));
139 set(clusterKey+r, valueBuffer, length);
140 } catch (DatabaseException e) {
141 LOGGER.error("resource value set(clusterKey: {}, r: {}, length: {}) failed",
142 clusterKey, r, length, e);
147 byte[] valueBuffer = new byte[65536];
149 private void processSetShort(int op) {
151 int s = Bytes.readLE2(bytes, pos);
152 int length = ((op&7)<<2) + (s >> 14);
154 throw new IllegalStateException();
156 throw new IllegalStateException();
159 if(DEBUG) System.err.println("DEBUG: SetShort " + r + " " + length + " offset=" + (pos-1-24) + " " + Arrays.toString(Arrays.copyOf(valueBuffer,length)));
162 System.arraycopy(bytes, pos, valueBuffer, 0, length);
166 set(clusterKey+r, valueBuffer, length);
167 } catch (DatabaseException e) {
168 LOGGER.error("resource value setShort(clusterKey: {}, r: {}, length: {}) failed",
169 clusterKey, r, length, e);
174 private void processStatementResource(ClusterEnum enu, int pOrO) {
175 if(ClusterEnum.ForeignShort == enu) {
176 int fs = bytes[pos++]&0xff;
177 foreignRefs[pOrO] = fs;
178 } else if(ClusterEnum.Local == enu) {
179 int lo = bytes[pos++]&0xff;
182 long l1 = Bytes.readLE8(bytes, pos);
184 long l2 = Bytes.readLE8(bytes, pos);
186 ClusterUID cuid = ClusterUID.make(l1, l2);
187 foreignClusters[foreignPos] = cuid;
188 int lo = bytes[pos++]&0xff;
189 foreignIndices[foreignPos] = lo;
190 foreignRefs[pOrO] = foreignPos;
196 ClusterUID[] foreignClusters = new ClusterUID[256];
197 int[] foreignIndices = new int[256];
199 int lows[] = new int[2];
200 int foreignRefs[] = new int[2];
202 private void processStatement(int op, StmEnum stmEnum, ClusterEnum p, ClusterEnum o) throws IllegalAcornStateException {
204 int curPos = pos-1-24;
206 processStatementResource(p, 0);
207 processStatementResource(o, 1);
209 int ri = bytes[pos++]&0xff;
213 ClusterUID puid = uid;
214 ClusterUID ouid = puid;
216 if(ClusterEnum.ForeignShort == p && ClusterEnum.ForeignShort == o) {
217 ri |= (op&0x3F) << 8;
219 Data data = ClusterEnum.getData(stmEnum, p, o);
220 // data.left is the amount of bytes in last two bytes
221 if(data.bytes == 0) {
222 ri = ri | ((op&0x3F)<<8);
225 int opBits = data.bits;
226 int extraBits = 6-opBits;
227 if(data.bytes == 1) {
228 extra = bytes[pos++]&0xff;
229 int high = extra >> extraBits;
230 if(ClusterEnum.ForeignShort == p) {
231 oi = lows[1] + (high<<8);
233 pi = lows[0] + (high<<8);
236 extra = Bytes.readLE2(bytes, pos);
238 int high1 = (extra >> extraBits)&((1<<6)-1);
239 int high2 = (extra >> (extraBits+6))&((1<<6)-1);
240 if(ClusterEnum.ForeignShort == p) {
241 oi = lows[1] + (high1<<8);
243 pi = lows[0] + (high1<<8);
244 oi = lows[1] + (high2<<8);
247 ri = ri | ((extra&((1<<extraBits)-1))<<8) | ((op&((1<<opBits)-1))<<(8+extraBits));
252 if(ClusterEnum.ForeignLong == p) {
253 int ref = foreignRefs[0];
254 foreignIndices[ref] = pi;
255 puid = foreignClusters[ref];
257 if(ClusterEnum.ForeignLong == o) {
258 int ref = foreignRefs[1];
259 foreignIndices[ref] = oi;
260 ouid = foreignClusters[ref];
263 if(ClusterEnum.ForeignShort == p) {
264 int ref = foreignRefs[0];
265 pi = foreignIndices[ref];
266 puid = foreignClusters[ref];
268 if(ClusterEnum.ForeignShort == o) {
269 int ref = foreignRefs[1];
270 oi = foreignIndices[ref];
271 ouid = foreignClusters[ref];
275 throw new IllegalStateException();
277 throw new IllegalStateException();
279 throw new IllegalStateException();
281 throw new IllegalStateException();
283 throw new IllegalStateException();
285 throw new IllegalStateException();
287 if(StmEnum.Add == stmEnum) {
290 System.err.println("DEBUG: ClusterChange " + uid + ": Add ri=" + ri + " pi=" + pi + " oi=" + oi + " pc=" + puid + " oc=" + ouid + " offset=" + curPos + " " + p.ordinal + " " + o.ordinal);
292 int predicateKey = getResourceKey(puid, pi);
293 int objectKey = getResourceKey(ouid, oi);
295 claim(clusterKey+ri, predicateKey, objectKey, puid, ouid);
296 } catch (DatabaseException e) {
297 LOGGER.error("statement add(clusterKey: {}, ri: {}, predicateKey: {}, objectKey: {}, puid: {}, ouid: {}) failed",
298 clusterKey, ri, predicateKey, objectKey, puid.toString(), ouid.toString(), e);
304 System.err.println("DEBUG: ClusterChange " + uid + ": Rem ri=" + ri + " pi=" + pi + " oi=" + oi + " pc=" + puid + " oc=" + ouid + " offset=" + curPos + " " + p.ordinal + " " + o.ordinal);
306 int predicateKey = getResourceKey(puid, pi);
307 int objectKey = getResourceKey(ouid, oi);
309 deny(clusterKey+ri, predicateKey, objectKey, puid, ouid);
310 } catch (DatabaseException e) {
311 LOGGER.error("statement deny(clusterKey: {}, ri: {}, predicateKey: {}, objectKey: {}, puid: {}, ouid: {}) failed",
312 clusterKey, ri, predicateKey, objectKey, puid.toString(), ouid.toString(), e);
319 public void process() throws IllegalAcornStateException {
320 if (version == ClusterChange.VERSION) {
322 } else if (version == ClusterChange2.VERSION) {
327 private void process1() throws IllegalAcornStateException {
331 if(DEBUG) System.err.println("DEBUG: process " + uid + " " + len);
333 // op resolution for statement operation:
339 // 3 first bits (000)
340 // op: 000000 | r12-13
341 // op: 000001 | r12-13
342 // op: 000010 | r12-13
343 // op: 000011 | r12-13
344 // op: 000100 | r12-13
345 // op: 000101 | r12-13
346 // op: 000110 | r12-13
347 // op: 000111 | r12-13
364 int op = bytes[pos++]&0xff;
366 // common prefix: 0011
370 processStatement(op, StmEnum.Remove, ClusterEnum.Local, ClusterEnum.ForeignShort);
373 processStatement(op, StmEnum.Remove, ClusterEnum.ForeignShort, ClusterEnum.ForeignLong);
376 processStatement(op, StmEnum.Remove, ClusterEnum.ForeignLong, ClusterEnum.ForeignShort);
378 // 52 = 32+16+4 = 00110100
382 // 53 = 32+16+4+1 = 00110101
386 // 54 = 32+16+4+2 = 00110110
390 // 55 = 32+16+4+2+1 = 00110111
396 int bits6 = ((int)op)&0xC0;
400 processStatement(op, StmEnum.Add, ClusterEnum.ForeignShort, ClusterEnum.ForeignShort);
403 processStatement(op, StmEnum.Remove, ClusterEnum.ForeignShort, ClusterEnum.ForeignShort);
407 int bits5 = ((int)op)&0xE0;
410 int bits2 = (((int)op)&0xFC) >> 2;
418 processStatement(op, StmEnum.Add, ClusterEnum.Local, ClusterEnum.Local);
421 processStatement(op, StmEnum.Remove, ClusterEnum.Local, ClusterEnum.Local);
424 processStatement(op, StmEnum.Add, ClusterEnum.Local, ClusterEnum.ForeignLong);
427 processStatement(op, StmEnum.Remove, ClusterEnum.Local, ClusterEnum.ForeignLong);
430 processStatement(op, StmEnum.Add, ClusterEnum.ForeignLong, ClusterEnum.Local);
433 processStatement(op, StmEnum.Remove, ClusterEnum.ForeignLong, ClusterEnum.Local);
436 processStatement(op, StmEnum.Add, ClusterEnum.ForeignLong, ClusterEnum.ForeignLong);
439 processStatement(op, StmEnum.Remove, ClusterEnum.ForeignLong, ClusterEnum.ForeignLong);
447 // 4 low bits of payload
449 int bits4 = (((int)op)&0xF0)>>4;
452 processStatement(op, StmEnum.Add, ClusterEnum.Local, ClusterEnum.ForeignShort);
455 processStatement(op, StmEnum.Add, ClusterEnum.ForeignShort, ClusterEnum.Local);
458 processStatement(op, StmEnum.Add, ClusterEnum.ForeignShort, ClusterEnum.ForeignLong);
461 processStatement(op, StmEnum.Add, ClusterEnum.ForeignLong, ClusterEnum.ForeignShort);
464 processStatement(op, StmEnum.Remove, ClusterEnum.ForeignShort, ClusterEnum.Local);
467 int bits3 = (((int)op)&0xF8)>>3;
483 private void process2() throws IllegalAcornStateException {
487 int op = bytes[pos++]&0xff;
491 case ClusterChange2.SET_IMMUTABLE_OPERATION:
492 processSetImmutable(op);
494 case ClusterChange2.UNDO_VALUE_OPERATION:
495 processUndoValue(op);
497 case ClusterChange2.SET_DELETED_OPERATION:
501 throw new IllegalAcornStateException("Can not process operation " + op + " for cluster " + uid);
508 private void processSetImmutable(int op) {
509 int value = bytes[pos++]&0xff;
510 setImmutable(value > 0);
513 private void processUndoValue(int op) {
514 Bytes.readLE4(bytes, pos);
518 abstract void create() throws DatabaseException;
519 abstract void delete(int resourceIndex) throws DatabaseException;
520 abstract void modify(int resourceKey, long offset, int size, byte[] bytes, int pos) throws DatabaseException;
521 abstract void set(int resourceKey, byte[] bytes, int length) throws DatabaseException;
523 abstract void claim(int resourceKey, int predicateKey, int objectKey, ClusterUID puid, ClusterUID ouid) throws DatabaseException;
524 abstract void deny(int resourceKey, int predicateKey, int objectKey, ClusterUID puid, ClusterUID ouid) throws DatabaseException;
526 abstract void setImmutable(boolean value);