package com.sleepycat.je.log; import java.nio.ByteBuffer; import java.sql.Timestamp; import java.util.Calendar; import com.sleepycat.je.DatabaseException; import de.ovgu.cide.jakutil.*; /** * A FileHeader embodies the header information at the beginning of each log * file. */ public class FileHeader implements LoggableObject, LogReadable { private static final int LOG_VERSION=3; private long fileNum; private long lastEntryInPrevFileOffset; private Timestamp time; private int logVersion; FileHeader( long fileNum, long lastEntryInPrevFileOffset){ this.fileNum=fileNum; this.lastEntryInPrevFileOffset=lastEntryInPrevFileOffset; Calendar now=Calendar.getInstance(); time=new Timestamp(now.getTimeInMillis()); logVersion=LOG_VERSION; } /** * For logging only. */ public FileHeader(){ } /** * @return whether the file header has an old version number. * @throws DatabaseException if the header isn't valid. */ boolean validate( String fileName, long expectedFileNum) throws DatabaseException { if (fileNum != expectedFileNum) { throw new LogException("Wrong filenum in header for file " + fileName + " expected "+ expectedFileNum+ " got "+ fileNum); } return logVersion < LOG_VERSION; } /** * @return the offset of the last entry in the previous file. */ long getLastEntryInPrevFileOffset(){ return lastEntryInPrevFileOffset; } /** * @see LoggableObject#getLogType */ public LogEntryType getLogType(){ return LogEntryType.LOG_FILE_HEADER; } /** * @see LoggableObject#marshallOutsideWriteLatchCan 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 { } /** * A header is always a known size. */ static int entrySize(){ return LogUtils.getTimestampLogSize() + LogUtils.UNSIGNED_INT_BYTES + LogUtils.LONG_BYTES+ LogUtils.INT_BYTES; } /** * @see LoggableObject#getLogSize * @return number of bytes used to store this object */ public int getLogSize(){ return entrySize(); } /** * @see LoggableObject#writeToLogSerialize this object into the buffer. Update cksum with all * the bytes used by this object * @param logBuffer is the destination buffer */ public void writeToLog( ByteBuffer logBuffer){ LogUtils.writeTimestamp(logBuffer,time); LogUtils.writeUnsignedInt(logBuffer,fileNum); LogUtils.writeLong(logBuffer,lastEntryInPrevFileOffset); LogUtils.writeInt(logBuffer,logVersion); } /** * @see LogReadable#readFromLogInitialize this object from the data in itemBuf. * @param itemBuf the source buffer */ public void readFromLog( ByteBuffer logBuffer, byte entryTypeVersion) throws LogException { time=LogUtils.readTimestamp(logBuffer); fileNum=LogUtils.getUnsignedInt(logBuffer); lastEntryInPrevFileOffset=LogUtils.readLong(logBuffer); logVersion=LogUtils.readInt(logBuffer); if (logVersion > LOG_VERSION) { throw new LogException("Expected log version " + LOG_VERSION + " or earlier but found "+ logVersion+ " -- this version is not supported."); } } /** * @see LogReadable#dumpLog * @param sb destination string buffer * @param verbose if true, dump the full, verbose version */ public void dumpLog( StringBuffer sb, boolean verbose){ sb.append("<FileHeader num=\"0x"); sb.append(Long.toHexString(fileNum)); sb.append("\" lastEntryInPrevFileOffset=\"0x"); sb.append(Long.toHexString(lastEntryInPrevFileOffset)); sb.append("\" logVersion=\"0x"); sb.append(Integer.toHexString(logVersion)); sb.append("\" time=\"").append(time); sb.append("\"/>"); } /** * @see LogReadable#logEntryIsTransactional */ public boolean logEntryIsTransactional(){ return false; } /** * @see LogReadable#getTransactionId */ public long getTransactionId(){ return 0; } /** * Print in xml format */ public String toString(){ StringBuffer sb=new StringBuffer(); dumpLog(sb,true); return sb.toString(); } }