package com.sleepycat.je.tree; import java.nio.ByteBuffer; import com.sleepycat.je.DatabaseException; import com.sleepycat.je.cleaner.UtilizationTracker; import com.sleepycat.je.dbi.DatabaseImpl; import com.sleepycat.je.dbi.INList; import com.sleepycat.je.log.LogEntryType; import com.sleepycat.je.log.LogException; import com.sleepycat.je.log.LogReadable; import com.sleepycat.je.log.LogUtils; import com.sleepycat.je.log.LogWritable; import com.sleepycat.je.log.LoggableObject; import de.ovgu.cide.jakutil.*; /** * A Node contains all the common base information for any JE B-Tree node. */ public abstract class Node implements LoggableObject, LogReadable, LogWritable { public synchronized static void setLastNodeId( long id){ if (lastAllocatedId < id) { lastAllocatedId=id; } } private static long lastAllocatedId=0; private static final String BEGIN_TAG="<node>"; private static final String END_TAG="</node>"; private long nodeId; /** * Disallow use */ private Node(){ } /** * Create a new node, assigning it the next available node id. */ protected Node( boolean init){ if (init) { nodeId=getNextNodeId(); } } /** * Increment and return the next usable id. Must be synchronized. */ public static synchronized long getNextNodeId(){ return ++lastAllocatedId; } /** * Get the latest id, for checkpointing. */ public static synchronized long getLastId(){ return lastAllocatedId; } /** * Initialize a node that has been faulted in from the log */ public void postFetchInit( DatabaseImpl db, long sourceLsn) throws DatabaseException { } public long getNodeId(){ return nodeId; } void setNodeId( long nid){ nodeId=nid; } public void verify( byte[] maxKey) throws DatabaseException { } /** * @return true if this node is a duplicate-bearing node type, false * if otherwise. */ public boolean containsDuplicates(){ return false; } /** * Cover for LN's and just return 0 since they'll always be at the bottom * of the tree. */ int getLevel(){ return 0; } boolean matchLNByNodeId( TreeLocation location, long nodeId) throws DatabaseException { throw new DatabaseException("matchLNByNodeId called on non DIN/DBIN"); } /** * Add yourself to the in memory list if you're a type of node that * should belong. */ abstract void rebuildINList( INList inList) throws DatabaseException ; /** * Remove yourself from the in memory list if you're a type of node that * is put there. */ abstract void accountForSubtreeRemoval( INList inList, UtilizationTracker tracker) throws DatabaseException ; /** * @return true if you're part of a deletable subtree. */ abstract boolean isValidForDelete() throws DatabaseException ; /** * @return true if you're an IN in the search path */ abstract protected boolean isSoughtNode( long nid, boolean updateGeneration) throws DatabaseException ; /** * @return true if you can be the ancestor of the target IN. * Currently the determining factor is whether the target IN contains * duplicates. */ abstract protected boolean canBeAncestor( boolean targetContainsDuplicates); /** * Return the approximate size of this node in memory, if this * size should be included in it's parents memory accounting. * For example, all INs return 0, because they are accounted for * individually. LNs must return a count, they're not counted on * the INList. */ protected long getMemorySizeIncludedByParent(){ return 0; } /** * Default toString method at the root of the tree. */ public String toString(){ return this.dumpString(0,true); } private String beginTag(){ return BEGIN_TAG; } private String endTag(){ return END_TAG; } public void dump( int nSpaces){ System.out.print(dumpString(nSpaces,true)); } String dumpString( int nSpaces, boolean dumpTags){ StringBuffer self=new StringBuffer(); self.append(TreeUtils.indent(nSpaces)); if (dumpTags) { self.append(beginTag()); } self.append(nodeId); if (dumpTags) { self.append(endTag()); } return self.toString(); } public String shortDescription(){ return "<" + getType() + "/"+ getNodeId(); } public String getType(){ return getClass().getName(); } /** * @see LoggableObject#getLogType */ public abstract LogEntryType getLogType(); /** * @see LoggableObject#marshallOutsideWriteLatchBy default, nodes can be marshalled outside the log write latch. */ public boolean marshallOutsideWriteLatch(){ return true; } /** * @see LoggableObject#countAsObsoleteWhenLogged */ public boolean countAsObsoleteWhenLogged(){ return false; } /** * @see LoggableObject#postLogWork */ public void postLogWork( long justLoggedLsn) throws DatabaseException { } /** * @see LoggableObject#getLogSize */ public int getLogSize(){ return LogUtils.LONG_BYTES; } /** * @see LogWritable#writeToLog */ public void writeToLog( ByteBuffer logBuffer){ LogUtils.writeLong(logBuffer,nodeId); } /** * @see LogReadable#readFromLog */ public void readFromLog( ByteBuffer itemBuffer, byte entryTypeVersion) throws LogException { nodeId=LogUtils.readLong(itemBuffer); } /** * @see LogReadable#dumpLog */ public void dumpLog( StringBuffer sb, boolean verbose){ sb.append(BEGIN_TAG); sb.append(nodeId); sb.append(END_TAG); } }