]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/CacheEntryBase.java
First changes
[simantics/platform.git] / bundles / org.simantics.db.impl / src / org / simantics / db / impl / query / CacheEntryBase.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 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 java.util.ArrayList;
15 import java.util.Iterator;
16
17 import org.simantics.db.AsyncReadGraph;
18 import org.simantics.db.exception.DatabaseException;
19 import org.simantics.db.impl.DebugPolicy;
20 import org.simantics.db.impl.graph.ReadGraphImpl;
21 import org.simantics.db.impl.procedure.InternalProcedure;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24
25 abstract public class CacheEntryBase extends CacheEntry {
26
27     private static final Logger LOGGER = LoggerFactory.getLogger(CacheEntryBase.class);
28     
29         // Default level is something that is not quite a prospect but still allows for ordering within CacheCollectionResult 
30         public static final short UNDEFINED_LEVEL = 5;
31         
32         public short level = UNDEFINED_LEVEL;
33         public short age = 0;
34         public int GCStatus = 0;
35         
36     final public static CacheEntryBase[] NONE = new CacheEntryBase[0];
37
38         static private Object NO_RESULT = new Object();
39         static protected Object INVALID_RESULT = new Object();
40         
41         // Just created
42     static protected Object FRESH = new Object() { public String toString() { return "CREATED"; }};
43     // Result is computed - no exception
44     static protected Object READY = new Object() { public String toString() { return "READY"; }};
45     // Computation is under way
46     static protected Object PENDING = new Object() { public String toString() { return "PENDING"; }};
47     // Entry is discarded and is waiting for garbage collect
48     static protected Object DISCARDED = new Object() { public String toString() { return "DISCARDED"; }};
49     // The result has been invalidated
50     static protected Object REFUTED = new Object() { public String toString() { return "REFUTED"; }};
51     // The computation has excepted - the exception is in the result
52     static protected Object EXCEPTED = new Object() { public String toString() { return "EXCEPTED"; }};
53
54     // This indicates the status of the entry
55     public Object statusOrException = FRESH;
56     
57     private CacheEntry p1 = null;
58     private Object p2OrParents = null;
59     
60     private int hash = 0;
61     
62     @Override
63     final public int hashCode() {
64         if(hash == 0) hash = makeHash();
65         return hash;
66     }
67     
68     abstract int makeHash();
69     
70     // This can be tested to see if the result is finished
71     private Object result = NO_RESULT;
72     
73     final public boolean isFresh() {
74         return FRESH == statusOrException;
75     }
76
77     public void setReady() {
78         statusOrException = READY;
79     }
80
81     @Deprecated
82     final public boolean isReady() {
83         return READY == statusOrException || EXCEPTED == statusOrException;
84     }
85     
86     @Override
87     public void discard() {
88         if(DebugPolicy.QUERY_STATE) System.out.println("[QUERY STATE]: discarded " + this);
89         statusOrException = DISCARDED;
90     }
91     
92     @Override
93     final public boolean isDiscarded() {
94         return DISCARDED == statusOrException;
95     }
96     
97     @Override
98     final public void refute() {
99         if(DebugPolicy.QUERY_STATE) System.out.println("[QUERY STATE]: refuted " + this);
100         statusOrException = REFUTED;
101     }
102     
103     @Override
104     final public boolean isRefuted() {
105         return REFUTED == statusOrException;
106     }
107
108     @Override
109     final public void except(Throwable t) {
110         if(DebugPolicy.QUERY_STATE) System.out.println("[QUERY STATE]: excepted " + this);
111         if(statusOrException != DISCARDED) {
112                 statusOrException = EXCEPTED;
113                 result = t;
114         } else {
115                 LOGGER.warn("Cache entry got excepted status after being discarded: " + getClass().getSimpleName(), t);
116                 result = t;
117         }
118     }
119     
120     final public void checkAndThrow() throws DatabaseException {
121         if(isExcepted()) {
122             Throwable throwable = (Throwable)result;
123             if(throwable instanceof DatabaseException) throw (DatabaseException)throwable;
124             else throw new DatabaseException(throwable);
125         }
126     }
127     
128     @Override
129     final public boolean isExcepted() {
130         return EXCEPTED == statusOrException;
131     }
132
133     @Override
134     final public void setPending() {
135         statusOrException = PENDING;
136     }
137     
138     @Override
139     final public boolean isPending() {
140         return PENDING == statusOrException;
141     }
142     
143     final public boolean assertPending() {
144         boolean result = isPending();
145         if(!result) {
146                 LOGGER.warn("Assertion failed, expected pending, got " + statusOrException);
147         }
148         return result;
149     }
150
151     final public boolean assertNotPending() {
152         boolean result = !isPending();
153         if(!result) {
154                 new Exception(this +  ": Assertion failed, expected not pending, got " + statusOrException).printStackTrace();
155         }
156         return result;
157     }
158
159     final public boolean assertNotDiscarded() {
160         boolean result = !isDiscarded();
161         if(!result) {
162                 new Exception(this +  ": Assertion failed, expected not discarded, got " + statusOrException).printStackTrace();
163         }
164         return result;
165     }
166
167     @Override
168     public void setResult(Object result) {
169         this.result = result;
170     }
171     
172     @SuppressWarnings("unchecked")
173     @Override
174     final public <T> T getResult() {
175         assert(statusOrException != DISCARDED);
176         return (T)result;
177     }
178     
179     @Override
180     public void clearResult(QuerySupport support) {
181         setResult(NO_RESULT);
182     }
183     
184     @Override
185     final public void addParent(CacheEntry entry) {
186          
187         assert(entry != null);
188         
189         if(p1 == entry) {
190                 return;
191         }
192         if(p2OrParents == entry) {
193                 return;
194         }
195         if(p1 == null) {
196                 p1 = entry;
197         } else if(p2OrParents == null) {
198                 p2OrParents = entry;
199         } else if(p2OrParents instanceof QueryIdentityHashSet) {
200             ((QueryIdentityHashSet)p2OrParents).add(entry);
201             ((QueryIdentityHashSet)p2OrParents).purge();
202         } else {
203             CacheEntry tmp = (CacheEntry)p2OrParents;
204             p2OrParents = new QueryIdentityHashSet(2);
205             ((QueryIdentityHashSet)p2OrParents).add(tmp);
206             ((QueryIdentityHashSet)p2OrParents).add(entry);
207         }
208         
209     }
210
211     @Override
212     CacheEntry pruneFirstParents() {
213
214         if(p1 == null) {
215                 // No parents
216                 return null;
217         }
218         
219         if(!p1.isDiscarded()) {
220                 
221                 // First parent is still active
222                 return p1;
223                 
224         } else {
225                 
226                 // Clear p1
227                 p1 = null;
228                 
229                 // First parent is discarded => look for more parents
230                 if(p2OrParents instanceof QueryIdentityHashSet) {
231
232                         QueryIdentityHashSet set = (QueryIdentityHashSet)p2OrParents;
233                         CacheEntry entry = set.removeDiscarded();
234                         if(entry == null) p2OrParents = null;
235                         p1 = entry;
236                         return p1;
237
238                 } else if(p2OrParents instanceof CacheEntry) {
239                         
240                         CacheEntry entry = (CacheEntry)p2OrParents;
241                         if(entry.isDiscarded()) {
242                                 // Second entry is also discarded => all empty
243                                 p2OrParents = null;
244                                 return null;
245                         } else {
246                                 p1 = entry;
247                                 p2OrParents = null;
248                                 return p1;
249                         }
250                         
251                 } else {
252                 
253                         // Nothing left
254                         return null;
255                         
256                 }
257                 
258         }
259         
260     }
261     
262     @Override
263     final public void removeParent(CacheEntry entry) {
264        
265         if(p1 == null) {
266             if(p2OrParents != null) throw new Error("CacheEntryBase.removeParent: corrupted parents (p1 == null, while p2OrParents != null).");
267             else throw new Error("CacheEntryBase.removeParent: no parents.");
268         }
269         if(p1 == entry) {
270             if(p2OrParents == null) {
271                 p1 = null;
272             } else if(p2OrParents instanceof QueryIdentityHashSet) {
273                 QueryIdentityHashSet set = (QueryIdentityHashSet)p2OrParents;
274                 int size = set.size();
275                 if(size == 0) {
276                     p1 = null;
277                     p2OrParents = null;
278                 } else if (size == 1) {
279                     CacheEntry next = set.iterator().next();
280                     p1 = next;
281                     set = null;
282                 } else if(set.size() == 2) {
283                     Iterator<CacheEntry> iterator = set.iterator();
284                     p1 = iterator.next();
285                     p2OrParents = iterator.next();
286                 } else {
287                     p1 = set.iterator().next();
288                     set.remove(p1);
289                 }
290             } else {
291                 p1 = (CacheEntry)p2OrParents;
292                 p2OrParents = null;
293             }
294             
295         } else if(p2OrParents.getClass() == QueryIdentityHashSet.class) {
296             
297             QueryIdentityHashSet set = (QueryIdentityHashSet)p2OrParents;
298             boolean success = set.remove(entry);
299             if(!success) {
300                 throw new Error("CacheEntryBase.removeParent: parent was not found.");
301             }
302             assert(set.size() >= 1);
303             if(set.size() == 1) {
304                 p2OrParents = set.iterator().next();
305             }
306             
307         } else {
308             if(p2OrParents == entry) {
309                 p2OrParents = null;
310             } else {
311                 throw new Error("CacheEntryBase.removeParent: had 2 parents but neither was removed.");
312             }
313         }
314     }
315
316     @Override
317     final public boolean hasParents() {
318         assert(statusOrException != DISCARDED);
319         return p1 != null;
320     }
321     
322     @Override
323         final public Iterable<CacheEntry> getParents(QueryProcessor processor) {
324
325                 ArrayList<CacheEntry> result = new ArrayList<CacheEntry>();
326                 if(p1 != null) result.add(p1);
327                 if(p2OrParents != null) {
328                 if(p2OrParents instanceof QueryIdentityHashSet) {
329                         for(CacheEntry entry : (QueryIdentityHashSet)p2OrParents) {
330                                 result.add(entry);
331                         }
332                 } else {
333                         result.add((CacheEntry)p2OrParents);
334                 }
335                 }
336                 fillImpliedParents(processor, result);
337                 return result;
338                 
339         }
340     
341     @Override
342     CacheEntry getFirstParent(QueryProcessor processor) {
343         return p1;
344     }
345     
346     @Override
347     boolean moreThanOneParent(QueryProcessor processor) {
348         return p2OrParents != null;
349     }
350     
351     @Override
352     int parentCount(QueryProcessor processor) {
353         if(p2OrParents != null) {
354                 if(p2OrParents instanceof QueryIdentityHashSet) {
355                         return ((QueryIdentityHashSet)p2OrParents).size()+1;
356                 } else {
357                         return 2;
358                 }
359         } else {
360                 return p1 != null ? 1 : 0;
361         }
362         
363     }
364     
365     protected void fillImpliedParents(QueryProcessor processor, ArrayList<CacheEntry> result) {
366         
367     }
368     
369     protected String internalError() {
370         return toString() + " " + statusOrException + " " + result;
371     }
372
373     
374     protected boolean handleException(ReadGraphImpl graph, IntProcedure procedure) {
375         if(isExcepted()) {
376                 procedure.exception(graph, (Throwable)getResult());
377                 return true;
378         } else {
379                 return false;
380         }
381     }
382     
383     protected boolean handleException(ReadGraphImpl graph, TripleIntProcedure procedure) {
384         if(isExcepted()) {
385                 procedure.exception(graph, (Throwable)getResult());
386                 return true;
387         } else {
388                 return false;
389         }
390     }
391
392     protected <T> boolean handleException(ReadGraphImpl graph, InternalProcedure<T> procedure) {
393         if(isExcepted()) {
394                 procedure.exception(graph, (Throwable)getResult());
395                 return true;
396         } else {
397                 return false;
398         }
399     }
400     
401     @Override
402     boolean isImmutable(ReadGraphImpl graph) throws DatabaseException {
403         return false;
404     }
405     
406     @Override
407     boolean shouldBeCollected() {
408         return true;
409     }
410     
411     @Override
412     short getLevel() {
413         return level;
414     }
415     
416     @Override
417     short setLevel(short level) {
418         short existing = this.level;
419         this.level = level;
420         return existing;
421     }
422     
423     @Override
424     void prepareRecompute(QuerySupport querySupport) {
425                 setPending();
426                 clearResult(querySupport);
427     }
428     
429     /*
430      * 
431      * 
432      */
433     @Override
434     int getGCStatus() {
435         return GCStatus;
436     }
437     
438     @Override
439     int setGCStatus(int status) {
440         GCStatus = status;
441         return GCStatus;
442     }
443     
444     @Override
445     void setGCStatusFlag(int flag, boolean value) {
446         if(value) {
447                 GCStatus |= flag;
448         } else {
449                 GCStatus &= ~flag;
450         }
451     }
452     
453     @Override
454     public Object getOriginalRequest() {
455         // This is the original request for all built-in queries
456         return getQuery();
457     }
458     
459 //    abstract public void addOrSet(AsyncReadGraph graph, Object item);
460 //    abstract public void except(AsyncReadGraph graph, Throwable t);
461     
462     //abstract public void perform(AsyncReadGraph graph, Object query, Object procedure);
463     
464 }