]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - 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
diff --git a/bundles/org.simantics.datatypes/src/org/simantics/datatypes/utils/LogUtils.java b/bundles/org.simantics.datatypes/src/org/simantics/datatypes/utils/LogUtils.java
new file mode 100644 (file)
index 0000000..3950518
--- /dev/null
@@ -0,0 +1,495 @@
+package org.simantics.datatypes.utils;\r
+\r
+import gnu.trove.map.hash.TObjectIntHashMap;\r
+\r
+import java.io.DataInput;\r
+import java.io.DataOutput;\r
+import java.io.IOException;\r
+import java.util.Collection;\r
+import java.util.HashMap;\r
+import java.util.IdentityHashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Set;\r
+\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.accessor.reference.ChildReference;\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.binding.error.BindingException;\r
+import org.simantics.databoard.binding.error.RuntimeBindingConstructionException;\r
+import org.simantics.databoard.binding.impl.BindingPrintContext;\r
+import org.simantics.databoard.serialization.RuntimeSerializerConstructionException;\r
+import org.simantics.databoard.serialization.Serializer;\r
+import org.simantics.databoard.util.IdentityPair;\r
+import org.simantics.datatypes.DatatypeResource;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.primitiverequest.RelatedValue;\r
+import org.simantics.db.common.procedure.adapter.TransientCacheListener;\r
+import org.simantics.db.common.utils.Logger;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.service.Bytes;\r
+import org.simantics.db.service.SerialisationSupport;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.utils.datastructures.Pair;\r
+\r
+interface LogContentManager {\r
+       \r
+       LogContentBean getContentBean(ReadGraph graph, Resource node) throws DatabaseException;\r
+       void setContentBean(WriteGraph graph, Resource node, LogContentBean bean) throws DatabaseException;\r
+       \r
+}\r
+\r
+class LogContentBinding extends Binding {\r
+\r
+       private final SerialisationSupport ss;\r
+       \r
+       public LogContentBinding(SerialisationSupport ss) {\r
+               this.ss = ss;\r
+       }\r
+       \r
+       private final Serializer serializer = new Serializer() {\r
+\r
+               @Override\r
+               public void serialize(DataOutput out, TObjectIntHashMap<Object> identities, Object obj) throws IOException {\r
+                       throw new UnsupportedOperationException();\r
+               }\r
+\r
+               @Override\r
+               public void serialize(DataOutput out, Object obj) throws IOException {\r
+                       throw new UnsupportedOperationException();\r
+               }\r
+\r
+               @Override\r
+               public Object deserialize(DataInput in, List<Object> identities)\r
+                               throws IOException {\r
+                       throw new UnsupportedOperationException();\r
+               }\r
+\r
+               @Override\r
+               public Object deserialize(DataInput in) throws IOException {\r
+                       throw new UnsupportedOperationException();\r
+               }\r
+\r
+               @Override\r
+               public void deserializeTo(DataInput in, List<Object> identities,\r
+                               Object dst) throws IOException {\r
+                       throw new UnsupportedOperationException();\r
+               }\r
+\r
+               @Override\r
+               public void deserializeTo(DataInput in, Object dst) throws IOException {\r
+                       throw new UnsupportedOperationException();\r
+               }\r
+\r
+               @Override\r
+               public void skip(DataInput in, List<Object> identities)\r
+                               throws IOException {\r
+                       throw new UnsupportedOperationException();\r
+               }\r
+\r
+               @Override\r
+               public void skip(DataInput in) throws IOException {\r
+                       throw new UnsupportedOperationException();\r
+               }\r
+\r
+               @Override\r
+               public Integer getConstantSize() {\r
+                       throw new UnsupportedOperationException();\r
+               }\r
+\r
+               @Override\r
+               public int getSize(Object obj, TObjectIntHashMap<Object> identities)\r
+                               throws IOException {\r
+                       throw new UnsupportedOperationException();\r
+               }\r
+\r
+               @Override\r
+               public int getSize(Object obj) throws IOException {\r
+                       throw new UnsupportedOperationException();\r
+               }\r
+\r
+               @Override\r
+               public int getMinSize() {\r
+                       throw new UnsupportedOperationException();\r
+               }\r
+               \r
+               public byte[] serialize(Object obj) throws IOException {\r
+                       LogContentBean bean = (LogContentBean)obj;\r
+                       int bytes = 1 + 4 + 4 + 8 * bean.stamps.length + 8 * bean.resources.length;\r
+                       byte[] result = new byte[bytes];\r
+                       Bytes.write(result, 0, bean.leaf ? (byte)1 : (byte)0);\r
+                       int byteIndex = 1;\r
+                       Bytes.writeLE(result, byteIndex, bean.n);\r
+                       byteIndex += 4;\r
+                       Bytes.writeLE(result, byteIndex, bean.stamps.length);\r
+                       byteIndex += 4;\r
+                       for(long l : bean.stamps) {\r
+                               Bytes.writeLE(result, byteIndex, l);\r
+                               byteIndex += 8;\r
+                       }\r
+                       for(PossibleResource pr : bean.resources) {\r
+                               Bytes.writeLE(result, byteIndex, pr.longValue());\r
+                               byteIndex += 8;\r
+                       }\r
+                       return result;\r
+               }\r
+               \r
+               public Object deserialize(byte[] data) throws IOException {\r
+                       \r
+                       LogContentBean result = new LogContentBean();\r
+\r
+                       try {\r
+                       \r
+                               result.leaf = Bytes.read(data, 0) == 1 ? true : false;\r
+                               int byteIndex = 1;\r
+                               result.n = Bytes.readLE4(data, byteIndex);\r
+                               byteIndex += 4;\r
+                               int t =  Bytes.readLE4(data, byteIndex);\r
+                               byteIndex += 4;\r
+                               \r
+                               result.stamps = new long[t];\r
+                               result.resources = new PossibleResource[t];\r
+                               \r
+                               for(int i=0;i<t;i++) {\r
+                                       result.stamps[i] = Bytes.readLE8(data, byteIndex);\r
+                                       byteIndex += 8;\r
+                               }\r
+                               \r
+                               for(int i=0;i<t;i++) {\r
+                                       result.resources[i] = PossibleResource.read(ss, Bytes.readLE8(data, byteIndex));\r
+                                       byteIndex += 8;\r
+                               }\r
+       \r
+                       } catch (DatabaseException e) {\r
+                       \r
+                               e.printStackTrace();\r
+                               \r
+                       }\r
+                       \r
+                       return result;\r
+                       \r
+               }\r
+               \r
+       };\r
+       \r
+       @Override\r
+       public void accept(Visitor1 v, Object obj) {\r
+               throw new UnsupportedOperationException();\r
+       }\r
+\r
+       @Override\r
+       public <T> T accept(Visitor<T> v) {\r
+               throw new UnsupportedOperationException();\r
+       }\r
+\r
+       @Override\r
+       public boolean isInstance(Object obj) {\r
+               throw new UnsupportedOperationException();\r
+       }\r
+\r
+       @Override\r
+       public void readFrom(Binding srcBinding, Object src, Object dst)\r
+                       throws BindingException {\r
+               throw new UnsupportedOperationException();\r
+       }\r
+\r
+       @Override\r
+       public void assertInstaceIsValid(Object obj, Set<Object> validInstances)\r
+                       throws BindingException {\r
+               throw new UnsupportedOperationException();\r
+       }\r
+\r
+       @Override\r
+       public int deepHashValue(Object value,\r
+                       IdentityHashMap<Object, Object> hashedObjects)\r
+                       throws BindingException {\r
+               throw new UnsupportedOperationException();\r
+       }\r
+\r
+       @Override\r
+       public int deepCompare(Object o1, Object o2,\r
+                       Set<IdentityPair<Object, Object>> compareHistory)\r
+                       throws BindingException {\r
+               throw new UnsupportedOperationException();\r
+       }\r
+\r
+       @Override\r
+       protected void toString(Object value, BindingPrintContext ctx)\r
+                       throws BindingException {\r
+               throw new UnsupportedOperationException();\r
+       }\r
+\r
+       @Override\r
+       public int getComponentCount() {\r
+               throw new UnsupportedOperationException();\r
+       }\r
+\r
+       @Override\r
+       public Binding getComponentBinding(int index) {\r
+               throw new UnsupportedOperationException();\r
+       }\r
+\r
+       @Override\r
+       public Binding getComponentBinding(ChildReference path) {\r
+               throw new UnsupportedOperationException();\r
+       }\r
+       \r
+       @Override\r
+       public Serializer serializer() throws RuntimeSerializerConstructionException {\r
+               return serializer;\r
+       }\r
+       \r
+}\r
+\r
+final public class LogUtils implements LogContentManager {\r
+\r
+       final public static boolean DEBUG = false;\r
+       \r
+       final public Binding CONTENT_BEAN_BINDING;\r
+       final public DatatypeResource DATA;\r
+       \r
+       public LogUtils(ReadGraph graph) throws DatabaseException {\r
+               try {\r
+                       CONTENT_BEAN_BINDING = new LogContentBinding(graph.getService(SerialisationSupport.class));\r
+                       DATA = DatatypeResource.getInstance(graph);\r
+               } catch (RuntimeBindingConstructionException e) {\r
+                       Logger.defaultLogError(e);\r
+                       throw new DatabaseException(e);\r
+               }\r
+       }\r
+       \r
+       public Resource create(WriteGraph graph, int t, int stamp) throws DatabaseException {\r
+               Layer0 L0 = Layer0.getInstance(graph);\r
+               Resource tree = graph.newResource();\r
+               graph.claim(tree, L0.InstanceOf, null, DATA.Log);\r
+               Resource index = createIndexNode(graph, this, stamp, t); \r
+               graph.claim(tree, DATA.Log_root, DATA.Log_root_Inverse, index);\r
+               graph.claimLiteral(tree, DATA.Log_t, t, Bindings.INTEGER);\r
+               Resource leaf = createLeafNode(graph, this, stamp, t);\r
+               graph.claim(index, DATA.BTreeNode_Content, null, leaf);\r
+               LogContentBean rContent = getContentBean(graph, index);\r
+               rContent.n = 1;\r
+               rContent.stamps[0] = stamp;\r
+               rContent.resources[0].r = leaf;\r
+               setContentBean(graph, index, rContent);\r
+               return tree;\r
+       }\r
+\r
+       public void insert(WriteGraph graph, Resource T, int stamp, Resource v) throws DatabaseException {\r
+\r
+               Resource r = getRoot(graph, T);\r
+               int t = getDegree(graph, T);\r
+               insertImpl(graph, this, T, r, t, stamp, v);\r
+               \r
+       }\r
+\r
+       static class BatchContentManager implements LogContentManager {\r
+\r
+               final private LogUtils bu;\r
+               \r
+               final Map<Resource, LogContentBean> beans = new HashMap<Resource, LogContentBean>();\r
+               \r
+               public BatchContentManager(LogUtils bu) {\r
+                       this.bu = bu;\r
+               }\r
+               \r
+               @Override\r
+               public LogContentBean getContentBean(ReadGraph graph, Resource node) throws DatabaseException {\r
+                       LogContentBean bean = beans.get(node);\r
+                       if(bean != null) return bean;\r
+                       return bu.getContentBean(graph, node);\r
+               }\r
+\r
+               @Override\r
+               public void setContentBean(WriteGraph graph, Resource node, LogContentBean bean) throws DatabaseException {\r
+                       beans.put(node, bean);\r
+               }\r
+               \r
+               public void apply(WriteGraph graph) throws DatabaseException {\r
+                       for(Map.Entry<Resource, LogContentBean> entry : beans.entrySet()) {\r
+                               bu.setContentBean(graph, entry.getKey(), entry.getValue());\r
+                       }\r
+               }\r
+               \r
+       }\r
+       \r
+       public void insertAll(WriteGraph graph, Resource T, Collection<Pair<Integer, Resource>> values) throws DatabaseException {\r
+\r
+               Resource r = getRoot(graph, T);\r
+               int t = getDegree(graph, T);\r
+               BatchContentManager cm = new BatchContentManager(this);\r
+               for(Pair<Integer, Resource> entry : values) {\r
+                       insertImpl(graph, cm, T, r, t, entry.first, entry.second);\r
+               }\r
+               cm.apply(graph);\r
+               \r
+       }\r
+       \r
+       // Implementation\r
+       private void insertImpl(WriteGraph graph, LogContentManager manager, Resource T, Resource r, int t, int k, Resource v) throws DatabaseException {\r
+               \r
+               int code = insertImpl2(graph, manager, 0, T, r, t, k, v); \r
+               \r
+               if(code > 0) {\r
+                       \r
+                       LogContentBean rContent = manager.getContentBean(graph, r);\r
+                       \r
+                       if(DEBUG) System.err.println("[insert index code=" + code + "]");\r
+\r
+                       Resource newRoot = createIndexNode(graph, manager, k, t);\r
+                       graph.claim(newRoot, DATA.Log_Node_Contains, null, r);\r
+                       setRoot(graph, T, newRoot);\r
+                       \r
+                       LogContentBean nContent = manager.getContentBean(graph, newRoot);\r
+                       nContent.stamps[0] = rContent.stamps[0];\r
+                       nContent.resources[0].r = r;\r
+                       nContent.n = 1;\r
+                       manager.setContentBean(graph, newRoot, nContent);\r
+\r
+                       Resource leaf = createLeaf(graph, manager, newRoot, code, k, t);\r
+                       \r
+                       LogContentBean lContent = manager.getContentBean(graph, leaf);\r
+                       lContent.n = 1;\r
+                       lContent.stamps[0] = k;\r
+                       lContent.resources[0].r = v;\r
+\r
+                       if(DEBUG) System.err.println("[insert " + k + "]: started a new branch");\r
+\r
+                       manager.setContentBean(graph, leaf, lContent);\r
+\r
+               }\r
+               \r
+       }\r
+\r
+       private int insertImpl2(WriteGraph graph, LogContentManager manager, int level, Resource T, Resource r, int t, int k, Resource v) throws DatabaseException {\r
+\r
+               LogContentBean rContent = manager.getContentBean(graph, r);\r
+\r
+               // Index\r
+               if(!rContent.leaf) {\r
+                       \r
+                       Resource child = rContent.resources[rContent.n-1].r;\r
+                       int code = insertImpl2(graph, manager, level+1, T, child, t, k, v); \r
+                       \r
+                       if(code == 0) {\r
+                               \r
+                               // Value was inserted successfully\r
+                               return 0;\r
+                               \r
+                       } else {\r
+\r
+                               // The child was full\r
+                               if(rContent.n < t) {\r
+                                       \r
+                                       // We can create a new child\r
+                                       Resource leaf = createLeaf(graph, manager, r, code-level-1, k, t);\r
+                                       LogContentBean lContent = manager.getContentBean(graph, leaf);\r
+                                       lContent.stamps[0] = k;\r
+                                       lContent.resources[0].r = v;\r
+                                       lContent.n = 1;\r
+                                       manager.setContentBean(graph, leaf, lContent);\r
+                                       \r
+                                       if(DEBUG) System.err.println("[insert " + k + "]: created a fresh leaf");\r
+                                       \r
+                                       return 0;\r
+                                       \r
+                               } else {\r
+\r
+                                       // We are full, let the parent handle this\r
+                                       return code;\r
+                                       \r
+                               }\r
+                               \r
+                               \r
+                       }\r
+                       \r
+               }\r
+               \r
+               // Leaf\r
+               else {\r
+\r
+                       if(rContent.n < t) {\r
+                               \r
+                               if(DEBUG) System.err.println("[insert " + k + "]: fit into leaf at level " + level);\r
+                               \r
+                               // Append\r
+                               rContent.stamps[rContent.n] = k;\r
+                               rContent.resources[rContent.n].r = v;\r
+                               rContent.n++;\r
+                               manager.setContentBean(graph, r, rContent);\r
+                               return 0;\r
+                               \r
+                       } else {\r
+\r
+                               // This leaf is full\r
+                               return level;\r
+                               \r
+                       }\r
+                       \r
+               }\r
+               \r
+       }\r
+       \r
+       private Resource createLeaf(WriteGraph graph, LogContentManager manager, Resource r, int code, int stamp, int t) throws DatabaseException {\r
+               LogContentBean rContent = manager.getContentBean(graph, r);\r
+               if(code == 0) {\r
+                       if(DEBUG) System.err.println("[insert leaf code=" + code + "]");\r
+                       Resource result = createLeafNode(graph, manager, stamp, t);\r
+                       graph.claim(r, DATA.Log_Node_Contains, null, result);\r
+                       rContent.stamps[rContent.n] = stamp;\r
+                       rContent.resources[rContent.n].r = result;\r
+                       rContent.n++;\r
+                       manager.setContentBean(graph, r, rContent);\r
+                       return result;\r
+               } else {\r
+                       if(DEBUG) System.err.println("[insert index code=" + code + "]");\r
+                       Resource index = createIndexNode(graph, manager, stamp, t);\r
+                       graph.claim(r, DATA.Log_Node_Contains, null, index);\r
+                       rContent.stamps[rContent.n] = stamp;\r
+                       rContent.resources[rContent.n].r = index;\r
+                       rContent.n++;\r
+                       manager.setContentBean(graph, r, rContent);\r
+                       return createLeaf(graph, manager, index, code-1, stamp, t);\r
+               }\r
+       }\r
+       \r
+       private Resource createIndexNode(WriteGraph graph, LogContentManager manager, int stamp, int t) throws DatabaseException {\r
+               Layer0 L0 = Layer0.getInstance(graph);\r
+               Resource result = graph.newResource();\r
+               graph.claim(result, L0.InstanceOf, null, DATA.Log_IndexNode);\r
+               manager.setContentBean(graph, result, LogContentBean.create(t, stamp, false));\r
+               return result;\r
+       }\r
+\r
+       private Resource createLeafNode(WriteGraph graph, LogContentManager manager, int stamp, int t) throws DatabaseException {\r
+               Layer0 L0 = Layer0.getInstance(graph);\r
+               Resource result = graph.newResource();\r
+               graph.claim(result, L0.InstanceOf, null, DATA.Log_LeafNode);\r
+               manager.setContentBean(graph, result, LogContentBean.create(t, stamp, true));\r
+               return result;\r
+       }\r
+       \r
+       private Resource getRoot(ReadGraph graph, Resource T) throws DatabaseException {\r
+               return graph.getPossibleObject(T, DATA.Log_root);\r
+       }\r
+       \r
+       private void setRoot(WriteGraph graph, Resource T, Resource r) throws DatabaseException {\r
+               graph.deny(T, DATA.Log_root);\r
+               graph.claim(T, DATA.Log_root, r);\r
+       }\r
+       \r
+       public void setContentBean(WriteGraph graph, Resource node, LogContentBean bean) throws DatabaseException {\r
+               graph.claimLiteral(node, DATA.Log_Node_content, DATA.Log_Content, bean, CONTENT_BEAN_BINDING );\r
+       }\r
+\r
+       private int getDegree(ReadGraph graph, Resource tree) throws DatabaseException {\r
+               return graph.syncRequest(new RelatedValue<Integer>(tree, DATA.Log_t, Bindings.INTEGER), TransientCacheListener.<Integer>instance());\r
+       }\r
+       \r
+       public LogContentBean getContentBean(ReadGraph graph, Resource node) throws DatabaseException {\r
+               return graph.syncRequest(new RelatedValue<LogContentBean>(node, DATA.Log_Node_content, CONTENT_BEAN_BINDING), TransientCacheListener.<LogContentBean>instance());\r
+       }\r
+       \r
+}\r