1 package org.simantics.datatypes.utils;
\r
3 import gnu.trove.map.hash.TObjectIntHashMap;
\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
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
37 interface LogContentManager {
\r
39 LogContentBean getContentBean(ReadGraph graph, Resource node) throws DatabaseException;
\r
40 void setContentBean(WriteGraph graph, Resource node, LogContentBean bean) throws DatabaseException;
\r
44 class LogContentBinding extends Binding {
\r
46 private final SerialisationSupport ss;
\r
48 public LogContentBinding(SerialisationSupport ss) {
\r
52 private final Serializer serializer = new Serializer() {
\r
55 public void serialize(DataOutput out, TObjectIntHashMap<Object> identities, Object obj) throws IOException {
\r
56 throw new UnsupportedOperationException();
\r
60 public void serialize(DataOutput out, Object obj) throws IOException {
\r
61 throw new UnsupportedOperationException();
\r
65 public Object deserialize(DataInput in, List<Object> identities)
\r
66 throws IOException {
\r
67 throw new UnsupportedOperationException();
\r
71 public Object deserialize(DataInput in) throws IOException {
\r
72 throw new UnsupportedOperationException();
\r
76 public void deserializeTo(DataInput in, List<Object> identities,
\r
77 Object dst) throws IOException {
\r
78 throw new UnsupportedOperationException();
\r
82 public void deserializeTo(DataInput in, Object dst) throws IOException {
\r
83 throw new UnsupportedOperationException();
\r
87 public void skip(DataInput in, List<Object> identities)
\r
88 throws IOException {
\r
89 throw new UnsupportedOperationException();
\r
93 public void skip(DataInput in) throws IOException {
\r
94 throw new UnsupportedOperationException();
\r
98 public Integer getConstantSize() {
\r
99 throw new UnsupportedOperationException();
\r
103 public int getSize(Object obj, TObjectIntHashMap<Object> identities)
\r
104 throws IOException {
\r
105 throw new UnsupportedOperationException();
\r
109 public int getSize(Object obj) throws IOException {
\r
110 throw new UnsupportedOperationException();
\r
114 public int getMinSize() {
\r
115 throw new UnsupportedOperationException();
\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
124 Bytes.writeLE(result, byteIndex, bean.n);
\r
126 Bytes.writeLE(result, byteIndex, bean.stamps.length);
\r
128 for(long l : bean.stamps) {
\r
129 Bytes.writeLE(result, byteIndex, l);
\r
132 for(PossibleResource pr : bean.resources) {
\r
133 Bytes.writeLE(result, byteIndex, pr.longValue());
\r
139 public Object deserialize(byte[] data) throws IOException {
\r
141 LogContentBean result = new LogContentBean();
\r
145 result.leaf = Bytes.read(data, 0) == 1 ? true : false;
\r
147 result.n = Bytes.readLE4(data, byteIndex);
\r
149 int t = Bytes.readLE4(data, byteIndex);
\r
152 result.stamps = new long[t];
\r
153 result.resources = new PossibleResource[t];
\r
155 for(int i=0;i<t;i++) {
\r
156 result.stamps[i] = Bytes.readLE8(data, byteIndex);
\r
160 for(int i=0;i<t;i++) {
\r
161 result.resources[i] = PossibleResource.read(ss, Bytes.readLE8(data, byteIndex));
\r
165 } catch (DatabaseException e) {
\r
167 e.printStackTrace();
\r
178 public void accept(Visitor1 v, Object obj) {
\r
179 throw new UnsupportedOperationException();
\r
183 public <T> T accept(Visitor<T> v) {
\r
184 throw new UnsupportedOperationException();
\r
188 public boolean isInstance(Object obj) {
\r
189 throw new UnsupportedOperationException();
\r
193 public void readFrom(Binding srcBinding, Object src, Object dst)
\r
194 throws BindingException {
\r
195 throw new UnsupportedOperationException();
\r
199 public void assertInstaceIsValid(Object obj, Set<Object> validInstances)
\r
200 throws BindingException {
\r
201 throw new UnsupportedOperationException();
\r
205 public int deepHashValue(Object value,
\r
206 IdentityHashMap<Object, Object> hashedObjects)
\r
207 throws BindingException {
\r
208 throw new UnsupportedOperationException();
\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
219 protected void toString(Object value, BindingPrintContext ctx)
\r
220 throws BindingException {
\r
221 throw new UnsupportedOperationException();
\r
225 public int getComponentCount() {
\r
226 throw new UnsupportedOperationException();
\r
230 public Binding getComponentBinding(int index) {
\r
231 throw new UnsupportedOperationException();
\r
235 public Binding getComponentBinding(ChildReference path) {
\r
236 throw new UnsupportedOperationException();
\r
240 public Serializer serializer() throws RuntimeSerializerConstructionException {
\r
246 final public class LogUtils implements LogContentManager {
\r
248 final public static boolean DEBUG = false;
\r
250 final public Binding CONTENT_BEAN_BINDING;
\r
251 final public DatatypeResource DATA;
\r
253 public LogUtils(ReadGraph graph) throws DatabaseException {
\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
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
274 rContent.stamps[0] = stamp;
\r
275 rContent.resources[0].r = leaf;
\r
276 setContentBean(graph, index, rContent);
\r
280 public void insert(WriteGraph graph, Resource T, int stamp, Resource v) throws DatabaseException {
\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
288 static class BatchContentManager implements LogContentManager {
\r
290 final private LogUtils bu;
\r
292 final Map<Resource, LogContentBean> beans = new HashMap<Resource, LogContentBean>();
\r
294 public BatchContentManager(LogUtils bu) {
\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
306 public void setContentBean(WriteGraph graph, Resource node, LogContentBean bean) throws DatabaseException {
\r
307 beans.put(node, bean);
\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
318 public void insertAll(WriteGraph graph, Resource T, Collection<Pair<Integer, Resource>> values) throws DatabaseException {
\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
331 private void insertImpl(WriteGraph graph, LogContentManager manager, Resource T, Resource r, int t, int k, Resource v) throws DatabaseException {
\r
333 int code = insertImpl2(graph, manager, 0, T, r, t, k, v);
\r
337 LogContentBean rContent = manager.getContentBean(graph, r);
\r
339 if(DEBUG) System.err.println("[insert index code=" + code + "]");
\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
345 LogContentBean nContent = manager.getContentBean(graph, newRoot);
\r
346 nContent.stamps[0] = rContent.stamps[0];
\r
347 nContent.resources[0].r = r;
\r
349 manager.setContentBean(graph, newRoot, nContent);
\r
351 Resource leaf = createLeaf(graph, manager, newRoot, code, k, t);
\r
353 LogContentBean lContent = manager.getContentBean(graph, leaf);
\r
355 lContent.stamps[0] = k;
\r
356 lContent.resources[0].r = v;
\r
358 if(DEBUG) System.err.println("[insert " + k + "]: started a new branch");
\r
360 manager.setContentBean(graph, leaf, lContent);
\r
366 private int insertImpl2(WriteGraph graph, LogContentManager manager, int level, Resource T, Resource r, int t, int k, Resource v) throws DatabaseException {
\r
368 LogContentBean rContent = manager.getContentBean(graph, r);
\r
371 if(!rContent.leaf) {
\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
378 // Value was inserted successfully
\r
383 // The child was full
\r
384 if(rContent.n < t) {
\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
392 manager.setContentBean(graph, leaf, lContent);
\r
394 if(DEBUG) System.err.println("[insert " + k + "]: created a fresh leaf");
\r
400 // We are full, let the parent handle this
\r
413 if(rContent.n < t) {
\r
415 if(DEBUG) System.err.println("[insert " + k + "]: fit into leaf at level " + level);
\r
418 rContent.stamps[rContent.n] = k;
\r
419 rContent.resources[rContent.n].r = v;
\r
421 manager.setContentBean(graph, r, rContent);
\r
426 // This leaf is full
\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
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
444 manager.setContentBean(graph, r, rContent);
\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
453 manager.setContentBean(graph, r, rContent);
\r
454 return createLeaf(graph, manager, index, code-1, stamp, t);
\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
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
474 private Resource getRoot(ReadGraph graph, Resource T) throws DatabaseException {
\r
475 return graph.getPossibleObject(T, DATA.Log_root);
\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
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
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
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