]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.datatypes/src/org/simantics/datatypes/utils/LogUtils.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.datatypes / src / org / simantics / datatypes / utils / LogUtils.java
1 package org.simantics.datatypes.utils;\r
2 \r
3 import gnu.trove.map.hash.TObjectIntHashMap;\r
4 \r
5 import java.io.DataInput;\r
6 import java.io.DataOutput;\r
7 import java.io.IOException;\r
8 import java.util.Collection;\r
9 import java.util.HashMap;\r
10 import java.util.IdentityHashMap;\r
11 import java.util.List;\r
12 import java.util.Map;\r
13 import java.util.Set;\r
14 \r
15 import org.simantics.databoard.Bindings;\r
16 import org.simantics.databoard.accessor.reference.ChildReference;\r
17 import org.simantics.databoard.binding.Binding;\r
18 import org.simantics.databoard.binding.error.BindingException;\r
19 import org.simantics.databoard.binding.error.RuntimeBindingConstructionException;\r
20 import org.simantics.databoard.binding.impl.BindingPrintContext;\r
21 import org.simantics.databoard.serialization.RuntimeSerializerConstructionException;\r
22 import org.simantics.databoard.serialization.Serializer;\r
23 import org.simantics.databoard.util.IdentityPair;\r
24 import org.simantics.datatypes.DatatypeResource;\r
25 import org.simantics.db.ReadGraph;\r
26 import org.simantics.db.Resource;\r
27 import org.simantics.db.WriteGraph;\r
28 import org.simantics.db.common.primitiverequest.RelatedValue;\r
29 import org.simantics.db.common.procedure.adapter.TransientCacheListener;\r
30 import org.simantics.db.common.utils.Logger;\r
31 import org.simantics.db.exception.DatabaseException;\r
32 import org.simantics.db.service.Bytes;\r
33 import org.simantics.db.service.SerialisationSupport;\r
34 import org.simantics.layer0.Layer0;\r
35 import org.simantics.utils.datastructures.Pair;\r
36 \r
37 interface LogContentManager {\r
38         \r
39         LogContentBean getContentBean(ReadGraph graph, Resource node) throws DatabaseException;\r
40         void setContentBean(WriteGraph graph, Resource node, LogContentBean bean) throws DatabaseException;\r
41         \r
42 }\r
43 \r
44 class LogContentBinding extends Binding {\r
45 \r
46         private final SerialisationSupport ss;\r
47         \r
48         public LogContentBinding(SerialisationSupport ss) {\r
49                 this.ss = ss;\r
50         }\r
51         \r
52         private final Serializer serializer = new Serializer() {\r
53 \r
54                 @Override\r
55                 public void serialize(DataOutput out, TObjectIntHashMap<Object> identities, Object obj) throws IOException {\r
56                         throw new UnsupportedOperationException();\r
57                 }\r
58 \r
59                 @Override\r
60                 public void serialize(DataOutput out, Object obj) throws IOException {\r
61                         throw new UnsupportedOperationException();\r
62                 }\r
63 \r
64                 @Override\r
65                 public Object deserialize(DataInput in, List<Object> identities)\r
66                                 throws IOException {\r
67                         throw new UnsupportedOperationException();\r
68                 }\r
69 \r
70                 @Override\r
71                 public Object deserialize(DataInput in) throws IOException {\r
72                         throw new UnsupportedOperationException();\r
73                 }\r
74 \r
75                 @Override\r
76                 public void deserializeTo(DataInput in, List<Object> identities,\r
77                                 Object dst) throws IOException {\r
78                         throw new UnsupportedOperationException();\r
79                 }\r
80 \r
81                 @Override\r
82                 public void deserializeTo(DataInput in, Object dst) throws IOException {\r
83                         throw new UnsupportedOperationException();\r
84                 }\r
85 \r
86                 @Override\r
87                 public void skip(DataInput in, List<Object> identities)\r
88                                 throws IOException {\r
89                         throw new UnsupportedOperationException();\r
90                 }\r
91 \r
92                 @Override\r
93                 public void skip(DataInput in) throws IOException {\r
94                         throw new UnsupportedOperationException();\r
95                 }\r
96 \r
97                 @Override\r
98                 public Integer getConstantSize() {\r
99                         throw new UnsupportedOperationException();\r
100                 }\r
101 \r
102                 @Override\r
103                 public int getSize(Object obj, TObjectIntHashMap<Object> identities)\r
104                                 throws IOException {\r
105                         throw new UnsupportedOperationException();\r
106                 }\r
107 \r
108                 @Override\r
109                 public int getSize(Object obj) throws IOException {\r
110                         throw new UnsupportedOperationException();\r
111                 }\r
112 \r
113                 @Override\r
114                 public int getMinSize() {\r
115                         throw new UnsupportedOperationException();\r
116                 }\r
117                 \r
118                 public byte[] serialize(Object obj) throws IOException {\r
119                         LogContentBean bean = (LogContentBean)obj;\r
120                         int bytes = 1 + 4 + 4 + 8 * bean.stamps.length + 8 * bean.resources.length;\r
121                         byte[] result = new byte[bytes];\r
122                         Bytes.write(result, 0, bean.leaf ? (byte)1 : (byte)0);\r
123                         int byteIndex = 1;\r
124                         Bytes.writeLE(result, byteIndex, bean.n);\r
125                         byteIndex += 4;\r
126                         Bytes.writeLE(result, byteIndex, bean.stamps.length);\r
127                         byteIndex += 4;\r
128                         for(long l : bean.stamps) {\r
129                                 Bytes.writeLE(result, byteIndex, l);\r
130                                 byteIndex += 8;\r
131                         }\r
132                         for(PossibleResource pr : bean.resources) {\r
133                                 Bytes.writeLE(result, byteIndex, pr.longValue());\r
134                                 byteIndex += 8;\r
135                         }\r
136                         return result;\r
137                 }\r
138                 \r
139                 public Object deserialize(byte[] data) throws IOException {\r
140                         \r
141                         LogContentBean result = new LogContentBean();\r
142 \r
143                         try {\r
144                         \r
145                                 result.leaf = Bytes.read(data, 0) == 1 ? true : false;\r
146                                 int byteIndex = 1;\r
147                                 result.n = Bytes.readLE4(data, byteIndex);\r
148                                 byteIndex += 4;\r
149                                 int t =  Bytes.readLE4(data, byteIndex);\r
150                                 byteIndex += 4;\r
151                                 \r
152                                 result.stamps = new long[t];\r
153                                 result.resources = new PossibleResource[t];\r
154                                 \r
155                                 for(int i=0;i<t;i++) {\r
156                                         result.stamps[i] = Bytes.readLE8(data, byteIndex);\r
157                                         byteIndex += 8;\r
158                                 }\r
159                                 \r
160                                 for(int i=0;i<t;i++) {\r
161                                         result.resources[i] = PossibleResource.read(ss, Bytes.readLE8(data, byteIndex));\r
162                                         byteIndex += 8;\r
163                                 }\r
164         \r
165                         } catch (DatabaseException e) {\r
166                         \r
167                                 e.printStackTrace();\r
168                                 \r
169                         }\r
170                         \r
171                         return result;\r
172                         \r
173                 }\r
174                 \r
175         };\r
176         \r
177         @Override\r
178         public void accept(Visitor1 v, Object obj) {\r
179                 throw new UnsupportedOperationException();\r
180         }\r
181 \r
182         @Override\r
183         public <T> T accept(Visitor<T> v) {\r
184                 throw new UnsupportedOperationException();\r
185         }\r
186 \r
187         @Override\r
188         public boolean isInstance(Object obj) {\r
189                 throw new UnsupportedOperationException();\r
190         }\r
191 \r
192         @Override\r
193         public void readFrom(Binding srcBinding, Object src, Object dst)\r
194                         throws BindingException {\r
195                 throw new UnsupportedOperationException();\r
196         }\r
197 \r
198         @Override\r
199         public void assertInstaceIsValid(Object obj, Set<Object> validInstances)\r
200                         throws BindingException {\r
201                 throw new UnsupportedOperationException();\r
202         }\r
203 \r
204         @Override\r
205         public int deepHashValue(Object value,\r
206                         IdentityHashMap<Object, Object> hashedObjects)\r
207                         throws BindingException {\r
208                 throw new UnsupportedOperationException();\r
209         }\r
210 \r
211         @Override\r
212         public int deepCompare(Object o1, Object o2,\r
213                         Set<IdentityPair<Object, Object>> compareHistory)\r
214                         throws BindingException {\r
215                 throw new UnsupportedOperationException();\r
216         }\r
217 \r
218         @Override\r
219         protected void toString(Object value, BindingPrintContext ctx)\r
220                         throws BindingException {\r
221                 throw new UnsupportedOperationException();\r
222         }\r
223 \r
224         @Override\r
225         public int getComponentCount() {\r
226                 throw new UnsupportedOperationException();\r
227         }\r
228 \r
229         @Override\r
230         public Binding getComponentBinding(int index) {\r
231                 throw new UnsupportedOperationException();\r
232         }\r
233 \r
234         @Override\r
235         public Binding getComponentBinding(ChildReference path) {\r
236                 throw new UnsupportedOperationException();\r
237         }\r
238         \r
239         @Override\r
240         public Serializer serializer() throws RuntimeSerializerConstructionException {\r
241                 return serializer;\r
242         }\r
243         \r
244 }\r
245 \r
246 final public class LogUtils implements LogContentManager {\r
247 \r
248         final public static boolean DEBUG = false;\r
249         \r
250         final public Binding CONTENT_BEAN_BINDING;\r
251         final public DatatypeResource DATA;\r
252         \r
253         public LogUtils(ReadGraph graph) throws DatabaseException {\r
254                 try {\r
255                         CONTENT_BEAN_BINDING = new LogContentBinding(graph.getService(SerialisationSupport.class));\r
256                         DATA = DatatypeResource.getInstance(graph);\r
257                 } catch (RuntimeBindingConstructionException e) {\r
258                         Logger.defaultLogError(e);\r
259                         throw new DatabaseException(e);\r
260                 }\r
261         }\r
262         \r
263         public Resource create(WriteGraph graph, int t, int stamp) throws DatabaseException {\r
264                 Layer0 L0 = Layer0.getInstance(graph);\r
265                 Resource tree = graph.newResource();\r
266                 graph.claim(tree, L0.InstanceOf, null, DATA.Log);\r
267                 Resource index = createIndexNode(graph, this, stamp, t); \r
268                 graph.claim(tree, DATA.Log_root, DATA.Log_root_Inverse, index);\r
269                 graph.claimLiteral(tree, DATA.Log_t, t, Bindings.INTEGER);\r
270                 Resource leaf = createLeafNode(graph, this, stamp, t);\r
271                 graph.claim(index, DATA.BTreeNode_Content, null, leaf);\r
272                 LogContentBean rContent = getContentBean(graph, index);\r
273                 rContent.n = 1;\r
274                 rContent.stamps[0] = stamp;\r
275                 rContent.resources[0].r = leaf;\r
276                 setContentBean(graph, index, rContent);\r
277                 return tree;\r
278         }\r
279 \r
280         public void insert(WriteGraph graph, Resource T, int stamp, Resource v) throws DatabaseException {\r
281 \r
282                 Resource r = getRoot(graph, T);\r
283                 int t = getDegree(graph, T);\r
284                 insertImpl(graph, this, T, r, t, stamp, v);\r
285                 \r
286         }\r
287 \r
288         static class BatchContentManager implements LogContentManager {\r
289 \r
290                 final private LogUtils bu;\r
291                 \r
292                 final Map<Resource, LogContentBean> beans = new HashMap<Resource, LogContentBean>();\r
293                 \r
294                 public BatchContentManager(LogUtils bu) {\r
295                         this.bu = bu;\r
296                 }\r
297                 \r
298                 @Override\r
299                 public LogContentBean getContentBean(ReadGraph graph, Resource node) throws DatabaseException {\r
300                         LogContentBean bean = beans.get(node);\r
301                         if(bean != null) return bean;\r
302                         return bu.getContentBean(graph, node);\r
303                 }\r
304 \r
305                 @Override\r
306                 public void setContentBean(WriteGraph graph, Resource node, LogContentBean bean) throws DatabaseException {\r
307                         beans.put(node, bean);\r
308                 }\r
309                 \r
310                 public void apply(WriteGraph graph) throws DatabaseException {\r
311                         for(Map.Entry<Resource, LogContentBean> entry : beans.entrySet()) {\r
312                                 bu.setContentBean(graph, entry.getKey(), entry.getValue());\r
313                         }\r
314                 }\r
315                 \r
316         }\r
317         \r
318         public void insertAll(WriteGraph graph, Resource T, Collection<Pair<Integer, Resource>> values) throws DatabaseException {\r
319 \r
320                 Resource r = getRoot(graph, T);\r
321                 int t = getDegree(graph, T);\r
322                 BatchContentManager cm = new BatchContentManager(this);\r
323                 for(Pair<Integer, Resource> entry : values) {\r
324                         insertImpl(graph, cm, T, r, t, entry.first, entry.second);\r
325                 }\r
326                 cm.apply(graph);\r
327                 \r
328         }\r
329         \r
330         // Implementation\r
331         private void insertImpl(WriteGraph graph, LogContentManager manager, Resource T, Resource r, int t, int k, Resource v) throws DatabaseException {\r
332                 \r
333                 int code = insertImpl2(graph, manager, 0, T, r, t, k, v); \r
334                 \r
335                 if(code > 0) {\r
336                         \r
337                         LogContentBean rContent = manager.getContentBean(graph, r);\r
338                         \r
339                         if(DEBUG) System.err.println("[insert index code=" + code + "]");\r
340 \r
341                         Resource newRoot = createIndexNode(graph, manager, k, t);\r
342                         graph.claim(newRoot, DATA.Log_Node_Contains, null, r);\r
343                         setRoot(graph, T, newRoot);\r
344                         \r
345                         LogContentBean nContent = manager.getContentBean(graph, newRoot);\r
346                         nContent.stamps[0] = rContent.stamps[0];\r
347                         nContent.resources[0].r = r;\r
348                         nContent.n = 1;\r
349                         manager.setContentBean(graph, newRoot, nContent);\r
350 \r
351                         Resource leaf = createLeaf(graph, manager, newRoot, code, k, t);\r
352                         \r
353                         LogContentBean lContent = manager.getContentBean(graph, leaf);\r
354                         lContent.n = 1;\r
355                         lContent.stamps[0] = k;\r
356                         lContent.resources[0].r = v;\r
357 \r
358                         if(DEBUG) System.err.println("[insert " + k + "]: started a new branch");\r
359 \r
360                         manager.setContentBean(graph, leaf, lContent);\r
361 \r
362                 }\r
363                 \r
364         }\r
365 \r
366         private int insertImpl2(WriteGraph graph, LogContentManager manager, int level, Resource T, Resource r, int t, int k, Resource v) throws DatabaseException {\r
367 \r
368                 LogContentBean rContent = manager.getContentBean(graph, r);\r
369 \r
370                 // Index\r
371                 if(!rContent.leaf) {\r
372                         \r
373                         Resource child = rContent.resources[rContent.n-1].r;\r
374                         int code = insertImpl2(graph, manager, level+1, T, child, t, k, v); \r
375                         \r
376                         if(code == 0) {\r
377                                 \r
378                                 // Value was inserted successfully\r
379                                 return 0;\r
380                                 \r
381                         } else {\r
382 \r
383                                 // The child was full\r
384                                 if(rContent.n < t) {\r
385                                         \r
386                                         // We can create a new child\r
387                                         Resource leaf = createLeaf(graph, manager, r, code-level-1, k, t);\r
388                                         LogContentBean lContent = manager.getContentBean(graph, leaf);\r
389                                         lContent.stamps[0] = k;\r
390                                         lContent.resources[0].r = v;\r
391                                         lContent.n = 1;\r
392                                         manager.setContentBean(graph, leaf, lContent);\r
393                                         \r
394                                         if(DEBUG) System.err.println("[insert " + k + "]: created a fresh leaf");\r
395                                         \r
396                                         return 0;\r
397                                         \r
398                                 } else {\r
399 \r
400                                         // We are full, let the parent handle this\r
401                                         return code;\r
402                                         \r
403                                 }\r
404                                 \r
405                                 \r
406                         }\r
407                         \r
408                 }\r
409                 \r
410                 // Leaf\r
411                 else {\r
412 \r
413                         if(rContent.n < t) {\r
414                                 \r
415                                 if(DEBUG) System.err.println("[insert " + k + "]: fit into leaf at level " + level);\r
416                                 \r
417                                 // Append\r
418                                 rContent.stamps[rContent.n] = k;\r
419                                 rContent.resources[rContent.n].r = v;\r
420                                 rContent.n++;\r
421                                 manager.setContentBean(graph, r, rContent);\r
422                                 return 0;\r
423                                 \r
424                         } else {\r
425 \r
426                                 // This leaf is full\r
427                                 return level;\r
428                                 \r
429                         }\r
430                         \r
431                 }\r
432                 \r
433         }\r
434         \r
435         private Resource createLeaf(WriteGraph graph, LogContentManager manager, Resource r, int code, int stamp, int t) throws DatabaseException {\r
436                 LogContentBean rContent = manager.getContentBean(graph, r);\r
437                 if(code == 0) {\r
438                         if(DEBUG) System.err.println("[insert leaf code=" + code + "]");\r
439                         Resource result = createLeafNode(graph, manager, stamp, t);\r
440                         graph.claim(r, DATA.Log_Node_Contains, null, result);\r
441                         rContent.stamps[rContent.n] = stamp;\r
442                         rContent.resources[rContent.n].r = result;\r
443                         rContent.n++;\r
444                         manager.setContentBean(graph, r, rContent);\r
445                         return result;\r
446                 } else {\r
447                         if(DEBUG) System.err.println("[insert index code=" + code + "]");\r
448                         Resource index = createIndexNode(graph, manager, stamp, t);\r
449                         graph.claim(r, DATA.Log_Node_Contains, null, index);\r
450                         rContent.stamps[rContent.n] = stamp;\r
451                         rContent.resources[rContent.n].r = index;\r
452                         rContent.n++;\r
453                         manager.setContentBean(graph, r, rContent);\r
454                         return createLeaf(graph, manager, index, code-1, stamp, t);\r
455                 }\r
456         }\r
457         \r
458         private Resource createIndexNode(WriteGraph graph, LogContentManager manager, int stamp, int t) throws DatabaseException {\r
459                 Layer0 L0 = Layer0.getInstance(graph);\r
460                 Resource result = graph.newResource();\r
461                 graph.claim(result, L0.InstanceOf, null, DATA.Log_IndexNode);\r
462                 manager.setContentBean(graph, result, LogContentBean.create(t, stamp, false));\r
463                 return result;\r
464         }\r
465 \r
466         private Resource createLeafNode(WriteGraph graph, LogContentManager manager, int stamp, int t) throws DatabaseException {\r
467                 Layer0 L0 = Layer0.getInstance(graph);\r
468                 Resource result = graph.newResource();\r
469                 graph.claim(result, L0.InstanceOf, null, DATA.Log_LeafNode);\r
470                 manager.setContentBean(graph, result, LogContentBean.create(t, stamp, true));\r
471                 return result;\r
472         }\r
473         \r
474         private Resource getRoot(ReadGraph graph, Resource T) throws DatabaseException {\r
475                 return graph.getPossibleObject(T, DATA.Log_root);\r
476         }\r
477         \r
478         private void setRoot(WriteGraph graph, Resource T, Resource r) throws DatabaseException {\r
479                 graph.deny(T, DATA.Log_root);\r
480                 graph.claim(T, DATA.Log_root, r);\r
481         }\r
482         \r
483         public void setContentBean(WriteGraph graph, Resource node, LogContentBean bean) throws DatabaseException {\r
484                 graph.claimLiteral(node, DATA.Log_Node_content, DATA.Log_Content, bean, CONTENT_BEAN_BINDING );\r
485         }\r
486 \r
487         private int getDegree(ReadGraph graph, Resource tree) throws DatabaseException {\r
488                 return graph.syncRequest(new RelatedValue<Integer>(tree, DATA.Log_t, Bindings.INTEGER), TransientCacheListener.<Integer>instance());\r
489         }\r
490         \r
491         public LogContentBean getContentBean(ReadGraph graph, Resource node) throws DatabaseException {\r
492                 return graph.syncRequest(new RelatedValue<LogContentBean>(node, DATA.Log_Node_content, CONTENT_BEAN_BINDING), TransientCacheListener.<LogContentBean>instance());\r
493         }\r
494         \r
495 }\r