]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.acorn/src/org/simantics/acorn/internal/ClusterUpdateProcessorBase.java
Merge commit 'b3da313'
[simantics/platform.git] / bundles / org.simantics.acorn / src / org / simantics / acorn / internal / ClusterUpdateProcessorBase.java
1 package org.simantics.acorn.internal;
2
3 import java.util.Arrays;
4 import java.util.HashMap;
5 import java.util.Map;
6
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
16 abstract public class ClusterUpdateProcessorBase {
17         
18         public final static boolean DEBUG = false;
19
20         final protected ClusterManager manager;
21         final public byte[] bytes;
22         private int pos = 0;
23         final private int len;
24         final private ClusterUID uid;
25         final private int clusterKey;
26         final public int version;
27         
28         final Map<ClusterUID, Integer> clusterKeyCache = new HashMap<ClusterUID, Integer>();
29         
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);
35                 return key+index;
36         }
37         
38         
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);
47                 pos = 24;
48                 client.clusterLRU.acquireMutex();
49                 try {
50                         clusterKey = client.clusterLRU.getClusterKeyByUID(cuid1, cuid2) << 12;
51                 } catch (Throwable t) {
52                         throw new IllegalStateException(t);
53                 } finally {
54                         client.clusterLRU.releaseMutex();
55                 }
56         }
57         
58         public ClusterUID getClusterUID() {
59                 return uid;
60         }
61         
62         private void processCreate() {
63                 int r = Bytes.readLE2(bytes, pos);
64                 pos+=2;
65                 if(DEBUG) System.err.println("DEBUG: New ri=" + r + " offset=" + (pos-3-24));
66                 try {
67                         create();
68                 } catch (DatabaseException e) {
69                         e.printStackTrace();
70                 }
71                 
72         }
73         
74         private void processDelete() {
75                 
76                 int ri = Bytes.readLE2(bytes, pos);
77                 pos += 2;
78                 
79                 if(DEBUG) System.err.println("DEBUG: Delete " + ri);
80                 
81                 try {
82                         delete(ri);
83                 } catch (DatabaseException e) {
84                         e.printStackTrace();
85                 }
86                 
87         }
88
89         private void processModify(int op) {
90                 
91                 int ri = Bytes.readLE2(bytes, pos);
92                 pos+=2;
93                 long offset = Bytes.readLE7(bytes, pos);
94                 pos+=7;
95                 int size = Bytes.readLE2(bytes, pos);
96                 pos+=2;
97                 
98                 offset += (ri>>14) << 56;
99                 ri = ri & 0x3FFF;
100                 
101                 if(size < 0)
102                         throw new IllegalStateException();
103                 if(ri < 1)
104                         throw new IllegalStateException();
105                 if(ri > 4095)
106                         throw new IllegalStateException();
107                 
108                 if(DEBUG) System.err.println("DEBUG: Modify " + ri + " " + offset + " " + size + " offset=" + (pos-1-24) + " " + Arrays.toString(Arrays.copyOf(valueBuffer,size)));
109
110                 try {
111                         modify(clusterKey + ri, offset, size, bytes, pos);
112                 } catch (DatabaseException e) {
113                         e.printStackTrace();
114                 }
115
116                 pos += size;
117                 
118         }
119
120         private void processSet(int op) {
121                 
122                 int s = Bytes.readLE4(bytes, pos);
123                 int length = (s >> 14);
124                 if(length < 1)
125                         throw new IllegalStateException();
126                 int r = s & 0x3FFF;
127                 
128                 pos += 4;
129                 System.arraycopy(bytes, pos, valueBuffer, 0, length);
130                 pos += length;
131
132                 if(DEBUG) System.err.println("DEBUG: Set " + r + " " + length + " offset=" + (pos-1-24) + " " + Arrays.toString(Arrays.copyOf(valueBuffer,length)));
133
134                 try {
135                         set(clusterKey+r, valueBuffer, length);
136                 } catch (DatabaseException e) {
137                         e.printStackTrace();
138                 }
139                 
140         }
141
142         byte[] valueBuffer = new byte[65536];
143         
144         private void processSetShort(int op) {
145                 
146                 int s = Bytes.readLE2(bytes, pos);
147                 int length = ((op&7)<<2) + (s >> 14);
148                 if(length < 1)
149                         throw new IllegalStateException();
150                 if(length > 31)
151                         throw new IllegalStateException();
152                 int r = s & 0x3FFF;
153                 
154                 if(DEBUG) System.err.println("DEBUG: SetShort " + r + " " + length + " offset=" + (pos-1-24) + " " + Arrays.toString(Arrays.copyOf(valueBuffer,length)));
155                 pos += 2;
156
157                 System.arraycopy(bytes, pos, valueBuffer, 0, length);
158                 pos += length;
159                 
160                 try {
161                         set(clusterKey+r, valueBuffer, length);
162                 } catch (DatabaseException e) {
163                         e.printStackTrace();
164                 }
165                 
166         }
167
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;
174                         lows[pOrO] = lo;
175                 } else {
176                         long l1 = Bytes.readLE8(bytes, pos);
177                         pos += 8;
178                         long l2 = Bytes.readLE8(bytes, pos);
179                         pos += 8;
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;
185                         foreignPos++;
186                         lows[pOrO] = lo;
187                 }
188         }
189         
190         ClusterUID[] foreignClusters = new ClusterUID[256];
191         int[] foreignIndices = new int[256];
192         int foreignPos = 0;
193         int lows[] = new int[2];
194         int foreignRefs[] = new int[2];
195         
196         private void processStatement(int op, StmEnum stmEnum, ClusterEnum p, ClusterEnum o) throws IllegalAcornStateException {
197
198                 int curPos = pos-1-24;
199                 
200                 processStatementResource(p, 0);
201                 processStatementResource(o, 1);
202
203                 int ri = bytes[pos++]&0xff;
204                 int pi = 0;
205                 int oi = 0;
206                 
207                 ClusterUID puid = uid;
208                 ClusterUID ouid = puid;
209                 
210                 if(ClusterEnum.ForeignShort == p && ClusterEnum.ForeignShort == o) {
211                         ri |= (op&0x3F) << 8;
212                 } else {
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); 
217                         } else {
218                                 int extra = 0;
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);
226                                         } else {
227                                                 pi = lows[0] + (high<<8);
228                                         }
229                                 } else {
230                                         extra = Bytes.readLE2(bytes, pos);
231                                         pos += 2;
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);
236                                         } else {
237                                                 pi = lows[0] + (high1<<8);
238                                                 oi = lows[1] + (high2<<8);
239                                         }
240                                 }
241                                 ri = ri | ((extra&((1<<extraBits)-1))<<8) | ((op&((1<<opBits)-1))<<(8+extraBits)); 
242                         }
243                 }
244
245                 // Set foreigns
246                 if(ClusterEnum.ForeignLong == p) {
247                         int ref = foreignRefs[0];
248                         foreignIndices[ref] = pi;
249                         puid = foreignClusters[ref];
250                 }
251                 if(ClusterEnum.ForeignLong == o) {
252                         int ref = foreignRefs[1];
253                         foreignIndices[ref] = oi;
254                         ouid = foreignClusters[ref]; 
255                 }
256                 // Get foreigns
257                 if(ClusterEnum.ForeignShort == p) {
258                         int ref = foreignRefs[0];
259                         pi = foreignIndices[ref];
260                         puid = foreignClusters[ref]; 
261                 }
262                 if(ClusterEnum.ForeignShort == o) {
263                         int ref = foreignRefs[1];
264                         oi = foreignIndices[ref];
265                         ouid = foreignClusters[ref]; 
266                 }
267
268                 if(ri < 1)
269                         throw new IllegalStateException();
270                 if(pi < 1)
271                         throw new IllegalStateException();
272                 if(oi < 1)
273                         throw new IllegalStateException();
274                 if(ri > 4095)
275                         throw new IllegalStateException();
276                 if(pi > 4095)
277                         throw new IllegalStateException();
278                 if(oi > 4095)
279                         throw new IllegalStateException();
280
281                 if(StmEnum.Add == stmEnum) {
282                         
283                         if(DEBUG)
284                 System.err.println("DEBUG: ClusterChange " + uid + ": Add ri=" + ri + " pi=" + pi + " oi=" + oi + " pc=" + puid + " oc=" + ouid + " offset=" + curPos + " " + p.ordinal + " " + o.ordinal);
285             
286                         int predicateKey = getResourceKey(puid, pi);
287                         int objectKey = getResourceKey(ouid, oi);       
288                         try {
289                                 claim(clusterKey+ri, predicateKey, objectKey, puid, ouid);
290                         } catch (DatabaseException e) {
291                                 e.printStackTrace();
292                         }
293                         
294                 } else {
295                         
296                         if(DEBUG)
297                 System.err.println("DEBUG: ClusterChange " + uid + ": Rem ri=" + ri + " pi=" + pi + " oi=" + oi + " pc=" + puid + " oc=" + ouid + " offset=" + curPos + " " + p.ordinal + " " + o.ordinal);
298             
299                         int predicateKey = getResourceKey(puid, pi);
300                         int objectKey = getResourceKey(ouid, oi);
301                         try {
302                                 deny(clusterKey+ri, predicateKey, objectKey, puid, ouid);
303                         } catch (DatabaseException e) {
304                                 e.printStackTrace();
305                         }
306                         
307                 }
308                 
309         }
310
311         public void process() throws IllegalAcornStateException {
312                 
313                 foreignPos = 0;
314
315                 if(DEBUG) System.err.println("DEBUG: process " + uid + " " + len);
316                 
317                 // op resolution for statement operation:
318                 
319                 // 2 first bits
320                 // op: 01 | r8-13
321                 // op: 10 | r8-13
322
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 
332
333                 // 4 first bits
334                 // op: 1100 | r10-13
335                 // op: 1101 | r10-13 
336                 // op: 1110 | r10-13 
337                 // op: 1111 | r10-13
338                 // op: 0010 | r10-13
339                 
340                 // 6 bits
341                 // op: 00110001 = 49
342                 // op: 00110010 = 50
343                 // op: 00110011 = 51
344                 // other: 0011xxxx
345                 
346                 while(pos < len) {
347                 
348                         int op = bytes[pos++]&0xff;
349                         
350                         // common prefix: 0011
351                         switch(op) {
352                         
353                         case 49:
354                                 processStatement(op, StmEnum.Remove, ClusterEnum.Local, ClusterEnum.ForeignShort);
355                                 break;
356                         case 50:
357                                 processStatement(op, StmEnum.Remove, ClusterEnum.ForeignShort, ClusterEnum.ForeignLong);
358                                 break;
359                         case 51:
360                                 processStatement(op, StmEnum.Remove, ClusterEnum.ForeignLong, ClusterEnum.ForeignShort);
361                                 break;
362                         // 52 = 32+16+4 = 00110100
363                         case 52:
364                                 processCreate();
365                                 break;
366                         // 53 = 32+16+4+1 = 00110101
367                         case 53:
368                                 processSet(op);
369                                 break;
370                         // 54 = 32+16+4+2 = 00110110
371                         case 54:
372                                 processDelete();
373                                 break;
374                         // 55 = 32+16+4+2+1 = 00110111
375                         case 55:
376                                 processModify(op);
377                                 break;
378                         default:
379                                 
380                                 int bits6 = ((int)op)&0xC0;
381                                 switch(bits6) {
382                                 
383                                 case 0x40:
384                                         processStatement(op, StmEnum.Add, ClusterEnum.ForeignShort, ClusterEnum.ForeignShort);
385                                         break;
386                                 case 0x80:
387                                         processStatement(op, StmEnum.Remove, ClusterEnum.ForeignShort, ClusterEnum.ForeignShort);
388                                         break;
389                                 default:
390
391                                         int bits5 = ((int)op)&0xE0;
392                                         if(bits5 == 0) {
393
394                                                 int bits2 = (((int)op)&0xFC) >> 2;      
395                                                 
396                                                 // 3 top bits are 0
397                                                 // 6 bits of op
398                                                 
399                                                 switch(bits2) {
400
401                                                 case 0:
402                                                         processStatement(op, StmEnum.Add, ClusterEnum.Local, ClusterEnum.Local);
403                                                         break;
404                                                 case 1:
405                                                         processStatement(op, StmEnum.Remove, ClusterEnum.Local, ClusterEnum.Local);
406                                                         break;
407                                                 case 2:
408                                                         processStatement(op, StmEnum.Add, ClusterEnum.Local, ClusterEnum.ForeignLong);
409                                                         break;
410                                                 case 3:
411                                                         processStatement(op, StmEnum.Remove, ClusterEnum.Local, ClusterEnum.ForeignLong);
412                                                         break;
413                                                 case 4:
414                                                         processStatement(op, StmEnum.Add, ClusterEnum.ForeignLong, ClusterEnum.Local);
415                                                         break;
416                                                 case 5:
417                                                         processStatement(op, StmEnum.Remove, ClusterEnum.ForeignLong, ClusterEnum.Local);
418                                                         break;
419                                                 case 6:
420                                                         processStatement(op, StmEnum.Add, ClusterEnum.ForeignLong, ClusterEnum.ForeignLong);
421                                                         break;
422                                                 case 7:
423                                                         processStatement(op, StmEnum.Remove, ClusterEnum.ForeignLong, ClusterEnum.ForeignLong);
424                                                         break;
425                                                 
426                                                 }
427
428                                         } else {
429
430                                                 // 4 top bits of op
431                                                 // 4 low bits of payload
432
433                                                 int bits4 = (((int)op)&0xF0)>>4;
434                                                 switch(bits4) {
435                                                 case 0b1100:
436                                                         processStatement(op, StmEnum.Add, ClusterEnum.Local, ClusterEnum.ForeignShort);
437                                                         break;
438                                                 case 0b1101:
439                                                         processStatement(op, StmEnum.Add, ClusterEnum.ForeignShort, ClusterEnum.Local);
440                                                         break;
441                                                 case 0b1110:
442                                                         processStatement(op, StmEnum.Add, ClusterEnum.ForeignShort, ClusterEnum.ForeignLong);
443                                                         break;
444                                                 case 0b1111:
445                                                         processStatement(op, StmEnum.Add, ClusterEnum.ForeignLong, ClusterEnum.ForeignShort);
446                                                         break;
447                                                 case 0b0010:
448                                                         processStatement(op, StmEnum.Remove, ClusterEnum.ForeignShort, ClusterEnum.Local);
449                                                         break;
450                                                 case 0b0011:
451                                                         int bits3 = (((int)op)&0xF8)>>3;
452                                                         if(bits3 == 7)
453                                                                 processSetShort(op);
454                                                         break;
455                                                 }
456
457                                         }
458                                 
459                                 }
460                                 
461                         }
462                         
463                 }
464                 
465         }
466         
467         
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;
472         
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;
475         
476 }