]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/WriteSupportImpl.java
Fix for empty cancelled write transactions leaving scheduled updates
[simantics/platform.git] / bundles / org.simantics.db.procore / src / fi / vtt / simantics / procore / internal / WriteSupportImpl.java
1 package fi.vtt.simantics.procore.internal;
2
3 import java.util.TreeMap;
4
5 import org.simantics.db.Metadata;
6 import org.simantics.db.Resource;
7 import org.simantics.db.VirtualGraph;
8 import org.simantics.db.WriteGraph;
9 import org.simantics.db.common.MetadataUtils;
10 import org.simantics.db.common.exception.DebugException;
11 import org.simantics.db.common.utils.Logger;
12 import org.simantics.db.exception.DatabaseException;
13 import org.simantics.db.exception.ImmutableException;
14 import org.simantics.db.exception.ServiceException;
15 import org.simantics.db.impl.ClusterI;
16 import org.simantics.db.impl.MemWatch;
17 import org.simantics.db.impl.ResourceImpl;
18 import org.simantics.db.impl.VirtualGraphImpl;
19 import org.simantics.db.impl.graph.ReadGraphImpl;
20 import org.simantics.db.impl.graph.WriteGraphImpl;
21 import org.simantics.db.impl.graph.WriteSupport;
22 import org.simantics.db.impl.query.QueryProcessor;
23 import org.simantics.db.impl.query.QuerySupport;
24 import org.simantics.db.procore.cluster.ClusterImpl;
25 import org.simantics.db.procore.protocol.Constants;
26 import org.simantics.db.request.Write;
27 import org.simantics.db.request.WriteOnly;
28 import org.simantics.db.request.WriteResult;
29 import org.simantics.db.request.WriteTraits;
30 import org.simantics.db.service.ByteReader;
31
32 public class WriteSupportImpl implements WriteSupport {
33
34     final private SessionImplSocket session;
35     final private QueryProcessor queryProcessor;
36     final private State state;
37     final private QuerySupport querySupport;
38     final private TreeMap<String, byte[]> metadata;
39     
40     WriteSupportImpl(SessionImplSocket session) {
41         this.session = session;
42         this.queryProcessor = session.getQueryProvider2();
43         this.state = session.state;
44         this.querySupport = session.querySupport;
45         this.metadata = new TreeMap<String, byte[]>();
46         assert(this.session != null);
47         assert(this.queryProcessor != null);
48         assert(this.state != null);
49         assert(this.querySupport != null);
50     }
51     
52     @Override
53     public void flushCluster() {
54         session.clusterTable.flushCluster(session.graphSession);
55         if(session.defaultClusterSet != null) {
56             long resourceId = session.defaultClusterSet.getResourceId();
57             session.clusterSetsSupport.put(resourceId, Constants.NewClusterId);
58         }
59     }
60
61     @Override
62     public void flushCluster(Resource r) {
63         session.clusterStream.reallyFlush();
64     }
65
66     @Override
67     public boolean writeOnly() {
68         return session.writeOnly;
69     }
70
71     @Override
72     public void flush(boolean intermediate) {
73
74         if (!session.state.isWriteTransaction())
75             throw new IllegalStateException("Can only flush during transaction.");
76
77         gc();
78         
79     }
80     
81     final public void claim(VirtualGraph provider, Resource subject, Resource predicate, Resource object) throws ServiceException {
82         claim(provider, querySupport.getId(subject), querySupport.getId(predicate), querySupport.getId(object));
83     }
84
85     @Override
86     final public void claim(VirtualGraph provider, int subject, int predicate, int object)
87     throws ServiceException {
88
89         provider = session.getProvider(provider); 
90         if (writeOnly()) {
91             if (provider != null) {
92                 ((VirtualGraphImpl)provider).claim(subject, predicate, object);
93                 queryProcessor.updateStatements(subject, predicate);
94                 session.clientChanges.claim(subject, predicate, object);
95             } else {
96                 claimImpl2(subject, predicate, object);
97             }
98         } else {
99 //            queryProcessor.acquireWrite(writeState.getGraph());
100             if (provider != null) {
101                 ((VirtualGraphImpl)provider).claim(subject, predicate, object);
102                 queryProcessor.updateStatements(subject, predicate);
103                 session.clientChanges.claim(subject, predicate, object);
104             } else {
105                 claimImpl(subject, predicate, object);
106             }
107             queryProcessor.releaseWrite(session.writeState.getGraph());
108         }
109         
110     }
111     
112     @Override
113     public void setValue(VirtualGraph provider, Resource resource, byte[] value) throws ServiceException {
114
115         provider = session.getProvider(provider);
116         if (writeOnly()) {
117             if (provider != null) {
118                 ((VirtualGraphImpl)provider).claimValue(((ResourceImpl) resource).id, value, value.length);
119                 queryProcessor.updateValue(querySupport.getId(resource));
120                 session.clientChanges.claimValue(resource);
121             } else {
122                 try {
123                     addSetValue(((ResourceImpl) resource).id, value, value.length);
124                 } catch (DatabaseException e) {
125                     Logger.defaultLogError(e);
126                 }
127             }
128         } else {
129             if (provider != null) {
130                 ((VirtualGraphImpl)provider).claimValue(((ResourceImpl) resource).id, value, value.length);
131                 queryProcessor.updateValue(querySupport.getId(resource));
132                 session.clientChanges.claimValue(resource);
133             } else {
134                 try {
135                     addSetValue(((ResourceImpl) resource).id, value, value.length);
136                 } catch (DatabaseException e) {
137                     Logger.defaultLogError(e);
138                 }
139             }
140             queryProcessor.releaseWrite(session.writeState.getGraph());
141         }
142
143     }
144
145     @Override
146     public Resource createResource(VirtualGraph provider) throws DatabaseException {
147         if (provider != null) {
148             int newId = ((VirtualGraphImpl)provider).newResource(false);
149             return new ResourceImpl(session.resourceSupport, newId);
150         } else {
151             return session.getNewResource();
152         }
153     }
154
155     @Override
156     public Resource createResource(VirtualGraph provider, long clusterId)
157     throws DatabaseException {
158         assert (provider == null);
159         return session.getNewResource(clusterId);
160     }
161
162     @Override
163     public Resource createResource(VirtualGraph provider, Resource clusterSet)
164     throws DatabaseException {
165         assert(provider == null);
166         assert(clusterSet != null);
167         return session.getNewResource(clusterSet);
168     }
169
170     @Override
171     public void createClusterSet(VirtualGraph provider, Resource clusterSet)
172     throws DatabaseException {
173         assert(provider == null);
174         assert(clusterSet != null);
175         session.getNewClusterSet(clusterSet);
176     }
177
178     @Override
179     public boolean hasClusterSet(VirtualGraph dummy, Resource clusterSet)
180     throws ServiceException {
181         return session.containsClusterSet(clusterSet);
182     }
183
184     @Override
185     public Resource setDefaultClusterSet(Resource clusterSet)
186     throws ServiceException {
187         return session.setDefaultClusterSet4NewResource(clusterSet);
188     }
189     @Override
190     public void denyValue(VirtualGraph provider, Resource resource) throws ServiceException {
191         provider = session.getProvider(provider);
192         if (null == provider) {
193             int key = ((ResourceImpl)resource).id;
194             ClusterI cluster = session.clusterTable.getClusterByResourceKey(key);
195             if (cluster.getImmutable() && (session.serviceMode & SessionImplSocket.SERVICE_MODE_ALLOW) == 0)
196                 if(key != queryProcessor.getRootLibrary())
197                         throw new ImmutableException("Trying to modify immutable resource key=" + key);
198
199             try { 
200                 cluster.removeValue(key, session.clusterTranslator);
201             } catch (DatabaseException e) {
202                 Logger.defaultLogError(e);
203                 return;
204             }
205             queryProcessor.updateValue(key);
206             session.clientChanges.claimValue(resource);
207         } else {
208             ((VirtualGraphImpl)provider).denyValue(((ResourceImpl) resource).id);
209             queryProcessor.updateValue(querySupport.getId(resource));
210             session.clientChanges.claimValue(resource);
211         }
212         if (!writeOnly())
213             queryProcessor.releaseWrite(session.writeState.getGraph());
214     }
215
216
217     @Override
218     public boolean removeStatement(VirtualGraph provider, Resource subject, Resource predicate,
219             Resource object) throws ServiceException {
220         boolean ret = true;
221         if (writeOnly()) {
222             if (provider != null) {
223                 ((VirtualGraphImpl)provider).deny(querySupport.getId(subject), querySupport.getId(predicate), querySupport.getId(object));
224                 queryProcessor.updateStatements(querySupport.getId(subject), querySupport.getId(predicate));
225             } else {
226                 ret = removeStatement(querySupport.getId(subject), querySupport.getId(predicate), querySupport.getId(object));
227             }
228         } else {
229             if (provider != null) {
230 //                queryProcessor.acquireWrite(writeState.getGraph());
231                 ((VirtualGraphImpl)provider).deny(querySupport.getId(subject), querySupport.getId(predicate), querySupport.getId(object));
232                 queryProcessor.updateStatements(querySupport.getId(subject), querySupport.getId(predicate));
233                 queryProcessor.releaseWrite(session.writeState.getGraph());
234             } else {
235                 int sid = querySupport.getId(subject);
236                 int pid = querySupport.getId(predicate);
237                 int oid = querySupport.getId(object);
238                 if (sid < 0 || pid < 0 || oid < 0) {
239                     // One of the resources is virtual, cannot remove such
240                     // statement from persistent storage.
241                     return false;
242                 }
243 //                queryProcessor.acquireWrite(writeState.getGraph());
244                 ret = removeStatement(sid, pid, oid);
245                 queryProcessor.releaseWrite(session.writeState.getGraph());
246             }
247         }
248         session.clientChanges.deny(subject, predicate, object);
249         return ret;
250     }
251     
252     @Override
253     public synchronized void performWriteRequest(WriteGraph graph_, Write request) throws DatabaseException {
254         WriteGraphImpl graph = (WriteGraphImpl)graph_;
255 //        graph.state.barrier.inc();
256         try {
257             request.perform(graph);
258         } catch (Throwable t) {
259             t.printStackTrace();
260         }
261 //        graph.state.barrier.dec();
262 //        graph.waitAsync(request);
263         
264         queryProcessor.performDirtyUpdates(graph);
265         
266         // Do not fire metadata listeners for virtual requests
267         if(graph.getProvider() == null) {
268             //session.fireMetadataListeners(graph, session.clientChanges);
269             state.commitAndContinue(graph, session.clusterStream, request);
270             //session.clientChanges = new ClientChangesImpl(session);
271         }
272
273 //        graph.state.barrier.assertReady();
274         
275     }
276     
277     @Override
278     public synchronized <T> T performWriteRequest(WriteGraph graph_, WriteResult<T> request) throws DatabaseException {
279
280         WriteGraphImpl graph = (WriteGraphImpl)graph_;
281 //        graph.state.barrier.inc();
282         T result = null;
283         Throwable t = null;
284         try {
285             result = request.perform(graph);
286         } catch (Throwable t2) {
287             if(DebugException.DEBUG) new DebugException(t2).printStackTrace();
288             t = t2;
289         }
290         
291 //        graph.state.barrier.dec();
292 //        graph.waitAsync(request);
293         
294         queryProcessor.performDirtyUpdates(graph);
295
296         // Do not fire metadata listeners for virtual requests
297         if(graph.getProvider() == null) {
298             //session.fireMetadataListeners((WriteGraphImpl)graph, session.clientChanges);
299             state.commitAndContinue(graph, session.clusterStream, request);
300             //session.clientChanges = new ClientChangesImpl(session);
301         }
302         
303         if(t != null) {
304             if(t instanceof DatabaseException) throw (DatabaseException)t;
305             else throw new DatabaseException(t);
306         }
307         
308         return result;
309         
310     }
311
312     @Override
313     public synchronized void performWriteRequest(WriteGraph graph, WriteOnly request) throws DatabaseException {
314
315         session.acquireWriteOnly();
316         
317         request.perform(graph);
318         
319         ReadGraphImpl impl = (ReadGraphImpl)graph;
320         
321         queryProcessor.performDirtyUpdates(impl);
322
323         // Do not fire metadata listeners for virtual requests
324         if(graph.getProvider() == null) {
325             //session.fireMetadataListeners(impl, session.clientChanges);
326             state.commitAndContinue(session.writeState.getGraph(), session.clusterStream, request);
327             //session.clientChanges = new ClientChangesImpl(session);
328         }        
329         session.releaseWriteOnly(impl);
330         
331     }
332
333     
334     @Override
335     public void gc() {
336         if (MemWatch.isLowOnMemory()) {
337             session.clusterTable.gc();
338             queryProcessor.gc(0, Integer.MAX_VALUE);
339             System.gc();
340         }
341     }
342     
343     @Override
344     public void claimValue(VirtualGraph provider, Resource resource, byte[] value) throws DatabaseException {
345         claimValue(provider, ((ResourceImpl)resource).id, value, value.length);
346     }
347
348     @Override
349     public void claimValue(VirtualGraph provider, int resource, byte[] value, int length) throws DatabaseException {
350
351         provider = session.getProvider(provider);
352         if (writeOnly()) {
353             if (provider != null) {
354                 ((VirtualGraphImpl)provider).claimValue(resource, value, length);
355                 queryProcessor.updateValue(resource);
356                 session.clientChanges.claimValue(resource);
357             } else {
358                 addSetValue(resource, value, length);
359             }
360         } else {
361             if (provider != null) {
362                 ((VirtualGraphImpl)provider).claimValue(resource, value, length);
363                 queryProcessor.updateValue(resource);
364                 session.clientChanges.claimValue(resource);
365                 queryProcessor.releaseWrite(session.writeState.getGraph());
366             } else {
367                 try {
368                     addSetValue(resource, value, length);
369                 } catch (DatabaseException e) {
370                     throw e;
371                 } catch (Throwable t) {
372                     throw new DatabaseException(t);
373                 } finally {
374                     queryProcessor.releaseWrite(session.writeState.getGraph());
375                 }
376             }
377         }
378     }
379     
380     @Override
381     public void claimValue(VirtualGraph provider, Resource resource, ByteReader reader, int amount) throws DatabaseException {
382         claimValue(provider, resource, reader.readBytes(null, amount));
383     }
384
385     @Override
386     public <T> void addMetadata(Metadata data) throws ServiceException {
387         MetadataUtils.addMetadata(session, metadata, data);
388     }
389
390     @Override
391     public <T extends Metadata> T getMetadata(Class<T> clazz) throws ServiceException {
392         return MetadataUtils.getMetadata(session, metadata, clazz);
393     }
394
395     @Override
396     public TreeMap<String, byte[]> getMetadata() {
397         return metadata;
398     }
399
400     @Override
401     public void commitDone(WriteTraits writeTraits, long csid) {
402         metadata.clear();
403         if (this.writeTraits == writeTraits) {
404             session.graphSession.undoContext.clear();
405             this.writeTraits = null;
406         }
407 //        if (null != operation)
408 //            operation = null;
409     }
410     @Override
411     public int clearMetadata() {
412         int ret = metadata.size();
413         metadata.clear();
414         return ret;
415     }
416     @Override
417     public void clearUndoList(WriteTraits writeTraits) {
418         this.writeTraits = writeTraits;
419     }
420     @Override
421     public void startUndo() {
422         session.state.setCombine(false);
423     }
424     private WriteTraits writeTraits = null;
425     private void addSetValue(int subject, byte[] value, int length)
426     throws DatabaseException {
427
428         ClusterI cluster = session.clusterTable.getClusterByResourceKey(subject);
429         if (cluster.getImmutable() && (session.serviceMode & SessionImplSocket.SERVICE_MODE_ALLOW) == 0)
430                 if(subject != queryProcessor.getRootLibrary())
431                         throw new ImmutableException("Trying to modify immutable resource key=" + subject);
432         
433         ClusterI cluster2 = cluster.setValue(subject, value, length, session.clusterTranslator);
434         if (cluster2 != cluster)
435             session.clusterTable.replaceCluster(cluster2);
436         
437         session.clientChanges.claimValue(subject);
438         
439         if (cluster2.isWriteOnly())
440             return;
441
442         queryProcessor.updateValue(subject);
443
444     }
445
446     final private void claimImpl(int subject, int predicate, int object)
447     throws ServiceException {
448
449         assert (subject != 0);
450         assert (predicate != 0);
451         assert (object != 0);
452
453         ClusterImpl cluster = session.clusterTable.getClusterByResourceKey(subject);
454         assert (null != cluster);
455         if (cluster.getImmutable() && (session.serviceMode & SessionImplSocket.SERVICE_MODE_ALLOW) == 0)
456                 if(subject != queryProcessor.getRootLibrary())
457                         throw new ImmutableException("Trying to modify immutable resource key=" + subject);
458         try {
459             ClusterI c = cluster.addRelation(subject, predicate, object, session.clusterTranslator);
460             if (null != c && c != cluster)
461                 session.clusterTable.replaceCluster(c);
462         } catch (DatabaseException e) {
463             Logger.defaultLogError(e);
464             throw new RuntimeException(e);
465         }
466         queryProcessor.updateStatements(subject, predicate);
467         session.clientChanges.claim(subject, predicate, object);
468
469     }
470
471     final private void claimImpl2(int subject, int predicate, int object) {
472         
473         assert (subject != 0);
474         assert (predicate != 0);
475         assert (object != 0);
476
477         ClusterI cluster = session.clusterTable.getClusterByResourceKey(subject);
478         try {
479             ClusterI c = cluster.addRelation(subject, predicate, object, session.clusterTranslator);
480             if (null != c && c != cluster)
481                 session.clusterTable.replaceCluster(c);
482         } catch (DatabaseException e) {
483             Logger.defaultLogError(e);
484         }
485         if (cluster.isWriteOnly())
486             return;
487         queryProcessor.updateStatements(subject, predicate);
488
489     }
490     
491     private boolean removeStatement(int subject, int predicate, int object) throws ImmutableException {
492
493         assert (subject != 0);
494         assert (predicate != 0);
495         assert (object != 0);
496
497         ClusterI cluster = session.clusterTable.getClusterByResourceKey(subject);
498         assert (null != cluster);
499
500         if (cluster.getImmutable() && (session.serviceMode & SessionImplSocket.SERVICE_MODE_ALLOW) == 0)
501                 if(subject != queryProcessor.getRootLibrary())
502                         throw new ImmutableException("Trying to modify immutable resource key=" + subject);
503
504         try {
505             cluster.denyRelation(subject, predicate, object, session.clusterTranslator);
506         } catch (DatabaseException e) {
507             Logger.defaultLogError(e);
508             return false;
509         }
510         queryProcessor.updateStatements(subject, predicate);
511         return true;
512
513     }
514     
515 }