X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.db.impl%2Fsrc%2Forg%2Fsimantics%2Fdb%2Fimpl%2Fquery%2FCacheEntryBase.java;h=98e7f0d00554f1c3f351339d8aa4b891028966ae;hp=953f915b9dbc6b4c413c334b48d4feb7df94d6a0;hb=ae2e31aa5eb35410e5b2ce222d42421154f3fecc;hpb=969bd23cab98a79ca9101af33334000879fb60c5 diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/CacheEntryBase.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/CacheEntryBase.java index 953f915b9..98e7f0d00 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/CacheEntryBase.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/CacheEntryBase.java @@ -1,454 +1,539 @@ -/******************************************************************************* - * 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.common.utils.Logger; -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; - -abstract public class CacheEntryBase extends CacheEntry { - - // 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.defaultLogError("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) { - System.err.println("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; - } - - @Override - final public 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 - 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 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 getParents(QueryProcessor processor) { - - ArrayList result = new ArrayList(); - 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 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 boolean handleException(ReadGraphImpl graph, InternalProcedure 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(); - } - -} +/******************************************************************************* + * Copyright (c) 2007, 2018 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.Collection; +import java.util.Iterator; + +import org.simantics.databoard.Bindings; +import org.simantics.db.DevelopmentKeys; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.impl.graph.ReadGraphImpl; +import org.simantics.db.impl.procedure.InternalProcedure; +import org.simantics.utils.Development; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract 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 Object NO_RESULT = new Object() { public String toString() { return "NO_RESULT"; }}; + static protected Object INVALID_RESULT = new Object() { public String toString() { return "INVALID_RESULT"; }}; + +// // 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 REQUIRES_COMPUTATION = 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 = REQUIRES_COMPUTATION; + + 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 + Object result = NO_RESULT; + + final public boolean isFresh() { + return REQUIRES_COMPUTATION == statusOrException; + } + + public void setReady() { + assert(result != NO_RESULT); + statusOrException = READY; + } + + @Deprecated + final public boolean isReady() { + return READY == statusOrException || EXCEPTED == statusOrException; + } + + @Override + public void discard() { + if (Development.DEVELOPMENT) { + if(Development.getProperty(DevelopmentKeys.CACHE_ENTRY_STATE, Bindings.BOOLEAN)) { + System.err.println("[QUERY STATE]: discarded " + this); + } + } + statusOrException = DISCARDED; + } + + @Override + final public boolean isDiscarded() { + return DISCARDED == statusOrException; + } + + @Override + final public void refute() { + if (Development.DEVELOPMENT) { + if(Development.getProperty(DevelopmentKeys.CACHE_ENTRY_STATE, Bindings.BOOLEAN)) { + System.err.println("[QUERY STATE]: refuted " + this); + } + } + statusOrException = REQUIRES_COMPUTATION; + } + + @Override + final public boolean isRefuted() { + return REQUIRES_COMPUTATION == statusOrException; + } + + @Override + public void except(Throwable throwable) { + if (Development.DEVELOPMENT) { + if(Development.getProperty(DevelopmentKeys.CACHE_ENTRY_STATE, Bindings.BOOLEAN)) { + System.err.println("[QUERY STATE]: excepted " + this); + } + } + if(statusOrException != DISCARDED) { + statusOrException = EXCEPTED; + result = throwable; + } else { + LOGGER.warn("Cache entry got excepted status after being discarded: " + getClass().getSimpleName(), throwable); + result = throwable; + } + } + + 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 + public void setPending(QuerySupport querySupport) { + statusOrException = PENDING; + clearResult(querySupport); + } + + @Override + final public boolean isPending() { + return PENDING == statusOrException; + } + + final public boolean requiresComputation() { + return REQUIRES_COMPUTATION == 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 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 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 Collection> getParents(QueryProcessor processor) { + + ArrayList> result = new ArrayList>(); + 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> result) { + } + + protected String internalError() { + return toString() + " " + statusOrException + " " + result; + } + + + protected boolean handleException(ReadGraphImpl graph, IntProcedure procedure) throws DatabaseException { + if(isExcepted()) { + procedure.exception(graph, (Throwable)getResult()); + return true; + } else { + return false; + } + } + + protected boolean handleException(ReadGraphImpl graph, TripleIntProcedure procedure) throws DatabaseException { + if(isExcepted()) { + procedure.exception(graph, (Throwable)getResult()); + return true; + } else { + return false; + } + } + + protected boolean handleException(ReadGraphImpl graph, InternalProcedure procedure) throws DatabaseException { + 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(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(); + } + + public CacheEntryBase() { + } + + public String classId() { + return getClass().getName(); + } + + public void serializeKey(QuerySerializer serializer) { + throw new IllegalStateException("Cannot serialize query key for " + this); + } + + public void serializeValue(QuerySerializer serializer) { + throw new IllegalStateException("Cannot serialize query value for " + this); + } + + public void serializeParents(QuerySerializer serializer) { + Collection> ps = getParents(serializer.getQueryProcessor()); + int sizePos = serializer.writeUnknownSize(); + int actual = 0; + for(CacheEntry entry : ps) { + CacheEntryBase b = (CacheEntryBase)entry; + String cid = b.classId(); + if(cid == null) + continue; + serializer.serializeId(b.classId()); + b.serializeKey(serializer); + actual++; + } + serializer.setUnknownSize(sizePos, actual); + } + + public long cluster(QueryProcessor processor) { + throw new IllegalStateException("Cannot compute query cluster for " + this); + } + + public void serialize(QuerySerializer serializer) { + serializer.serializeId(classId()); + serializeKey(serializer); + serializeValue(serializer); + serializeParents(serializer); + } + +}