package com.sleepycat.je.tree;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.dbi.DatabaseId;
import com.sleepycat.je.dbi.DatabaseImpl;
import com.sleepycat.je.dbi.EnvironmentImpl;
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.LoggableObject;
import com.sleepycat.je.utilint.DbLsn;
import de.ovgu.cide.jakutil.*;
/**
* BINDelta contains the information needed to create a partial (delta) BIN log
* entry. It also knows how to combine a full BIN log entry and a delta to
* generate a new BIN.
*/
public class BINDelta implements LoggableObject, LogReadable {
private DatabaseId dbId;
private long lastFullLsn;
private List deltas;
private LogEntryType logEntryType;
/**
* Read a BIN and create the deltas.
*/
public BINDelta( BIN bin){
lastFullLsn=bin.getLastFullVersion();
dbId=bin.getDatabaseId();
deltas=new ArrayList();
logEntryType=bin.getBINDeltaType();
for (int i=0; i < bin.getNEntries(); i++) {
if (bin.isDirty(i)) {
deltas.add(new DeltaInfo(bin.getKey(i),bin.getLsn(i),bin.getState(i)));
}
}
}
/**
* For instantiating from the log.
*/
public BINDelta(){
dbId=new DatabaseId();
lastFullLsn=DbLsn.NULL_LSN;
deltas=new ArrayList();
}
/**
* @return a count of deltas for this BIN.
*/
int getNumDeltas(){
return deltas.size();
}
/**
* @return the dbId for this BIN.
*/
public DatabaseId getDbId(){
return dbId;
}
/**
* @return the last full version of this BIN
*/
public long getLastFullLsn(){
return lastFullLsn;
}
/**
* Create a BIN by starting with the full version and applying the deltas.
*/
public BIN reconstituteBIN( EnvironmentImpl env) throws DatabaseException {
BIN fullBIN=(BIN)env.getLogManager().get(lastFullLsn);
DatabaseImpl db=env.getDbMapTree().getDb(dbId);
fullBIN.setDatabase(db);
fullBIN.setLastFullLsn(lastFullLsn);
this.hook612(fullBIN);
for (int i=0; i < deltas.size(); i++) {
DeltaInfo info=(DeltaInfo)deltas.get(i);
int foundIndex=fullBIN.findEntry(info.getKey(),true,false);
if (foundIndex >= 0 && (foundIndex & IN.EXACT_MATCH) != 0) {
foundIndex&=~IN.EXACT_MATCH;
if (info.isKnownDeleted()) {
fullBIN.setKnownDeleted(foundIndex);
}
else {
fullBIN.updateEntry(foundIndex,info.getLsn(),info.getState());
}
}
else {
if (!info.isKnownDeleted()) {
ChildReference entry=new ChildReference(null,info.getKey(),info.getLsn(),info.getState());
boolean insertOk=fullBIN.insertEntry(entry);
assert insertOk;
}
}
}
fullBIN.setGeneration(0);
this.hook611(fullBIN);
return fullBIN;
}
public LogEntryType getLogType(){
return logEntryType;
}
/**
* @see LoggableObject#marshallOutsideWriteLatchCan be marshalled outside the log write latch.
*/
public boolean marshallOutsideWriteLatch(){
return true;
}
/**
* @see LoggableObject#countAsObsoleteWhenLogged
*/
public boolean countAsObsoleteWhenLogged(){
return false;
}
public void postLogWork( long justLoggedLsn){
}
public void readFromLog( ByteBuffer itemBuffer, byte entryTypeVersion) throws LogException {
dbId.readFromLog(itemBuffer,entryTypeVersion);
lastFullLsn=LogUtils.readLong(itemBuffer);
int numDeltas=LogUtils.readInt(itemBuffer);
for (int i=0; i < numDeltas; i++) {
DeltaInfo info=new DeltaInfo();
info.readFromLog(itemBuffer,entryTypeVersion);
deltas.add(info);
}
}
public int getLogSize(){
int size=dbId.getLogSize() + LogUtils.LONG_BYTES + LogUtils.INT_BYTES;
for (int i=0; i < deltas.size(); i++) {
DeltaInfo info=(DeltaInfo)deltas.get(i);
size+=info.getLogSize();
}
return size;
}
public void writeToLog( ByteBuffer logBuffer){
dbId.writeToLog(logBuffer);
LogUtils.writeLong(logBuffer,lastFullLsn);
LogUtils.writeInt(logBuffer,deltas.size());
for (int i=0; i < deltas.size(); i++) {
DeltaInfo info=(DeltaInfo)deltas.get(i);
info.writeToLog(logBuffer);
}
}
public void dumpLog( StringBuffer sb, boolean verbose){
dbId.dumpLog(sb,verbose);
sb.append("<lastFullLsn>");
sb.append(DbLsn.toString(lastFullLsn));
sb.append("</lastFullLsn>");
sb.append("<deltas size=\"").append(deltas.size()).append("\"/>");
for (int i=0; i < deltas.size(); i++) {
DeltaInfo info=(DeltaInfo)deltas.get(i);
info.dumpLog(sb,verbose);
}
}
/**
* @see LogReadable#logEntryIsTransactional
*/
public boolean logEntryIsTransactional(){
return false;
}
/**
* @see LogReadable#getTransactionId
*/
public long getTransactionId(){
return 0;
}
protected void hook611( BIN fullBIN) throws DatabaseException {
}
protected void hook612( BIN fullBIN) throws DatabaseException {
}
}