--- /dev/null
+package fi.vtt.simantics.procore.internal;\r
+\r
+import java.util.TreeMap;\r
+\r
+import org.simantics.db.Metadata;\r
+import org.simantics.db.Operation;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.VirtualGraph;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.MetadataUtils;\r
+import org.simantics.db.common.exception.DebugException;\r
+import org.simantics.db.common.utils.Logger;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.exception.ImmutableException;\r
+import org.simantics.db.exception.ServiceException;\r
+import org.simantics.db.impl.ClusterI;\r
+import org.simantics.db.impl.MemWatch;\r
+import org.simantics.db.impl.ResourceImpl;\r
+import org.simantics.db.impl.VirtualGraphImpl;\r
+import org.simantics.db.impl.graph.ReadGraphImpl;\r
+import org.simantics.db.impl.graph.WriteGraphImpl;\r
+import org.simantics.db.impl.graph.WriteSupport;\r
+import org.simantics.db.impl.query.QueryProcessor;\r
+import org.simantics.db.impl.query.QuerySupport;\r
+import org.simantics.db.procore.cluster.ClusterImpl;\r
+import org.simantics.db.procore.protocol.Constants;\r
+import org.simantics.db.request.Write;\r
+import org.simantics.db.request.WriteOnly;\r
+import org.simantics.db.request.WriteResult;\r
+import org.simantics.db.request.WriteTraits;\r
+import org.simantics.db.service.ByteReader;\r
+\r
+public class WriteSupportImpl implements WriteSupport {\r
+\r
+ final private SessionImplSocket session;\r
+ final private QueryProcessor queryProcessor;\r
+ final private State state;\r
+ final private QuerySupport querySupport;\r
+ final private TreeMap<String, byte[]> metadata;\r
+ \r
+ WriteSupportImpl(SessionImplSocket session) {\r
+ this.session = session;\r
+ this.queryProcessor = session.getQueryProvider2();\r
+ this.state = session.state;\r
+ this.querySupport = session.querySupport;\r
+ this.metadata = new TreeMap<String, byte[]>();\r
+ assert(this.session != null);\r
+ assert(this.queryProcessor != null);\r
+ assert(this.state != null);\r
+ assert(this.querySupport != null);\r
+ }\r
+ \r
+ @Override\r
+ public void flushCluster() {\r
+ session.clusterTable.flushCluster(session.graphSession);\r
+ if(session.defaultClusterSet != null) {\r
+ long resourceId = session.defaultClusterSet.getResourceId();\r
+ session.clusterSetsSupport.put(resourceId, Constants.NewClusterId);\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public void flushCluster(Resource r) {\r
+ session.clusterStream.reallyFlush();\r
+ }\r
+\r
+ @Override\r
+ public boolean writeOnly() {\r
+ return session.writeOnly;\r
+ }\r
+\r
+ @Override\r
+ public void flush(boolean intermediate) {\r
+\r
+ if (!session.state.isWriteTransaction())\r
+ throw new IllegalStateException("Can only flush during transaction.");\r
+\r
+ gc();\r
+ \r
+ }\r
+ \r
+ final public void claim(VirtualGraph provider, Resource subject, Resource predicate, Resource object) throws ServiceException {\r
+ claim(provider, querySupport.getId(subject), querySupport.getId(predicate), querySupport.getId(object));\r
+ }\r
+\r
+ @Override\r
+ final public void claim(VirtualGraph provider, int subject, int predicate, int object)\r
+ throws ServiceException {\r
+\r
+ provider = session.getProvider(provider); \r
+ if (writeOnly()) {\r
+ if (provider != null) {\r
+ ((VirtualGraphImpl)provider).claim(subject, predicate, object);\r
+ queryProcessor.updateStatements(subject, predicate);\r
+ session.clientChanges.claim(subject, predicate, object);\r
+ } else {\r
+ claimImpl2(subject, predicate, object);\r
+ }\r
+ } else {\r
+// queryProcessor.acquireWrite(writeState.getGraph());\r
+ if (provider != null) {\r
+ ((VirtualGraphImpl)provider).claim(subject, predicate, object);\r
+ queryProcessor.updateStatements(subject, predicate);\r
+ session.clientChanges.claim(subject, predicate, object);\r
+ } else {\r
+ claimImpl(subject, predicate, object);\r
+ }\r
+ queryProcessor.releaseWrite(session.writeState.getGraph());\r
+ }\r
+ \r
+ }\r
+ \r
+ @Override\r
+ public void setValue(VirtualGraph provider, Resource resource, byte[] value) throws ServiceException {\r
+\r
+ provider = session.getProvider(provider);\r
+ if (writeOnly()) {\r
+ if (provider != null) {\r
+ ((VirtualGraphImpl)provider).claimValue(((ResourceImpl) resource).id, value, value.length);\r
+ queryProcessor.updateValue(querySupport.getId(resource));\r
+ session.clientChanges.claimValue(resource);\r
+ } else {\r
+ try {\r
+ addSetValue(((ResourceImpl) resource).id, value, value.length);\r
+ } catch (DatabaseException e) {\r
+ Logger.defaultLogError(e);\r
+ }\r
+ }\r
+ } else {\r
+ if (provider != null) {\r
+ ((VirtualGraphImpl)provider).claimValue(((ResourceImpl) resource).id, value, value.length);\r
+ queryProcessor.updateValue(querySupport.getId(resource));\r
+ session.clientChanges.claimValue(resource);\r
+ } else {\r
+ try {\r
+ addSetValue(((ResourceImpl) resource).id, value, value.length);\r
+ } catch (DatabaseException e) {\r
+ Logger.defaultLogError(e);\r
+ }\r
+ }\r
+ queryProcessor.releaseWrite(session.writeState.getGraph());\r
+ }\r
+\r
+ }\r
+\r
+ @Override\r
+ public Resource createResource(VirtualGraph provider) throws DatabaseException {\r
+ if (provider != null) {\r
+ int newId = ((VirtualGraphImpl)provider).newResource(false);\r
+ return new ResourceImpl(session.resourceSupport, newId);\r
+ } else {\r
+ return session.getNewResource();\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public Resource createResource(VirtualGraph provider, long clusterId)\r
+ throws DatabaseException {\r
+ assert (provider == null);\r
+ return session.getNewResource(clusterId);\r
+ }\r
+\r
+ @Override\r
+ public Resource createResource(VirtualGraph provider, Resource clusterSet)\r
+ throws DatabaseException {\r
+ assert(provider == null);\r
+ assert(clusterSet != null);\r
+ return session.getNewResource(clusterSet);\r
+ }\r
+\r
+ @Override\r
+ public void createClusterSet(VirtualGraph provider, Resource clusterSet)\r
+ throws DatabaseException {\r
+ assert(provider == null);\r
+ assert(clusterSet != null);\r
+ session.getNewClusterSet(clusterSet);\r
+ }\r
+\r
+ @Override\r
+ public boolean hasClusterSet(VirtualGraph dummy, Resource clusterSet)\r
+ throws ServiceException {\r
+ return session.containsClusterSet(clusterSet);\r
+ }\r
+\r
+ @Override\r
+ public Resource setDefaultClusterSet(Resource clusterSet)\r
+ throws ServiceException {\r
+ return session.setDefaultClusterSet4NewResource(clusterSet);\r
+ }\r
+ @Override\r
+ public void denyValue(VirtualGraph provider, Resource resource) throws ServiceException {\r
+ provider = session.getProvider(provider);\r
+ if (null == provider) {\r
+ int key = ((ResourceImpl)resource).id;\r
+ ClusterI cluster = session.clusterTable.getClusterByResourceKey(key);\r
+ if (cluster.getImmutable() && (session.serviceMode & SessionImplSocket.SERVICE_MODE_ALLOW) == 0)\r
+ if(key != queryProcessor.getRootLibrary())\r
+ throw new ImmutableException("Trying to modify immutable resource key=" + key);\r
+\r
+ try { \r
+ cluster.removeValue(key, session.clusterTranslator);\r
+ } catch (DatabaseException e) {\r
+ Logger.defaultLogError(e);\r
+ return;\r
+ }\r
+ queryProcessor.updateValue(key);\r
+ session.clientChanges.claimValue(resource);\r
+ } else {\r
+ ((VirtualGraphImpl)provider).denyValue(((ResourceImpl) resource).id);\r
+ queryProcessor.updateValue(querySupport.getId(resource));\r
+ session.clientChanges.claimValue(resource);\r
+ }\r
+ if (!writeOnly())\r
+ queryProcessor.releaseWrite(session.writeState.getGraph());\r
+ }\r
+\r
+\r
+ @Override\r
+ public boolean removeStatement(VirtualGraph provider, Resource subject, Resource predicate,\r
+ Resource object) throws ServiceException {\r
+ boolean ret = true;\r
+ if (writeOnly()) {\r
+ if (provider != null) {\r
+ ((VirtualGraphImpl)provider).deny(querySupport.getId(subject), querySupport.getId(predicate), querySupport.getId(object));\r
+ queryProcessor.updateStatements(querySupport.getId(subject), querySupport.getId(predicate));\r
+ } else {\r
+ ret = removeStatement(querySupport.getId(subject), querySupport.getId(predicate), querySupport.getId(object));\r
+ }\r
+ } else {\r
+ if (provider != null) {\r
+// queryProcessor.acquireWrite(writeState.getGraph());\r
+ ((VirtualGraphImpl)provider).deny(querySupport.getId(subject), querySupport.getId(predicate), querySupport.getId(object));\r
+ queryProcessor.updateStatements(querySupport.getId(subject), querySupport.getId(predicate));\r
+ queryProcessor.releaseWrite(session.writeState.getGraph());\r
+ } else {\r
+ int sid = querySupport.getId(subject);\r
+ int pid = querySupport.getId(predicate);\r
+ int oid = querySupport.getId(object);\r
+ if (sid < 0 || pid < 0 || oid < 0) {\r
+ // One of the resources is virtual, cannot remove such\r
+ // statement from persistent storage.\r
+ return false;\r
+ }\r
+// queryProcessor.acquireWrite(writeState.getGraph());\r
+ ret = removeStatement(sid, pid, oid);\r
+ queryProcessor.releaseWrite(session.writeState.getGraph());\r
+ }\r
+ }\r
+ session.clientChanges.deny(subject, predicate, object);\r
+ return ret;\r
+ }\r
+ \r
+ @Override\r
+ public synchronized void performWriteRequest(WriteGraph graph_, Write request) throws DatabaseException {\r
+ WriteGraphImpl graph = (WriteGraphImpl)graph_;\r
+// graph.state.barrier.inc();\r
+ try {\r
+ request.perform(graph);\r
+ } catch (Throwable t) {\r
+ t.printStackTrace();\r
+ }\r
+// graph.state.barrier.dec();\r
+// graph.waitAsync(request);\r
+ \r
+ queryProcessor.performDirtyUpdates(graph);\r
+ \r
+ // Do not fire metadata listeners for virtual requests\r
+ if(graph.getProvider() == null) {\r
+ //session.fireMetadataListeners(graph, session.clientChanges);\r
+ state.commitAndContinue(graph, session.clusterStream, request);\r
+ //session.clientChanges = new ClientChangesImpl(session);\r
+ }\r
+\r
+// graph.state.barrier.assertReady();\r
+ \r
+ }\r
+ \r
+ @Override\r
+ public synchronized <T> T performWriteRequest(WriteGraph graph_, WriteResult<T> request) throws DatabaseException {\r
+\r
+ WriteGraphImpl graph = (WriteGraphImpl)graph_;\r
+// graph.state.barrier.inc();\r
+ T result = null;\r
+ Throwable t = null;\r
+ try {\r
+ result = request.perform(graph);\r
+ } catch (Throwable t2) {\r
+ if(DebugException.DEBUG) new DebugException(t2).printStackTrace();\r
+ t = t2;\r
+ }\r
+ \r
+// graph.state.barrier.dec();\r
+// graph.waitAsync(request);\r
+ \r
+ queryProcessor.performDirtyUpdates(graph);\r
+\r
+ // Do not fire metadata listeners for virtual requests\r
+ if(graph.getProvider() == null) {\r
+ //session.fireMetadataListeners((WriteGraphImpl)graph, session.clientChanges);\r
+ state.commitAndContinue(graph, session.clusterStream, request);\r
+ //session.clientChanges = new ClientChangesImpl(session);\r
+ }\r
+ \r
+ if(t != null) {\r
+ if(t instanceof DatabaseException) throw (DatabaseException)t;\r
+ else throw new DatabaseException(t);\r
+ }\r
+ \r
+ return result;\r
+ \r
+ }\r
+\r
+ @Override\r
+ public synchronized void performWriteRequest(WriteGraph graph, WriteOnly request) throws DatabaseException {\r
+\r
+ session.acquireWriteOnly();\r
+ \r
+ request.perform(graph);\r
+ \r
+ ReadGraphImpl impl = (ReadGraphImpl)graph;\r
+ \r
+ queryProcessor.performDirtyUpdates(impl);\r
+\r
+ // Do not fire metadata listeners for virtual requests\r
+ if(graph.getProvider() == null) {\r
+ //session.fireMetadataListeners(impl, session.clientChanges);\r
+ state.commitAndContinue(session.writeState.getGraph(), session.clusterStream, request);\r
+ //session.clientChanges = new ClientChangesImpl(session);\r
+ } \r
+ session.releaseWriteOnly(impl);\r
+ \r
+ }\r
+\r
+ \r
+ @Override\r
+ public void gc() {\r
+ if (MemWatch.isLowOnMemory()) {\r
+ session.clusterTable.gc();\r
+ queryProcessor.gc(0, Integer.MAX_VALUE);\r
+ System.gc();\r
+ }\r
+ }\r
+ \r
+ @Override\r
+ public void claimValue(VirtualGraph provider, Resource resource, byte[] value) throws DatabaseException {\r
+ claimValue(provider, ((ResourceImpl)resource).id, value, value.length);\r
+ }\r
+\r
+ @Override\r
+ public void claimValue(VirtualGraph provider, int resource, byte[] value, int length) throws DatabaseException {\r
+\r
+ provider = session.getProvider(provider);\r
+ if (writeOnly()) {\r
+ if (provider != null) {\r
+ ((VirtualGraphImpl)provider).claimValue(resource, value, length);\r
+ queryProcessor.updateValue(resource);\r
+ session.clientChanges.claimValue(resource);\r
+ } else {\r
+ addSetValue(resource, value, length);\r
+ }\r
+ } else {\r
+ if (provider != null) {\r
+ ((VirtualGraphImpl)provider).claimValue(resource, value, length);\r
+ queryProcessor.updateValue(resource);\r
+ session.clientChanges.claimValue(resource);\r
+ queryProcessor.releaseWrite(session.writeState.getGraph());\r
+ } else {\r
+ try {\r
+ addSetValue(resource, value, length);\r
+ } catch (DatabaseException e) {\r
+ throw e;\r
+ } catch (Throwable t) {\r
+ throw new DatabaseException(t);\r
+ } finally {\r
+ queryProcessor.releaseWrite(session.writeState.getGraph());\r
+ }\r
+ }\r
+ }\r
+ }\r
+ \r
+ @Override\r
+ public void claimValue(VirtualGraph provider, Resource resource, ByteReader reader, int amount) throws DatabaseException {\r
+ claimValue(provider, resource, reader.readBytes(null, amount));\r
+ }\r
+\r
+ @Override\r
+ public <T> void addMetadata(Metadata data) throws ServiceException {\r
+ MetadataUtils.addMetadata(session, metadata, data);\r
+ }\r
+\r
+ @SuppressWarnings("unchecked")\r
+ @Override\r
+ public <T extends Metadata> T getMetadata(Class<T> clazz) throws ServiceException {\r
+ return MetadataUtils.getMetadata(session, metadata, clazz);\r
+ }\r
+\r
+ @Override\r
+ public TreeMap<String, byte[]> getMetadata() {\r
+ return metadata;\r
+ }\r
+\r
+ @Override\r
+ public void commitDone(WriteTraits writeTraits, long csid) {\r
+ metadata.clear();\r
+ if (this.writeTraits == writeTraits) {\r
+ session.graphSession.undoContext.clear();\r
+ this.writeTraits = null;\r
+ }\r
+// if (null != operation)\r
+// operation = null;\r
+ }\r
+ @Override\r
+ public int clearMetadata() {\r
+ int ret = metadata.size();\r
+ metadata.clear();\r
+ return ret;\r
+ }\r
+ @Override\r
+ public void clearUndoList(WriteTraits writeTraits) {\r
+ this.writeTraits = writeTraits;\r
+ }\r
+ @Override\r
+ public void startUndo() {\r
+ session.state.setCombine(false);\r
+ }\r
+ private WriteTraits writeTraits = null;\r
+ private void addSetValue(int subject, byte[] value, int length)\r
+ throws DatabaseException {\r
+\r
+ ClusterI cluster = session.clusterTable.getClusterByResourceKey(subject);\r
+ if (cluster.getImmutable() && (session.serviceMode & SessionImplSocket.SERVICE_MODE_ALLOW) == 0)\r
+ if(subject != queryProcessor.getRootLibrary())\r
+ throw new ImmutableException("Trying to modify immutable resource key=" + subject);\r
+ \r
+ ClusterI cluster2 = cluster.setValue(subject, value, length, session.clusterTranslator);\r
+ if (cluster2 != cluster)\r
+ session.clusterTable.replaceCluster(cluster2);\r
+ \r
+ session.clientChanges.claimValue(subject);\r
+ \r
+ if (cluster2.isWriteOnly())\r
+ return;\r
+\r
+ queryProcessor.updateValue(subject);\r
+\r
+ }\r
+\r
+ final private void claimImpl(int subject, int predicate, int object)\r
+ throws ServiceException {\r
+\r
+ assert (subject != 0);\r
+ assert (predicate != 0);\r
+ assert (object != 0);\r
+\r
+ ClusterImpl cluster = session.clusterTable.getClusterByResourceKey(subject);\r
+ assert (null != cluster);\r
+ if (cluster.getImmutable() && (session.serviceMode & SessionImplSocket.SERVICE_MODE_ALLOW) == 0)\r
+ if(subject != queryProcessor.getRootLibrary())\r
+ throw new ImmutableException("Trying to modify immutable resource key=" + subject);\r
+ try {\r
+ ClusterI c = cluster.addRelation(subject, predicate, object, session.clusterTranslator);\r
+ if (null != c && c != cluster)\r
+ session.clusterTable.replaceCluster(c);\r
+ } catch (DatabaseException e) {\r
+ Logger.defaultLogError(e);\r
+ throw new RuntimeException(e);\r
+ }\r
+ queryProcessor.updateStatements(subject, predicate);\r
+ session.clientChanges.claim(subject, predicate, object);\r
+\r
+ }\r
+\r
+ final private void claimImpl2(int subject, int predicate, int object) {\r
+ \r
+ assert (subject != 0);\r
+ assert (predicate != 0);\r
+ assert (object != 0);\r
+\r
+ ClusterI cluster = session.clusterTable.getClusterByResourceKey(subject);\r
+ try {\r
+ ClusterI c = cluster.addRelation(subject, predicate, object, session.clusterTranslator);\r
+ if (null != c && c != cluster)\r
+ session.clusterTable.replaceCluster(c);\r
+ } catch (DatabaseException e) {\r
+ Logger.defaultLogError(e);\r
+ }\r
+ if (cluster.isWriteOnly())\r
+ return;\r
+ queryProcessor.updateStatements(subject, predicate);\r
+\r
+ }\r
+ \r
+ private boolean removeStatement(int subject, int predicate, int object) throws ImmutableException {\r
+\r
+ assert (subject != 0);\r
+ assert (predicate != 0);\r
+ assert (object != 0);\r
+\r
+ ClusterI cluster = session.clusterTable.getClusterByResourceKey(subject);\r
+ assert (null != cluster);\r
+\r
+ if (cluster.getImmutable() && (session.serviceMode & SessionImplSocket.SERVICE_MODE_ALLOW) == 0)\r
+ if(subject != queryProcessor.getRootLibrary())\r
+ throw new ImmutableException("Trying to modify immutable resource key=" + subject);\r
+\r
+ try {\r
+ cluster.denyRelation(subject, predicate, object, session.clusterTranslator);\r
+ } catch (DatabaseException e) {\r
+ Logger.defaultLogError(e);\r
+ return false;\r
+ }\r
+ queryProcessor.updateStatements(subject, predicate);\r
+ return true;\r
+\r
+ }\r
+ \r
+}\r