package com.sleepycat.je.tree;
import java.nio.ByteBuffer;
import java.util.Comparator;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.dbi.CursorImpl;
import com.sleepycat.je.dbi.DatabaseId;
import com.sleepycat.je.dbi.DatabaseImpl;
import com.sleepycat.je.dbi.DbConfigManager;
import com.sleepycat.je.dbi.MemoryBudget;
import com.sleepycat.je.log.LogEntryType;
import com.sleepycat.je.log.LogException;
import com.sleepycat.je.log.LogUtils;
import com.sleepycat.je.log.LoggableObject;
import de.ovgu.cide.jakutil.*;
/**
* A DBIN represents an Duplicate Bottom Internal Node in the JE tree.
*/
public final class DBIN extends BIN implements LoggableObject {
private static final String BEGIN_TAG="<dbin>";
private static final String END_TAG="</dbin>";
/**
* Full key for this set of duplicates.
*/
private byte[] dupKey;
public DBIN(){
super();
}
public DBIN( DatabaseImpl db, byte[] identifierKey, int maxEntriesPerNode, byte[] dupKey, int level){
super(db,identifierKey,maxEntriesPerNode,level);
this.dupKey=dupKey;
}
/**
* Create a new DBIN. Need this because we can't call newInstance() without
* getting a 0 node.
*/
protected IN createNewInstance( byte[] identifierKey, int maxEntries, int level){
return new DBIN(getDatabase(),identifierKey,maxEntries,dupKey,level);
}
protected int generateLevel( DatabaseId dbId, int newLevel){
return newLevel;
}
/**
* Return the comparator function to be used for DBINs. This is the user
* defined duplicate comparison function, if defined.
*/
public final Comparator getKeyComparator(){
return getDatabase().getDuplicateComparator();
}
/**
* Return the key for this duplicate set.
*/
public byte[] getDupKey(){
return dupKey;
}
/**
* Get the key (dupe or identifier) in child that is used to locate it in
* 'this' node.
*/
public byte[] getChildKey( IN child) throws DatabaseException {
return child.getIdentifierKey();
}
public byte[] selectKey( byte[] mainTreeKey, byte[] dupTreeKey){
return dupTreeKey;
}
/**
* Return the key for navigating through the duplicate tree.
*/
public byte[] getDupTreeKey(){
return getIdentifierKey();
}
/**
* Return the key for navigating through the main tree.
*/
public byte[] getMainTreeKey(){
return dupKey;
}
/**
* @return true if this node is a duplicate-bearing node type, false if
* otherwise.
*/
public boolean containsDuplicates(){
return true;
}
/**
* @return the log entry type to use for bin delta log entries.
*/
LogEntryType getBINDeltaType(){
return LogEntryType.LOG_DUP_BIN_DELTA;
}
public BINReference createReference(){
return new DBINReference(getNodeId(),getDatabase().getId(),getIdentifierKey(),dupKey);
}
protected boolean canBeAncestor( boolean targetContainsDuplicates){
return false;
}
/**
* @Override
*/
boolean hasNonLNChildren(){
return false;
}
/**
* The following four methods access the correct fields in a cursor
* depending on whether "this" is a BIN or DBIN. For BIN's, the
* CursorImpl.index and CursorImpl.bin fields should be used. For DBIN's,
* the CursorImpl.dupIndex and CursorImpl.dupBin fields should be used.
*/
BIN getCursorBIN( CursorImpl cursor){
return cursor.getDupBIN();
}
BIN getCursorBINToBeRemoved( CursorImpl cursor){
return cursor.getDupBINToBeRemoved();
}
int getCursorIndex( CursorImpl cursor){
return cursor.getDupIndex();
}
void setCursorBIN( CursorImpl cursor, BIN bin){
cursor.setDupBIN((DBIN)bin);
}
void setCursorIndex( CursorImpl cursor, int index){
cursor.setDupIndex(index);
}
boolean matchLNByNodeId( TreeLocation location, long nodeId) throws DatabaseException {
for (int i=0; i < getNEntries(); i++) {
LN ln=(LN)fetchTarget(i);
if (ln != null) {
if (ln.getNodeId() == nodeId) {
location.bin=this;
location.index=i;
location.lnKey=getKey(i);
location.childLsn=getLsn(i);
return true;
}
}
}
return false;
}
void accumulateStats( TreeWalkerStatsAccumulator acc){
acc.processDBIN(this,new Long(getNodeId()),getLevel());
}
public String beginTag(){
return BEGIN_TAG;
}
public String endTag(){
return END_TAG;
}
/**
* For unit test support:
* @return a string that dumps information about this IN, without
*/
public String dumpString( int nSpaces, boolean dumpTags){
StringBuffer sb=new StringBuffer();
sb.append(TreeUtils.indent(nSpaces));
sb.append(beginTag());
sb.append('\n');
sb.append(TreeUtils.indent(nSpaces + 2));
sb.append("<dupkey>");
sb.append(dupKey == null ? "" : Key.dumpString(dupKey,0));
sb.append("</dupkey>");
sb.append('\n');
sb.append(super.dumpString(nSpaces,false));
sb.append(TreeUtils.indent(nSpaces));
sb.append(endTag());
return sb.toString();
}
/**
* @see LoggableObject#getLogType
*/
public LogEntryType getLogType(){
return LogEntryType.LOG_DBIN;
}
/**
* @see LoggableObject#getLogSize
*/
public int getLogSize(){
int size=super.getLogSize();
size+=LogUtils.getByteArrayLogSize(dupKey);
return size;
}
/**
* @see LoggableObject#writeToLog
*/
public void writeToLog( ByteBuffer logBuffer){
super.writeToLog(logBuffer);
LogUtils.writeByteArray(logBuffer,dupKey);
}
/**
* @see BIN#readFromLog
*/
public void readFromLog( ByteBuffer itemBuffer, byte entryTypeVersion) throws LogException {
super.readFromLog(itemBuffer,entryTypeVersion);
dupKey=LogUtils.readByteArray(itemBuffer);
}
/**
* DBINS need to dump their dup key
*/
protected void dumpLogAdditional( StringBuffer sb){
super.dumpLogAdditional(sb);
sb.append(Key.dumpString(dupKey,0));
}
public String shortClassName(){
return "DBIN";
}
}