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