001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: FileHeader.java,v 1.38.2.3 2008/01/07 15:14:13 cwl Exp $
007: */
008:
009: package com.sleepycat.je.log;
010:
011: import java.nio.ByteBuffer;
012: import java.sql.Timestamp;
013: import java.util.Calendar;
014:
015: import com.sleepycat.je.DatabaseException;
016:
017: /**
018: * A FileHeader embodies the header information at the beginning of each log
019: * file.
020: */
021: public class FileHeader implements Loggable {
022:
023: /*
024: * Version 3
025: * ---------
026: * [12328] Add main and dupe tree fanout values for DatabaseImpl.
027: * [12557] Add IN LSN array compression.
028: * [11597] Add a change to FileSummaryLNs: obsolete offset tracking was
029: * added and multiple records are stored for a single file rather than a
030: * single record. Each record contains the offsets that were tracked since
031: * the last record was written.
032: * [11597] Add the full obsolete LSN in LNLogEntry.
033: *
034: * Version 4
035: * ---------
036: * [#14422] Bump MapLN version from 1 to 2. Instead of a String for the
037: * comparator class name, store either a serialized string or Comparator.
038: *
039: * Version 5
040: * ---------
041: * [#15195] FileSummaryLN version 3. Add FileSummary.obsoleteLNSize and
042: * obsoleteLNSizeCounted fields.
043: */
044: private static final int LOG_VERSION = 5;
045:
046: /*
047: * fileNum is the number of file, starting at 0. An unsigned int, so stored
048: * in a long in memory, but in 4 bytes on disk
049: */
050: private long fileNum;
051: private long lastEntryInPrevFileOffset;
052: private Timestamp time;
053: private int logVersion;
054:
055: FileHeader(long fileNum, long lastEntryInPrevFileOffset) {
056: this .fileNum = fileNum;
057: this .lastEntryInPrevFileOffset = lastEntryInPrevFileOffset;
058: Calendar now = Calendar.getInstance();
059: time = new Timestamp(now.getTimeInMillis());
060: logVersion = LOG_VERSION;
061: }
062:
063: /**
064: * For logging only.
065: */
066: public FileHeader() {
067: }
068:
069: public int getLogVersion() {
070: return logVersion;
071: }
072:
073: /**
074: * @return whether the file header has an old version number.
075: *
076: * @throws DatabaseException if the header isn't valid.
077: */
078: boolean validate(String fileName, long expectedFileNum)
079: throws DatabaseException {
080:
081: if (fileNum != expectedFileNum) {
082: throw new LogException("Wrong filenum in header for file "
083: + fileName + " expected " + expectedFileNum
084: + " got " + fileNum);
085: }
086:
087: return logVersion < LOG_VERSION;
088: }
089:
090: /**
091: * @return the offset of the last entry in the previous file.
092: */
093: long getLastEntryInPrevFileOffset() {
094: return lastEntryInPrevFileOffset;
095: }
096:
097: /*
098: * Logging support
099: */
100:
101: /**
102: * A header is always a known size. Is public for unit testing.
103: */
104: public static int entrySize() {
105: return LogUtils.getTimestampLogSize() + // time
106: LogUtils.UNSIGNED_INT_BYTES + // file number
107: LogUtils.LONG_BYTES + // lastEntryInPrevFileOffset
108: LogUtils.INT_BYTES; // logVersion
109: }
110:
111: /**
112: * @see Loggable#getLogSize
113: * @return number of bytes used to store this object
114: */
115: public int getLogSize() {
116: return entrySize();
117: }
118:
119: /**
120: * @see Loggable#writeToLog
121: * Serialize this object into the buffer. Update cksum with all
122: * the bytes used by this object
123: * @param logBuffer is the destination buffer
124: */
125: public void writeToLog(ByteBuffer logBuffer) {
126: LogUtils.writeTimestamp(logBuffer, time);
127: LogUtils.writeUnsignedInt(logBuffer, fileNum);
128: LogUtils.writeLong(logBuffer, lastEntryInPrevFileOffset);
129: LogUtils.writeInt(logBuffer, logVersion);
130: }
131:
132: /**
133: * @see Loggable#readFromLog
134: * Initialize this object from the data in itemBuf.
135: * @param itemBuf the source buffer
136: */
137: public void readFromLog(ByteBuffer logBuffer, byte entryTypeVersion)
138: throws LogException {
139: time = LogUtils.readTimestamp(logBuffer);
140: fileNum = LogUtils.getUnsignedInt(logBuffer);
141: lastEntryInPrevFileOffset = LogUtils.readLong(logBuffer);
142: logVersion = LogUtils.readInt(logBuffer);
143: if (logVersion > LOG_VERSION) {
144: throw new LogException("Expected log version "
145: + LOG_VERSION + " or earlier but found "
146: + logVersion + " -- this version is not supported.");
147: }
148: }
149:
150: /**
151: * @see Loggable#dumpLog
152: * @param sb destination string buffer
153: * @param verbose if true, dump the full, verbose version
154: */
155: public void dumpLog(StringBuffer sb, boolean verbose) {
156: sb.append("<FileHeader num=\"0x");
157: sb.append(Long.toHexString(fileNum));
158: sb.append("\" lastEntryInPrevFileOffset=\"0x");
159: sb.append(Long.toHexString(lastEntryInPrevFileOffset));
160: sb.append("\" logVersion=\"0x");
161: sb.append(Integer.toHexString(logVersion));
162: sb.append("\" time=\"").append(time);
163: sb.append("\"/>");
164: }
165:
166: /**
167: * @see Loggable#getTransactionId
168: */
169: public long getTransactionId() {
170: return 0;
171: }
172:
173: /**
174: * Print in xml format
175: */
176: public String toString() {
177: StringBuffer sb = new StringBuffer();
178: dumpLog(sb, true);
179: return sb.toString();
180: }
181: }
|