1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
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
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.db.impl.query;
14 import java.util.ArrayList;
15 import java.util.Iterator;
17 import org.simantics.db.common.utils.Logger;
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;
23 abstract public class CacheEntryBase extends CacheEntry {
25 // Default level is something that is not quite a prospect but still allows for ordering within CacheCollectionResult
26 public static final short UNDEFINED_LEVEL = 5;
28 public short level = UNDEFINED_LEVEL;
30 public int GCStatus = 0;
32 final public static CacheEntryBase[] NONE = new CacheEntryBase[0];
34 static private Object NO_RESULT = new Object();
35 static protected Object INVALID_RESULT = new Object();
38 static protected Object FRESH = new Object() { public String toString() { return "CREATED"; }};
39 // Result is computed - no exception
40 static protected Object READY = new Object() { public String toString() { return "READY"; }};
41 // Computation is under way
42 static protected Object PENDING = new Object() { public String toString() { return "PENDING"; }};
43 // Entry is discarded and is waiting for garbage collect
44 static protected Object DISCARDED = new Object() { public String toString() { return "DISCARDED"; }};
45 // The result has been invalidated
46 static protected Object REFUTED = new Object() { public String toString() { return "REFUTED"; }};
47 // The computation has excepted - the exception is in the result
48 static protected Object EXCEPTED = new Object() { public String toString() { return "EXCEPTED"; }};
50 // This indicates the status of the entry
51 public Object statusOrException = FRESH;
53 private CacheEntry p1 = null;
54 private Object p2OrParents = null;
59 final public int hashCode() {
60 if(hash == 0) hash = makeHash();
64 abstract int makeHash();
66 // This can be tested to see if the result is finished
67 private Object result = NO_RESULT;
69 final public boolean isFresh() {
70 return FRESH == statusOrException;
73 public void setReady() {
74 statusOrException = READY;
78 final public boolean isReady() {
79 return READY == statusOrException || EXCEPTED == statusOrException;
83 public void discard() {
84 if(DebugPolicy.QUERY_STATE) System.out.println("[QUERY STATE]: discarded " + this);
85 statusOrException = DISCARDED;
89 final public boolean isDiscarded() {
90 return DISCARDED == statusOrException;
94 final public void refute() {
95 if(DebugPolicy.QUERY_STATE) System.out.println("[QUERY STATE]: refuted " + this);
96 statusOrException = REFUTED;
100 final public boolean isRefuted() {
101 return REFUTED == statusOrException;
105 final public void except(Throwable t) {
106 if(DebugPolicy.QUERY_STATE) System.out.println("[QUERY STATE]: excepted " + this);
107 if(statusOrException != DISCARDED) {
108 statusOrException = EXCEPTED;
111 Logger.defaultLogError("Cache entry got excepted status after being discarded: " + getClass().getSimpleName(), t);
116 final public void checkAndThrow() throws DatabaseException {
118 Throwable throwable = (Throwable)result;
119 if(throwable instanceof DatabaseException) throw (DatabaseException)throwable;
120 else throw new DatabaseException(throwable);
125 final public boolean isExcepted() {
126 return EXCEPTED == statusOrException;
130 final public void setPending() {
131 statusOrException = PENDING;
135 final public boolean isPending() {
136 return PENDING == statusOrException;
139 final public boolean assertPending() {
140 boolean result = isPending();
142 System.err.println("Assertion failed, expected pending, got " + statusOrException);
147 final public boolean assertNotPending() {
148 boolean result = !isPending();
150 new Exception(this + ": Assertion failed, expected not pending, got " + statusOrException).printStackTrace();
155 final public boolean assertNotDiscarded() {
156 boolean result = !isDiscarded();
158 new Exception(this + ": Assertion failed, expected not discarded, got " + statusOrException).printStackTrace();
164 public void setResult(Object result) {
165 this.result = result;
169 final public <T> T getResult() {
170 assert(statusOrException != DISCARDED);
175 public void clearResult(QuerySupport support) {
176 setResult(NO_RESULT);
180 final public void addParent(CacheEntry entry) {
182 assert(entry != null);
187 if(p2OrParents == entry) {
192 } else if(p2OrParents == null) {
194 } else if(p2OrParents instanceof QueryIdentityHashSet) {
195 ((QueryIdentityHashSet)p2OrParents).add(entry);
196 ((QueryIdentityHashSet)p2OrParents).purge();
198 CacheEntry tmp = (CacheEntry)p2OrParents;
199 p2OrParents = new QueryIdentityHashSet(2);
200 ((QueryIdentityHashSet)p2OrParents).add(tmp);
201 ((QueryIdentityHashSet)p2OrParents).add(entry);
207 CacheEntry pruneFirstParents() {
214 if(!p1.isDiscarded()) {
216 // First parent is still active
224 // First parent is discarded => look for more parents
225 if(p2OrParents instanceof QueryIdentityHashSet) {
227 QueryIdentityHashSet set = (QueryIdentityHashSet)p2OrParents;
228 CacheEntry entry = set.removeDiscarded();
229 if(entry == null) p2OrParents = null;
233 } else if(p2OrParents instanceof CacheEntry) {
235 CacheEntry entry = (CacheEntry)p2OrParents;
236 if(entry.isDiscarded()) {
237 // Second entry is also discarded => all empty
258 final public void removeParent(CacheEntry entry) {
261 if(p2OrParents != null) throw new Error("CacheEntryBase.removeParent: corrupted parents (p1 == null, while p2OrParents != null).");
262 else throw new Error("CacheEntryBase.removeParent: no parents.");
265 if(p2OrParents == null) {
267 } else if(p2OrParents instanceof QueryIdentityHashSet) {
268 QueryIdentityHashSet set = (QueryIdentityHashSet)p2OrParents;
269 int size = set.size();
273 } else if (size == 1) {
274 CacheEntry next = set.iterator().next();
277 } else if(set.size() == 2) {
278 Iterator<CacheEntry> iterator = set.iterator();
279 p1 = iterator.next();
280 p2OrParents = iterator.next();
282 p1 = set.iterator().next();
286 p1 = (CacheEntry)p2OrParents;
290 } else if(p2OrParents.getClass() == QueryIdentityHashSet.class) {
292 QueryIdentityHashSet set = (QueryIdentityHashSet)p2OrParents;
293 boolean success = set.remove(entry);
295 throw new Error("CacheEntryBase.removeParent: parent was not found.");
297 assert(set.size() >= 1);
298 if(set.size() == 1) {
299 p2OrParents = set.iterator().next();
303 if(p2OrParents == entry) {
306 throw new Error("CacheEntryBase.removeParent: had 2 parents but neither was removed.");
312 final public boolean hasParents() {
313 assert(statusOrException != DISCARDED);
318 final public Iterable<CacheEntry> getParents(QueryProcessor processor) {
320 ArrayList<CacheEntry> result = new ArrayList<CacheEntry>();
321 if(p1 != null) result.add(p1);
322 if(p2OrParents != null) {
323 if(p2OrParents instanceof QueryIdentityHashSet) {
324 for(CacheEntry entry : (QueryIdentityHashSet)p2OrParents) {
328 result.add((CacheEntry)p2OrParents);
331 fillImpliedParents(processor, result);
337 CacheEntry getFirstParent(QueryProcessor processor) {
342 boolean moreThanOneParent(QueryProcessor processor) {
343 return p2OrParents != null;
347 int parentCount(QueryProcessor processor) {
348 if(p2OrParents != null) {
349 if(p2OrParents instanceof QueryIdentityHashSet) {
350 return ((QueryIdentityHashSet)p2OrParents).size()+1;
355 return p1 != null ? 1 : 0;
360 protected void fillImpliedParents(QueryProcessor processor, ArrayList<CacheEntry> result) {
364 protected String internalError() {
365 return toString() + " " + statusOrException + " " + result;
369 protected boolean handleException(ReadGraphImpl graph, IntProcedure procedure) {
371 procedure.exception(graph, (Throwable)getResult());
378 protected boolean handleException(ReadGraphImpl graph, TripleIntProcedure procedure) {
380 procedure.exception(graph, (Throwable)getResult());
387 protected <T> boolean handleException(ReadGraphImpl graph, InternalProcedure<T> procedure) {
389 procedure.exception(graph, (Throwable)getResult());
397 boolean isImmutable(ReadGraphImpl graph) throws DatabaseException {
402 boolean shouldBeCollected() {
412 short setLevel(short level) {
413 short existing = this.level;
419 void prepareRecompute(QuerySupport querySupport) {
421 clearResult(querySupport);
434 int setGCStatus(int status) {
440 void setGCStatusFlag(int flag, boolean value) {
449 public Object getOriginalRequest() {
450 // This is the original request for all built-in queries