package com.sleepycat.je.log.entry; import java.nio.ByteBuffer; import com.sleepycat.je.DatabaseException; import com.sleepycat.je.dbi.DatabaseId; import com.sleepycat.je.log.LogEntryType; import com.sleepycat.je.log.LogUtils; import com.sleepycat.je.log.LoggableObject; import com.sleepycat.je.tree.Key; import com.sleepycat.je.tree.LN; import com.sleepycat.je.txn.Txn; import com.sleepycat.je.utilint.DbLsn; import de.ovgu.cide.jakutil.*; /** * LNLogEntry embodies all LN transactional log entries. * These entries contain: * <pre> * ln * databaseid * key * abortLsn -- if transactional * abortKnownDeleted -- if transactional * txn -- if transactional * </pre> */ public class LNLogEntry implements LogEntry, LoggableObject, NodeLogEntry { private LN ln; private DatabaseId dbId; private byte[] key; private long abortLsn=DbLsn.NULL_LSN; private boolean abortKnownDeleted; private Txn txn; private static final byte ABORT_KNOWN_DELETED_MASK=(byte)1; private Class logClass; private LogEntryType entryType; private long nodeId; private boolean isTransactional; public LNLogEntry( Class logClass, boolean isTransactional){ this.logClass=logClass; this.isTransactional=isTransactional; } public LNLogEntry( LogEntryType entryType, LN ln, DatabaseId dbId, byte[] key, long abortLsn, boolean abortKnownDeleted, Txn txn){ this.entryType=entryType; this.ln=ln; this.dbId=dbId; this.key=key; this.abortLsn=abortLsn; this.abortKnownDeleted=abortKnownDeleted; this.txn=txn; this.isTransactional=(txn != null); this.logClass=ln.getClass(); this.nodeId=ln.getNodeId(); } /** * @see LogEntry#readEntry */ public void readEntry( ByteBuffer entryBuffer, int entrySize, byte entryTypeVersion, boolean readFullItem) throws DatabaseException { try { if (readFullItem) { ln=(LN)logClass.newInstance(); ln.readFromLog(entryBuffer,entryTypeVersion); nodeId=ln.getNodeId(); dbId=new DatabaseId(); dbId.readFromLog(entryBuffer,entryTypeVersion); key=LogUtils.readByteArray(entryBuffer); if (isTransactional) { abortLsn=LogUtils.readLong(entryBuffer); if (DbLsn.getFileNumber(abortLsn) == DbLsn.getFileNumber(DbLsn.NULL_LSN)) { abortLsn=DbLsn.NULL_LSN; } abortKnownDeleted=((entryBuffer.get() & ABORT_KNOWN_DELETED_MASK) != 0) ? true : false; txn=new Txn(); txn.readFromLog(entryBuffer,entryTypeVersion); } } else { int endPosition=entryBuffer.position() + entrySize; nodeId=LogUtils.readLong(entryBuffer); entryBuffer.position(endPosition); ln=null; } } catch ( IllegalAccessException e) { throw new DatabaseException(e); } catch ( InstantiationException e) { throw new DatabaseException(e); } } /** * @see LogEntry#dumpEntry */ public StringBuffer dumpEntry( StringBuffer sb, boolean verbose){ ln.dumpLog(sb,verbose); dbId.dumpLog(sb,verbose); sb.append(Key.dumpString(key,0)); if (isTransactional) { if (abortLsn != DbLsn.NULL_LSN) { sb.append(DbLsn.toString(abortLsn)); } sb.append("<knownDeleted val=\""); sb.append(abortKnownDeleted ? "true" : "false"); sb.append("\"/>"); txn.dumpLog(sb,verbose); } return sb; } /** * @see LogEntry#getMainItem */ public Object getMainItem(){ return ln; } /** * @see LogEntry#clone */ public Object clone() throws CloneNotSupportedException { return super.clone(); } /** * @see LogEntry#isTransactional */ public boolean isTransactional(){ return isTransactional; } /** * @see LogEntry#getTransactionId */ public long getTransactionId(){ if (isTransactional) { return txn.getId(); } else { return 0; } } /** * @see NodeLogEntry#getNodeId */ public long getNodeId(){ return nodeId; } /** * @see LoggableObject#getLogType */ public LogEntryType getLogType(){ return entryType; } /** * @see LoggableObject#marshallOutsideWriteLatchAsk the ln if it can be marshalled outside the log write latch. */ public boolean marshallOutsideWriteLatch(){ return ln.marshallOutsideWriteLatch(); } /** * Returns true for a deleted LN to count it immediately as obsolete. * @see LoggableObject#countAsObsoleteWhenLogged */ public boolean countAsObsoleteWhenLogged(){ return ln.isDeleted(); } /** * For LN entries, we need to record the latest LSN for that node with the * owning transaction, within the protection of the log latch. This is a * callback for the log manager to do that recording. * @see LoggableObject#postLogWork */ public void postLogWork( long justLoggedLsn) throws DatabaseException { if (isTransactional) { txn.addLogInfo(justLoggedLsn); } } /** * @see LoggableObject#getLogSize */ public int getLogSize(){ int size=ln.getLogSize() + dbId.getLogSize() + LogUtils.getByteArrayLogSize(key); if (isTransactional) { size+=LogUtils.getLongLogSize(); size++; size+=txn.getLogSize(); } return size; } /** * @see LoggableObject#writeToLog */ public void writeToLog( ByteBuffer destBuffer){ ln.writeToLog(destBuffer); dbId.writeToLog(destBuffer); LogUtils.writeByteArray(destBuffer,key); if (isTransactional) { LogUtils.writeLong(destBuffer,abortLsn); byte aKD=0; if (abortKnownDeleted) { aKD|=ABORT_KNOWN_DELETED_MASK; } destBuffer.put(aKD); txn.writeToLog(destBuffer); } } public LN getLN(){ return ln; } public DatabaseId getDbId(){ return dbId; } public byte[] getKey(){ return key; } public byte[] getDupKey(){ if (ln.isDeleted()) { return null; } else { return ln.getData(); } } public long getAbortLsn(){ return abortLsn; } public boolean getAbortKnownDeleted(){ return abortKnownDeleted; } public Long getTxnId(){ if (isTransactional) { return new Long(txn.getId()); } else { return null; } } public Txn getUserTxn(){ if (isTransactional) { return txn; } else { return null; } } }