]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/ReadEntry.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.db.impl / src / org / simantics / db / impl / query / ReadEntry.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2018 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.db.impl.query;
13
14 import org.simantics.db.AsyncReadGraph;
15 import org.simantics.db.exception.DatabaseException;
16 import org.simantics.db.impl.graph.ReadGraphImpl;
17 import org.simantics.db.procedure.AsyncProcedure;
18 import org.simantics.db.request.Read;
19 import org.simantics.db.request.ReadExt;
20 import org.simantics.db.request.RequestFlags;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23
24 public final class ReadEntry<T> extends CacheEntryBase<AsyncProcedure<T>> implements AsyncProcedure<T> {
25
26     private static final Logger LOGGER = LoggerFactory.getLogger(ReadEntry.class);
27
28     protected Read<T> id;
29
30     public ReadEntry(Read<T> request) {
31         this.id = request;
32     }
33
34     @Override
35     int makeHash() {
36         return id.hashCode();
37     }
38
39     @Override
40     public Object getOriginalRequest() {
41         return id;
42     }
43
44     @Override
45     public void discard() {
46         super.discard();
47         setResult(null);
48     }
49
50     @Override
51     final public Query getQuery() {
52
53         return new Query() {
54
55             @Override
56             public void recompute(ReadGraphImpl graph) {
57
58                 try {
59
60                     T result = id.perform(graph);
61                     setResult(result);
62                     setReady();
63
64                 } catch (Throwable t) {
65
66                     except(t);
67
68                 }
69
70             }
71
72             @Override
73             public void removeEntry(QueryProcessor processor) {
74                 processor.cache.remove(ReadEntry.this);
75             }
76
77             @Override
78             public int type() {
79                 if (id instanceof ReadExt) {
80                     return ((ReadExt) id).getType();
81                 } else {
82                     return RequestFlags.INVALIDATE;
83                 }
84             }
85
86             @Override
87             public String toString() {
88                 if (id == null)
89                     return "DISCARDED";
90                 else
91                     return id.toString() + statusOrException;
92             }
93
94         };
95
96     }
97
98     public static <T> T computeForEach(ReadGraphImpl graph, Read<T> request, ReadEntry<T> entry,
99             AsyncProcedure<T> procedure_, boolean needsToBlock) throws DatabaseException {
100
101         AsyncProcedure<T> procedure = entry != null ? entry : procedure_;
102
103         ReadGraphImpl queryGraph = graph.withParent(entry, null, needsToBlock);
104         queryGraph.asyncBarrier.inc();
105
106         ReadGraphImpl executeGraph = graph.withParent(graph.parent, null, needsToBlock);
107         executeGraph.asyncBarrier.inc();
108         
109         try {
110
111             // This throws
112             T result = request.perform(queryGraph);
113
114             if(procedure != null) procedure.execute(executeGraph, result);
115             return (T)result;
116
117         } catch (DatabaseException e) {
118
119             if(procedure != null) procedure.exception(executeGraph, e);
120             throw e;
121
122         } catch (Throwable t) {
123
124             DatabaseException dbe = new DatabaseException(t);
125             if(procedure != null) procedure.exception(executeGraph, dbe);
126             throw dbe;
127
128         } finally {
129
130             queryGraph.asyncBarrier.dec();
131
132             try {
133             
134                 if (entry != null) {
135                     // This also throws so must dec barrier finally
136                     entry.performFromCache(executeGraph, procedure_);
137                 }
138             
139             } finally {
140  
141                 executeGraph.asyncBarrier.dec();
142                 if(needsToBlock)
143                     executeGraph.asyncBarrier.waitBarrier(procedure, executeGraph);
144
145             }
146                 
147  
148         }
149
150     }
151
152     public Object performFromCache(ReadGraphImpl graph, AsyncProcedure<T> procedure) throws DatabaseException {
153
154         AsyncProcedure<T> proc = (AsyncProcedure<T>) procedure;
155
156         if (isExcepted()) {
157                 if(proc != null) {
158                     try {
159                         proc.exception(graph, (Throwable) getResult());
160                     } catch (Throwable t) {
161                         LOGGER.error("performFromCache proc.exception failed", t);
162                     }
163                 }
164                 Throwable t = (Throwable) getResult();
165                 if(t instanceof DatabaseException) {
166                     throw (DatabaseException)t;
167                 } else {
168                     throw new DatabaseException(t);
169                 }
170         } else {
171                 if(proc != null) {
172                     try {
173                         proc.execute(graph, (T) getResult());
174                     } catch (Throwable t) {
175                         LOGGER.error("performFromCache proc.execute failed", t);
176                     }
177                 }
178                 return (T)getResult();
179         }
180
181     }
182
183     @Override
184     public String toString() {
185         if (id == null)
186             return "DISCARDED";
187         else
188             return id.toString() + " - " + statusOrException;
189     }
190
191     public Object get(ReadGraphImpl graph, AsyncProcedure<T> procedure) throws DatabaseException {
192         if (procedure != null)
193             performFromCache(graph, procedure);
194         checkAndThrow();
195         return getResult();
196     }
197
198     @Override
199     boolean isImmutable(ReadGraphImpl graph) throws DatabaseException {
200         if (id instanceof ReadExt) {
201             return ((ReadExt) id).isImmutable(graph);
202         }
203         return false;
204     }
205
206     @Override
207     public void execute(AsyncReadGraph graph, T result) {
208         setResult(result);
209         setReady();
210     }
211
212     @Override
213     public void exception(AsyncReadGraph graph, Throwable throwable) {
214         except(throwable);
215     }
216
217     @Override
218     public String classId() {
219         return null;
220     }
221
222 }