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;
16 abstract public class ClusterUpdateProcessorBase {
18 public final static boolean DEBUG = false;
20 final protected ClusterManager manager;
21 final public byte[] bytes;
23 final private int len;
24 final private ClusterUID uid;
25 final private int clusterKey;
26 final public int version;
28 final Map<ClusterUID, Integer> clusterKeyCache = new HashMap<ClusterUID, Integer>();
30 public int getResourceKey(ClusterUID uid, int index) throws IllegalAcornStateException {
31 Integer match = clusterKeyCache.get(uid);
32 if(match != null) return match+index;
33 int key = manager.getResourceKeyWitoutMutex(uid, 0);
34 clusterKeyCache.put(uid, key);
39 public ClusterUpdateProcessorBase(ClusterManager client, byte[] operations) throws DatabaseException {
40 this.manager = client;
41 this.bytes = operations;
42 this.len = Bytes.readLE4(bytes, 0)+4; // whatta?
43 version = Bytes.readLE4(bytes, 4);
44 long cuid1 = Bytes.readLE8(bytes, 8);
45 long cuid2 = Bytes.readLE8(bytes, 16);
46 uid = ClusterUID.make(cuid1, cuid2);
48 client.clusterLRU.acquireMutex();
50 clusterKey = client.clusterLRU.getClusterKeyByUID(cuid1, cuid2) << 12;
51 } catch (Throwable t) {
52 throw new IllegalStateException(t);
54 client.clusterLRU.releaseMutex();
58 public ClusterUID getClusterUID() {
62 private void processCreate() {
63 int r = Bytes.readLE2(bytes, pos);
65 if(DEBUG) System.err.println("DEBUG: New ri=" + r + " offset=" + (pos-3-24));
68 } catch (DatabaseException e) {
74 private void processDelete() {
76 int ri = Bytes.readLE2(bytes, pos);
79 if(DEBUG) System.err.println("DEBUG: Delete " + ri);
83 } catch (DatabaseException e) {
89 private void processModify(int op) {
91 int ri = Bytes.readLE2(bytes, pos);
93 long offset = Bytes.readLE7(bytes, pos);
95 int size = Bytes.readLE2(bytes, pos);
98 offset += (ri>>14) << 56;
102 throw new IllegalStateException();
104 throw new IllegalStateException();
106 throw new IllegalStateException();
108 if(DEBUG) System.err.println("DEBUG: Modify " + ri + " " + offset + " " + size + " offset=" + (pos-1-24) + " " + Arrays.toString(Arrays.copyOf(valueBuffer,size)));
111 modify(clusterKey + ri, offset, size, bytes, pos);
112 } catch (DatabaseException e) {
120 private void processSet(int op) {
122 int s = Bytes.readLE4(bytes, pos);
123 int length = (s >> 14);
125 throw new IllegalStateException();
129 System.arraycopy(bytes, pos, valueBuffer, 0, length);
132 if(DEBUG) System.err.println("DEBUG: Set " + r + " " + length + " offset=" + (pos-1-24) + " " + Arrays.toString(Arrays.copyOf(valueBuffer,length)));
135 set(clusterKey+r, valueBuffer, length);
136 } catch (DatabaseException e) {
142 byte[] valueBuffer = new byte[65536];
144 private void processSetShort(int op) {
146 int s = Bytes.readLE2(bytes, pos);
147 int length = ((op&7)<<2) + (s >> 14);
149 throw new IllegalStateException();
151 throw new IllegalStateException();
154 if(DEBUG) System.err.println("DEBUG: SetShort " + r + " " + length + " offset=" + (pos-1-24) + " " + Arrays.toString(Arrays.copyOf(valueBuffer,length)));
157 System.arraycopy(bytes, pos, valueBuffer, 0, length);
161 set(clusterKey+r, valueBuffer, length);
162 } catch (DatabaseException e) {
168 private void processStatementResource(ClusterEnum enu, int pOrO) {
169 if(ClusterEnum.ForeignShort == enu) {
170 int fs = bytes[pos++]&0xff;
171 foreignRefs[pOrO] = fs;
172 } else if(ClusterEnum.Local == enu) {
173 int lo = bytes[pos++]&0xff;
176 long l1 = Bytes.readLE8(bytes, pos);
178 long l2 = Bytes.readLE8(bytes, pos);
180 ClusterUID cuid = ClusterUID.make(l1, l2);
181 foreignClusters[foreignPos] = cuid;
182 int lo = bytes[pos++]&0xff;
183 foreignIndices[foreignPos] = lo;
184 foreignRefs[pOrO] = foreignPos;
190 ClusterUID[] foreignClusters = new ClusterUID[256];
191 int[] foreignIndices = new int[256];
193 int lows[] = new int[2];
194 int foreignRefs[] = new int[2];
196 private void processStatement(int op, StmEnum stmEnum, ClusterEnum p, ClusterEnum o) throws IllegalAcornStateException {
198 int curPos = pos-1-24;
200 processStatementResource(p, 0);
201 processStatementResource(o, 1);
203 int ri = bytes[pos++]&0xff;
207 ClusterUID puid = uid;
208 ClusterUID ouid = puid;
210 if(ClusterEnum.ForeignShort == p && ClusterEnum.ForeignShort == o) {
211 ri |= (op&0x3F) << 8;
213 Data data = ClusterEnum.getData(stmEnum, p, o);
214 // data.left is the amount of bytes in last two bytes
215 if(data.bytes == 0) {
216 ri = ri | ((op&0x3F)<<8);
219 int opBits = data.bits;
220 int extraBits = 6-opBits;
221 if(data.bytes == 1) {
222 extra = bytes[pos++]&0xff;
223 int high = extra >> extraBits;
224 if(ClusterEnum.ForeignShort == p) {
225 oi = lows[1] + (high<<8);
227 pi = lows[0] + (high<<8);
230 extra = Bytes.readLE2(bytes, pos);
232 int high1 = (extra >> extraBits)&((1<<6)-1);
233 int high2 = (extra >> (extraBits+6))&((1<<6)-1);
234 if(ClusterEnum.ForeignShort == p) {
235 oi = lows[1] + (high1<<8);
237 pi = lows[0] + (high1<<8);
238 oi = lows[1] + (high2<<8);
241 ri = ri | ((extra&((1<<extraBits)-1))<<8) | ((op&((1<<opBits)-1))<<(8+extraBits));
246 if(ClusterEnum.ForeignLong == p) {
247 int ref = foreignRefs[0];
248 foreignIndices[ref] = pi;
249 puid = foreignClusters[ref];
251 if(ClusterEnum.ForeignLong == o) {
252 int ref = foreignRefs[1];
253 foreignIndices[ref] = oi;
254 ouid = foreignClusters[ref];
257 if(ClusterEnum.ForeignShort == p) {
258 int ref = foreignRefs[0];
259 pi = foreignIndices[ref];
260 puid = foreignClusters[ref];
262 if(ClusterEnum.ForeignShort == o) {
263 int ref = foreignRefs[1];
264 oi = foreignIndices[ref];
265 ouid = foreignClusters[ref];
269 throw new IllegalStateException();
271 throw new IllegalStateException();
273 throw new IllegalStateException();
275 throw new IllegalStateException();
277 throw new IllegalStateException();
279 throw new IllegalStateException();
281 if(StmEnum.Add == stmEnum) {
284 System.err.println("DEBUG: ClusterChange " + uid + ": Add ri=" + ri + " pi=" + pi + " oi=" + oi + " pc=" + puid + " oc=" + ouid + " offset=" + curPos + " " + p.ordinal + " " + o.ordinal);
286 int predicateKey = getResourceKey(puid, pi);
287 int objectKey = getResourceKey(ouid, oi);
289 claim(clusterKey+ri, predicateKey, objectKey, puid, ouid);
290 } catch (DatabaseException e) {
297 System.err.println("DEBUG: ClusterChange " + uid + ": Rem ri=" + ri + " pi=" + pi + " oi=" + oi + " pc=" + puid + " oc=" + ouid + " offset=" + curPos + " " + p.ordinal + " " + o.ordinal);
299 int predicateKey = getResourceKey(puid, pi);
300 int objectKey = getResourceKey(ouid, oi);
302 deny(clusterKey+ri, predicateKey, objectKey, puid, ouid);
303 } catch (DatabaseException e) {
311 public void process() throws IllegalAcornStateException {
315 if(DEBUG) System.err.println("DEBUG: process " + uid + " " + len);
317 // op resolution for statement operation:
323 // 3 first bits (000)
324 // op: 000000 | r12-13
325 // op: 000001 | r12-13
326 // op: 000010 | r12-13
327 // op: 000011 | r12-13
328 // op: 000100 | r12-13
329 // op: 000101 | r12-13
330 // op: 000110 | r12-13
331 // op: 000111 | r12-13
348 int op = bytes[pos++]&0xff;
350 // common prefix: 0011
354 processStatement(op, StmEnum.Remove, ClusterEnum.Local, ClusterEnum.ForeignShort);
357 processStatement(op, StmEnum.Remove, ClusterEnum.ForeignShort, ClusterEnum.ForeignLong);
360 processStatement(op, StmEnum.Remove, ClusterEnum.ForeignLong, ClusterEnum.ForeignShort);
362 // 52 = 32+16+4 = 00110100
366 // 53 = 32+16+4+1 = 00110101
370 // 54 = 32+16+4+2 = 00110110
374 // 55 = 32+16+4+2+1 = 00110111
380 int bits6 = ((int)op)&0xC0;
384 processStatement(op, StmEnum.Add, ClusterEnum.ForeignShort, ClusterEnum.ForeignShort);
387 processStatement(op, StmEnum.Remove, ClusterEnum.ForeignShort, ClusterEnum.ForeignShort);
391 int bits5 = ((int)op)&0xE0;
394 int bits2 = (((int)op)&0xFC) >> 2;
402 processStatement(op, StmEnum.Add, ClusterEnum.Local, ClusterEnum.Local);
405 processStatement(op, StmEnum.Remove, ClusterEnum.Local, ClusterEnum.Local);
408 processStatement(op, StmEnum.Add, ClusterEnum.Local, ClusterEnum.ForeignLong);
411 processStatement(op, StmEnum.Remove, ClusterEnum.Local, ClusterEnum.ForeignLong);
414 processStatement(op, StmEnum.Add, ClusterEnum.ForeignLong, ClusterEnum.Local);
417 processStatement(op, StmEnum.Remove, ClusterEnum.ForeignLong, ClusterEnum.Local);
420 processStatement(op, StmEnum.Add, ClusterEnum.ForeignLong, ClusterEnum.ForeignLong);
423 processStatement(op, StmEnum.Remove, ClusterEnum.ForeignLong, ClusterEnum.ForeignLong);
431 // 4 low bits of payload
433 int bits4 = (((int)op)&0xF0)>>4;
436 processStatement(op, StmEnum.Add, ClusterEnum.Local, ClusterEnum.ForeignShort);
439 processStatement(op, StmEnum.Add, ClusterEnum.ForeignShort, ClusterEnum.Local);
442 processStatement(op, StmEnum.Add, ClusterEnum.ForeignShort, ClusterEnum.ForeignLong);
445 processStatement(op, StmEnum.Add, ClusterEnum.ForeignLong, ClusterEnum.ForeignShort);
448 processStatement(op, StmEnum.Remove, ClusterEnum.ForeignShort, ClusterEnum.Local);
451 int bits3 = (((int)op)&0xF8)>>3;
468 abstract void create() throws DatabaseException;
469 abstract void delete(int resourceIndex) throws DatabaseException;
470 abstract void modify(int resourceKey, long offset, int size, byte[] bytes, int pos) throws DatabaseException;
471 abstract void set(int resourceKey, byte[] bytes, int length) throws DatabaseException;
473 abstract void claim(int resourceKey, int predicateKey, int objectKey, ClusterUID puid, ClusterUID ouid) throws DatabaseException;
474 abstract void deny(int resourceKey, int predicateKey, int objectKey, ClusterUID puid, ClusterUID ouid) throws DatabaseException;