-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.db.impl.query;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Iterator;\r
-\r
-import org.simantics.db.common.utils.Logger;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.impl.DebugPolicy;\r
-import org.simantics.db.impl.graph.ReadGraphImpl;\r
-import org.simantics.db.impl.procedure.InternalProcedure;\r
-\r
-abstract public class CacheEntryBase extends CacheEntry {\r
-\r
- // Default level is something that is not quite a prospect but still allows for ordering within CacheCollectionResult \r
- public static final short UNDEFINED_LEVEL = 5;\r
- \r
- public short level = UNDEFINED_LEVEL;\r
- public short age = 0;\r
- public int GCStatus = 0;\r
- \r
- final public static CacheEntryBase[] NONE = new CacheEntryBase[0];\r
-\r
- static private Object NO_RESULT = new Object();\r
- static protected Object INVALID_RESULT = new Object();\r
- \r
- // Just created\r
- static protected Object FRESH = new Object() { public String toString() { return "CREATED"; }};\r
- // Result is computed - no exception\r
- static protected Object READY = new Object() { public String toString() { return "READY"; }};\r
- // Computation is under way\r
- static protected Object PENDING = new Object() { public String toString() { return "PENDING"; }};\r
- // Entry is discarded and is waiting for garbage collect\r
- static protected Object DISCARDED = new Object() { public String toString() { return "DISCARDED"; }};\r
- // The result has been invalidated\r
- static protected Object REFUTED = new Object() { public String toString() { return "REFUTED"; }};\r
- // The computation has excepted - the exception is in the result\r
- static protected Object EXCEPTED = new Object() { public String toString() { return "EXCEPTED"; }};\r
-\r
- // This indicates the status of the entry\r
- public Object statusOrException = FRESH;\r
- \r
- private CacheEntry p1 = null;\r
- private Object p2OrParents = null;\r
- \r
- private int hash = 0;\r
- \r
- @Override\r
- final public int hashCode() {\r
- if(hash == 0) hash = makeHash();\r
- return hash;\r
- }\r
- \r
- abstract int makeHash();\r
- \r
- // This can be tested to see if the result is finished\r
- private Object result = NO_RESULT;\r
- \r
- final public boolean isFresh() {\r
- return FRESH == statusOrException;\r
- }\r
-\r
- public void setReady() {\r
- statusOrException = READY;\r
- }\r
-\r
- @Deprecated\r
- final public boolean isReady() {\r
- return READY == statusOrException || EXCEPTED == statusOrException;\r
- }\r
- \r
- @Override\r
- public void discard() {\r
- if(DebugPolicy.QUERY_STATE) System.out.println("[QUERY STATE]: discarded " + this);\r
- statusOrException = DISCARDED;\r
- }\r
- \r
- @Override\r
- final public boolean isDiscarded() {\r
- return DISCARDED == statusOrException;\r
- }\r
- \r
- @Override\r
- final public void refute() {\r
- if(DebugPolicy.QUERY_STATE) System.out.println("[QUERY STATE]: refuted " + this);\r
- statusOrException = REFUTED;\r
- }\r
- \r
- @Override\r
- final public boolean isRefuted() {\r
- return REFUTED == statusOrException;\r
- }\r
-\r
- @Override\r
- final public void except(Throwable t) {\r
- if(DebugPolicy.QUERY_STATE) System.out.println("[QUERY STATE]: excepted " + this);\r
- if(statusOrException != DISCARDED) {\r
- statusOrException = EXCEPTED;\r
- result = t;\r
- } else {\r
- Logger.defaultLogError("Cache entry got excepted status after being discarded: " + getClass().getSimpleName(), t);\r
- result = t;\r
- }\r
- }\r
- \r
- final public void checkAndThrow() throws DatabaseException {\r
- if(isExcepted()) {\r
- Throwable throwable = (Throwable)result;\r
- if(throwable instanceof DatabaseException) throw (DatabaseException)throwable;\r
- else throw new DatabaseException(throwable);\r
- }\r
- }\r
- \r
- @Override\r
- final public boolean isExcepted() {\r
- return EXCEPTED == statusOrException;\r
- }\r
-\r
- @Override\r
- final public void setPending() {\r
- statusOrException = PENDING;\r
- }\r
- \r
- @Override\r
- final public boolean isPending() {\r
- return PENDING == statusOrException;\r
- }\r
- \r
- final public boolean assertPending() {\r
- boolean result = isPending();\r
- if(!result) {\r
- System.err.println("Assertion failed, expected pending, got " + statusOrException);\r
- }\r
- return result;\r
- }\r
-\r
- final public boolean assertNotPending() {\r
- boolean result = !isPending();\r
- if(!result) {\r
- new Exception(this + ": Assertion failed, expected not pending, got " + statusOrException).printStackTrace();\r
- }\r
- return result;\r
- }\r
-\r
- final public boolean assertNotDiscarded() {\r
- boolean result = !isDiscarded();\r
- if(!result) {\r
- new Exception(this + ": Assertion failed, expected not discarded, got " + statusOrException).printStackTrace();\r
- }\r
- return result;\r
- }\r
-\r
- @Override\r
- public void setResult(Object result) {\r
- this.result = result;\r
- }\r
- \r
- @Override\r
- final public <T> T getResult() {\r
- assert(statusOrException != DISCARDED);\r
- return (T)result;\r
- }\r
- \r
- @Override\r
- public void clearResult(QuerySupport support) {\r
- setResult(NO_RESULT);\r
- }\r
- \r
- @Override\r
- final public void addParent(CacheEntry entry) {\r
- \r
- assert(entry != null);\r
- \r
- if(p1 == entry) {\r
- return;\r
- }\r
- if(p2OrParents == entry) {\r
- return;\r
- }\r
- if(p1 == null) {\r
- p1 = entry;\r
- } else if(p2OrParents == null) {\r
- p2OrParents = entry;\r
- } else if(p2OrParents instanceof QueryIdentityHashSet) {\r
- ((QueryIdentityHashSet)p2OrParents).add(entry);\r
- ((QueryIdentityHashSet)p2OrParents).purge();\r
- } else {\r
- CacheEntry tmp = (CacheEntry)p2OrParents;\r
- p2OrParents = new QueryIdentityHashSet(2);\r
- ((QueryIdentityHashSet)p2OrParents).add(tmp);\r
- ((QueryIdentityHashSet)p2OrParents).add(entry);\r
- }\r
- \r
- }\r
-\r
- @Override\r
- CacheEntry pruneFirstParents() {\r
-\r
- if(p1 == null) {\r
- // No parents\r
- return null;\r
- }\r
- \r
- if(!p1.isDiscarded()) {\r
- \r
- // First parent is still active\r
- return p1;\r
- \r
- } else {\r
- \r
- // Clear p1\r
- p1 = null;\r
- \r
- // First parent is discarded => look for more parents\r
- if(p2OrParents instanceof QueryIdentityHashSet) {\r
-\r
- QueryIdentityHashSet set = (QueryIdentityHashSet)p2OrParents;\r
- CacheEntry entry = set.removeDiscarded();\r
- if(entry == null) p2OrParents = null;\r
- p1 = entry;\r
- return p1;\r
-\r
- } else if(p2OrParents instanceof CacheEntry) {\r
- \r
- CacheEntry entry = (CacheEntry)p2OrParents;\r
- if(entry.isDiscarded()) {\r
- // Second entry is also discarded => all empty\r
- p2OrParents = null;\r
- return null;\r
- } else {\r
- p1 = entry;\r
- p2OrParents = null;\r
- return p1;\r
- }\r
- \r
- } else {\r
- \r
- // Nothing left\r
- return null;\r
- \r
- }\r
- \r
- }\r
- \r
- }\r
- \r
- @Override\r
- final public void removeParent(CacheEntry entry) {\r
- \r
- if(p1 == null) {\r
- if(p2OrParents != null) throw new Error("CacheEntryBase.removeParent: corrupted parents (p1 == null, while p2OrParents != null).");\r
- else throw new Error("CacheEntryBase.removeParent: no parents.");\r
- }\r
- if(p1 == entry) {\r
- if(p2OrParents == null) {\r
- p1 = null;\r
- } else if(p2OrParents instanceof QueryIdentityHashSet) {\r
- QueryIdentityHashSet set = (QueryIdentityHashSet)p2OrParents;\r
- int size = set.size();\r
- if(size == 0) {\r
- p1 = null;\r
- p2OrParents = null;\r
- } else if (size == 1) {\r
- CacheEntry next = set.iterator().next();\r
- p1 = next;\r
- set = null;\r
- } else if(set.size() == 2) {\r
- Iterator<CacheEntry> iterator = set.iterator();\r
- p1 = iterator.next();\r
- p2OrParents = iterator.next();\r
- } else {\r
- p1 = set.iterator().next();\r
- set.remove(p1);\r
- }\r
- } else {\r
- p1 = (CacheEntry)p2OrParents;\r
- p2OrParents = null;\r
- }\r
- \r
- } else if(p2OrParents.getClass() == QueryIdentityHashSet.class) {\r
- \r
- QueryIdentityHashSet set = (QueryIdentityHashSet)p2OrParents;\r
- boolean success = set.remove(entry);\r
- if(!success) {\r
- throw new Error("CacheEntryBase.removeParent: parent was not found.");\r
- }\r
- assert(set.size() >= 1);\r
- if(set.size() == 1) {\r
- p2OrParents = set.iterator().next();\r
- }\r
- \r
- } else {\r
- if(p2OrParents == entry) {\r
- p2OrParents = null;\r
- } else {\r
- throw new Error("CacheEntryBase.removeParent: had 2 parents but neither was removed.");\r
- }\r
- }\r
- }\r
-\r
- @Override\r
- final public boolean hasParents() {\r
- assert(statusOrException != DISCARDED);\r
- return p1 != null;\r
- }\r
- \r
- @Override\r
- final public Iterable<CacheEntry> getParents(QueryProcessor processor) {\r
-\r
- ArrayList<CacheEntry> result = new ArrayList<CacheEntry>();\r
- if(p1 != null) result.add(p1);\r
- if(p2OrParents != null) {\r
- if(p2OrParents instanceof QueryIdentityHashSet) {\r
- for(CacheEntry entry : (QueryIdentityHashSet)p2OrParents) {\r
- result.add(entry);\r
- }\r
- } else {\r
- result.add((CacheEntry)p2OrParents);\r
- }\r
- }\r
- fillImpliedParents(processor, result);\r
- return result;\r
- \r
- }\r
- \r
- @Override\r
- CacheEntry getFirstParent(QueryProcessor processor) {\r
- return p1;\r
- }\r
- \r
- @Override\r
- boolean moreThanOneParent(QueryProcessor processor) {\r
- return p2OrParents != null;\r
- }\r
- \r
- @Override\r
- int parentCount(QueryProcessor processor) {\r
- if(p2OrParents != null) {\r
- if(p2OrParents instanceof QueryIdentityHashSet) {\r
- return ((QueryIdentityHashSet)p2OrParents).size()+1;\r
- } else {\r
- return 2;\r
- }\r
- } else {\r
- return p1 != null ? 1 : 0;\r
- }\r
- \r
- }\r
- \r
- protected void fillImpliedParents(QueryProcessor processor, ArrayList<CacheEntry> result) {\r
- \r
- }\r
- \r
- protected String internalError() {\r
- return toString() + " " + statusOrException + " " + result;\r
- }\r
-\r
- \r
- protected boolean handleException(ReadGraphImpl graph, IntProcedure procedure) {\r
- if(isExcepted()) {\r
- procedure.exception(graph, (Throwable)getResult());\r
- return true;\r
- } else {\r
- return false;\r
- }\r
- }\r
- \r
- protected boolean handleException(ReadGraphImpl graph, TripleIntProcedure procedure) {\r
- if(isExcepted()) {\r
- procedure.exception(graph, (Throwable)getResult());\r
- return true;\r
- } else {\r
- return false;\r
- }\r
- }\r
-\r
- protected <T> boolean handleException(ReadGraphImpl graph, InternalProcedure<T> procedure) {\r
- if(isExcepted()) {\r
- procedure.exception(graph, (Throwable)getResult());\r
- return true;\r
- } else {\r
- return false;\r
- }\r
- }\r
- \r
- @Override\r
- boolean isImmutable(ReadGraphImpl graph) throws DatabaseException {\r
- return false;\r
- }\r
- \r
- @Override\r
- boolean shouldBeCollected() {\r
- return true;\r
- }\r
- \r
- @Override\r
- short getLevel() {\r
- return level;\r
- }\r
- \r
- @Override\r
- short setLevel(short level) {\r
- short existing = this.level;\r
- this.level = level;\r
- return existing;\r
- }\r
- \r
- @Override\r
- void prepareRecompute(QuerySupport querySupport) {\r
- setPending();\r
- clearResult(querySupport);\r
- }\r
- \r
- /*\r
- * \r
- * \r
- */\r
- @Override\r
- int getGCStatus() {\r
- return GCStatus;\r
- }\r
- \r
- @Override\r
- int setGCStatus(int status) {\r
- GCStatus = status;\r
- return GCStatus;\r
- }\r
- \r
- @Override\r
- void setGCStatusFlag(int flag, boolean value) {\r
- if(value) {\r
- GCStatus |= flag;\r
- } else {\r
- GCStatus &= ~flag;\r
- }\r
- }\r
- \r
- @Override\r
- public Object getOriginalRequest() {\r
- // This is the original request for all built-in queries\r
- return getQuery();\r
- }\r
- \r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.db.impl.query;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.impl.DebugPolicy;
+import org.simantics.db.impl.graph.ReadGraphImpl;
+import org.simantics.db.impl.procedure.InternalProcedure;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+abstract public class CacheEntryBase extends CacheEntry {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(CacheEntryBase.class);
+
+ // Default level is something that is not quite a prospect but still allows for ordering within CacheCollectionResult
+ public static final short UNDEFINED_LEVEL = 5;
+
+ public short level = UNDEFINED_LEVEL;
+ public short age = 0;
+ public int GCStatus = 0;
+
+ final public static CacheEntryBase[] NONE = new CacheEntryBase[0];
+
+ static private Object NO_RESULT = new Object();
+ static protected Object INVALID_RESULT = new Object();
+
+ // Just created
+ static protected Object FRESH = new Object() { public String toString() { return "CREATED"; }};
+ // Result is computed - no exception
+ static protected Object READY = new Object() { public String toString() { return "READY"; }};
+ // Computation is under way
+ static protected Object PENDING = new Object() { public String toString() { return "PENDING"; }};
+ // Entry is discarded and is waiting for garbage collect
+ static protected Object DISCARDED = new Object() { public String toString() { return "DISCARDED"; }};
+ // The result has been invalidated
+ static protected Object REFUTED = new Object() { public String toString() { return "REFUTED"; }};
+ // The computation has excepted - the exception is in the result
+ static protected Object EXCEPTED = new Object() { public String toString() { return "EXCEPTED"; }};
+
+ // This indicates the status of the entry
+ public Object statusOrException = FRESH;
+
+ private CacheEntry p1 = null;
+ private Object p2OrParents = null;
+
+ private int hash = 0;
+
+ @Override
+ final public int hashCode() {
+ if(hash == 0) hash = makeHash();
+ return hash;
+ }
+
+ abstract int makeHash();
+
+ // This can be tested to see if the result is finished
+ private Object result = NO_RESULT;
+
+ final public boolean isFresh() {
+ return FRESH == statusOrException;
+ }
+
+ public void setReady() {
+ statusOrException = READY;
+ }
+
+ @Deprecated
+ final public boolean isReady() {
+ return READY == statusOrException || EXCEPTED == statusOrException;
+ }
+
+ @Override
+ public void discard() {
+ if(DebugPolicy.QUERY_STATE) System.out.println("[QUERY STATE]: discarded " + this);
+ statusOrException = DISCARDED;
+ }
+
+ @Override
+ final public boolean isDiscarded() {
+ return DISCARDED == statusOrException;
+ }
+
+ @Override
+ final public void refute() {
+ if(DebugPolicy.QUERY_STATE) System.out.println("[QUERY STATE]: refuted " + this);
+ statusOrException = REFUTED;
+ }
+
+ @Override
+ final public boolean isRefuted() {
+ return REFUTED == statusOrException;
+ }
+
+ @Override
+ final public void except(Throwable t) {
+ if(DebugPolicy.QUERY_STATE) System.out.println("[QUERY STATE]: excepted " + this);
+ if(statusOrException != DISCARDED) {
+ statusOrException = EXCEPTED;
+ result = t;
+ } else {
+ LOGGER.warn("Cache entry got excepted status after being discarded: " + getClass().getSimpleName(), t);
+ result = t;
+ }
+ }
+
+ final public void checkAndThrow() throws DatabaseException {
+ if(isExcepted()) {
+ Throwable throwable = (Throwable)result;
+ if(throwable instanceof DatabaseException) throw (DatabaseException)throwable;
+ else throw new DatabaseException(throwable);
+ }
+ }
+
+ @Override
+ final public boolean isExcepted() {
+ return EXCEPTED == statusOrException;
+ }
+
+ @Override
+ final public void setPending() {
+ statusOrException = PENDING;
+ }
+
+ @Override
+ final public boolean isPending() {
+ return PENDING == statusOrException;
+ }
+
+ final public boolean assertPending() {
+ boolean result = isPending();
+ if(!result) {
+ LOGGER.warn("Assertion failed, expected pending, got " + statusOrException);
+ }
+ return result;
+ }
+
+ final public boolean assertNotPending() {
+ boolean result = !isPending();
+ if(!result) {
+ new Exception(this + ": Assertion failed, expected not pending, got " + statusOrException).printStackTrace();
+ }
+ return result;
+ }
+
+ final public boolean assertNotDiscarded() {
+ boolean result = !isDiscarded();
+ if(!result) {
+ new Exception(this + ": Assertion failed, expected not discarded, got " + statusOrException).printStackTrace();
+ }
+ return result;
+ }
+
+ @Override
+ public void setResult(Object result) {
+ this.result = result;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ final public <T> T getResult() {
+ assert(statusOrException != DISCARDED);
+ return (T)result;
+ }
+
+ @Override
+ public void clearResult(QuerySupport support) {
+ setResult(NO_RESULT);
+ }
+
+ @Override
+ final public void addParent(CacheEntry entry) {
+
+ assert(entry != null);
+
+ if(p1 == entry) {
+ return;
+ }
+ if(p2OrParents == entry) {
+ return;
+ }
+ if(p1 == null) {
+ p1 = entry;
+ } else if(p2OrParents == null) {
+ p2OrParents = entry;
+ } else if(p2OrParents instanceof QueryIdentityHashSet) {
+ ((QueryIdentityHashSet)p2OrParents).add(entry);
+ ((QueryIdentityHashSet)p2OrParents).purge();
+ } else {
+ CacheEntry tmp = (CacheEntry)p2OrParents;
+ p2OrParents = new QueryIdentityHashSet(2);
+ ((QueryIdentityHashSet)p2OrParents).add(tmp);
+ ((QueryIdentityHashSet)p2OrParents).add(entry);
+ }
+
+ }
+
+ @Override
+ CacheEntry pruneFirstParents() {
+
+ if(p1 == null) {
+ // No parents
+ return null;
+ }
+
+ if(!p1.isDiscarded()) {
+
+ // First parent is still active
+ return p1;
+
+ } else {
+
+ // Clear p1
+ p1 = null;
+
+ // First parent is discarded => look for more parents
+ if(p2OrParents instanceof QueryIdentityHashSet) {
+
+ QueryIdentityHashSet set = (QueryIdentityHashSet)p2OrParents;
+ CacheEntry entry = set.removeDiscarded();
+ if(entry == null) p2OrParents = null;
+ p1 = entry;
+ return p1;
+
+ } else if(p2OrParents instanceof CacheEntry) {
+
+ CacheEntry entry = (CacheEntry)p2OrParents;
+ if(entry.isDiscarded()) {
+ // Second entry is also discarded => all empty
+ p2OrParents = null;
+ return null;
+ } else {
+ p1 = entry;
+ p2OrParents = null;
+ return p1;
+ }
+
+ } else {
+
+ // Nothing left
+ return null;
+
+ }
+
+ }
+
+ }
+
+
+ @Override
+ void pruneParentSet() {
+ // First parent is discarded => look for more parents
+ if(p2OrParents instanceof QueryIdentityHashSet) {
+
+ QueryIdentityHashSet set = (QueryIdentityHashSet)p2OrParents;
+ set.removeDiscardedReally();
+ if(set.isEmpty()) p2OrParents = null;
+
+ } else if(p2OrParents instanceof CacheEntry) {
+
+ CacheEntry entry = (CacheEntry)p2OrParents;
+ if(entry.isDiscarded()) {
+ // Second entry is also discarded => all empty
+ p2OrParents = null;
+ }
+
+ } else {
+
+ // Nothing left
+
+ }
+ }
+
+ @Override
+ final public void removeParent(CacheEntry entry) {
+
+ if(p1 == null) {
+ if(p2OrParents != null) throw new Error("CacheEntryBase.removeParent: corrupted parents (p1 == null, while p2OrParents != null).");
+ else throw new Error("CacheEntryBase.removeParent: no parents.");
+ }
+ if(p1 == entry) {
+ if(p2OrParents == null) {
+ p1 = null;
+ } else if(p2OrParents instanceof QueryIdentityHashSet) {
+ QueryIdentityHashSet set = (QueryIdentityHashSet)p2OrParents;
+ int size = set.size();
+ if(size == 0) {
+ p1 = null;
+ p2OrParents = null;
+ } else if (size == 1) {
+ CacheEntry next = set.iterator().next();
+ p1 = next;
+ set = null;
+ } else if(set.size() == 2) {
+ Iterator<CacheEntry> iterator = set.iterator();
+ p1 = iterator.next();
+ p2OrParents = iterator.next();
+ } else {
+ p1 = set.iterator().next();
+ set.remove(p1);
+ }
+ } else {
+ p1 = (CacheEntry)p2OrParents;
+ p2OrParents = null;
+ }
+
+ } else if(p2OrParents.getClass() == QueryIdentityHashSet.class) {
+
+ QueryIdentityHashSet set = (QueryIdentityHashSet)p2OrParents;
+ boolean success = set.remove(entry);
+ if(!success) {
+ throw new Error("CacheEntryBase.removeParent: parent was not found.");
+ }
+ assert(set.size() >= 1);
+ if(set.size() == 1) {
+ p2OrParents = set.iterator().next();
+ }
+
+ } else {
+ if(p2OrParents == entry) {
+ p2OrParents = null;
+ } else {
+ throw new Error("CacheEntryBase.removeParent: had 2 parents but neither was removed.");
+ }
+ }
+ }
+
+ @Override
+ final public boolean hasParents() {
+ assert(statusOrException != DISCARDED);
+ return p1 != null;
+ }
+
+ @Override
+ final public Iterable<CacheEntry> getParents(QueryProcessor processor) {
+
+ ArrayList<CacheEntry> result = new ArrayList<CacheEntry>();
+ if(p1 != null) result.add(p1);
+ if(p2OrParents != null) {
+ if(p2OrParents instanceof QueryIdentityHashSet) {
+ for(CacheEntry entry : (QueryIdentityHashSet)p2OrParents) {
+ result.add(entry);
+ }
+ } else {
+ result.add((CacheEntry)p2OrParents);
+ }
+ }
+ fillImpliedParents(processor, result);
+ return result;
+
+ }
+
+ @Override
+ CacheEntry getFirstParent(QueryProcessor processor) {
+ return p1;
+ }
+
+ @Override
+ boolean moreThanOneParent(QueryProcessor processor) {
+ return p2OrParents != null;
+ }
+
+ @Override
+ int parentCount(QueryProcessor processor) {
+ if(p2OrParents != null) {
+ if(p2OrParents instanceof QueryIdentityHashSet) {
+ return ((QueryIdentityHashSet)p2OrParents).size()+1;
+ } else {
+ return 2;
+ }
+ } else {
+ return p1 != null ? 1 : 0;
+ }
+
+ }
+
+ protected void fillImpliedParents(QueryProcessor processor, ArrayList<CacheEntry> result) {
+
+ }
+
+ protected String internalError() {
+ return toString() + " " + statusOrException + " " + result;
+ }
+
+
+ protected boolean handleException(ReadGraphImpl graph, IntProcedure procedure) {
+ if(isExcepted()) {
+ procedure.exception(graph, (Throwable)getResult());
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ protected boolean handleException(ReadGraphImpl graph, TripleIntProcedure procedure) {
+ if(isExcepted()) {
+ procedure.exception(graph, (Throwable)getResult());
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ protected <T> boolean handleException(ReadGraphImpl graph, InternalProcedure<T> procedure) {
+ if(isExcepted()) {
+ procedure.exception(graph, (Throwable)getResult());
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ boolean isImmutable(ReadGraphImpl graph) throws DatabaseException {
+ return false;
+ }
+
+ @Override
+ boolean shouldBeCollected() {
+ return true;
+ }
+
+ @Override
+ short getLevel() {
+ return level;
+ }
+
+ @Override
+ short setLevel(short level) {
+ short existing = this.level;
+ this.level = level;
+ return existing;
+ }
+
+ @Override
+ void prepareRecompute(QuerySupport querySupport) {
+ setPending();
+ clearResult(querySupport);
+ }
+
+ /*
+ *
+ *
+ */
+ @Override
+ int getGCStatus() {
+ return GCStatus;
+ }
+
+ @Override
+ int setGCStatus(int status) {
+ GCStatus = status;
+ return GCStatus;
+ }
+
+ @Override
+ void setGCStatusFlag(int flag, boolean value) {
+ if(value) {
+ GCStatus |= flag;
+ } else {
+ GCStatus &= ~flag;
+ }
+ }
+
+ @Override
+ public Object getOriginalRequest() {
+ // This is the original request for all built-in queries
+ return getQuery();
+ }
+
+}