001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: LogEntryType.java,v 1.76.2.4 2008/01/07 15:14:13 cwl Exp $
007: */
008:
009: package com.sleepycat.je.log;
010:
011: import java.util.HashSet;
012: import java.util.Set;
013:
014: import com.sleepycat.je.DatabaseException;
015: import com.sleepycat.je.log.entry.BINDeltaLogEntry;
016: import com.sleepycat.je.log.entry.DeletedDupLNLogEntry;
017: import com.sleepycat.je.log.entry.INLogEntry;
018: import com.sleepycat.je.log.entry.LNLogEntry;
019: import com.sleepycat.je.log.entry.LogEntry;
020: import com.sleepycat.je.log.entry.SingleItemEntry;
021:
022: /**
023: * LogEntryType is an enumeration of all log entry types.
024: *
025: * <p>When adding a new version of a log entry type, make sure the
026: * corresponding LogEntry instance is capable of reading in older versions from
027: * the log. The LogEntry instance must be sure that older versions are
028: * converted in memory into a correct instance of the newest version, so when
029: * that LogEntry object is written again as the result of migration, eviction,
030: * the resulting new log entry conforms to the requirements of the new version.
031: * If context objects are required for data conversion, the conversion can be
032: * done in the Node.postFetchInit method.</p>
033: */
034: public class LogEntryType {
035:
036: /* w
037: * Collection of log entry type classes, used to read the log. Note that
038: * this must be declared before any instances of LogEntryType, since the
039: * constructor uses this map. Each statically defined LogEntryType should
040: * register itself with this collection.
041: */
042: private static final int MAX_TYPE_NUM = 27;
043:
044: private static LogEntryType[] LOG_TYPES = new LogEntryType[MAX_TYPE_NUM];
045:
046: /*
047: * Enumeration of log entry types. The log entry type represents the 2
048: * byte field that starts every log entry. The top byte is the log type,
049: * the bottom byte holds the version value, provisional bit, and
050: * replicated bit.
051: *
052: * Log type (8 bits)
053: * (Provisional (1 bit) Replicated (1 bit) Version (6 bits)
054: *
055: * The top byte (log type) identifies the type and can be used to
056: * lookup the LogEntryType object, while the bottom byte has
057: * information about the entry (instance) of this type. The bottom
058: * byte is effectively entry header information that is common to
059: * all types and is managed by static methods in this class.
060: *
061: * The provisional bit can be set for any log type in the log. It's an
062: * indication to recovery that the entry shouldn't be processed when
063: * rebuilding the tree. It's used to ensure the atomic logging of multiple
064: * entries.
065: *
066: * The replicated bit should only be set for log types where
067: * isTypeReplicated is true. This means that this particular log entry
068: * did get broadcast to the replication group, and bears a VLSN tag.
069: */
070:
071: /* Node types */
072: public static final LogEntryType LOG_LN_TRANSACTIONAL = new LogEntryType(
073: (byte) 1, (byte) 0, "LN_TX", new LNLogEntry(
074: com.sleepycat.je.tree.LN.class), true, // isTransactional
075: true, // marshallOutsideLatch
076: true); // isTypeReplicated
077:
078: public static final LogEntryType LOG_LN = new LogEntryType(
079: (byte) 2, (byte) 0, "LN", new LNLogEntry(
080: com.sleepycat.je.tree.LN.class), false, // isTransactional
081: true, // marshallOutsideLatch
082: false);// isTypeReplicated
083:
084: public static final LogEntryType LOG_MAPLN_TRANSACTIONAL = new LogEntryType(
085: (byte) 3, (byte) 2, "MapLN_TX", new LNLogEntry(
086: com.sleepycat.je.tree.MapLN.class), true, // isTransactional
087: true, // marshallOutsideLatch
088: true); // isTypeReplicated
089:
090: public static final LogEntryType LOG_MAPLN = new LogEntryType(
091: (byte) 4, (byte) 2, "MapLN", new LNLogEntry(
092: com.sleepycat.je.tree.MapLN.class), false, // isTransactional
093: true, // marshallOutsideLatch
094: false);// isTypeReplicated
095:
096: public static final LogEntryType LOG_NAMELN_TRANSACTIONAL = new LogEntryType(
097: (byte) 5, (byte) 0, "NameLN_TX", new LNLogEntry(
098: com.sleepycat.je.tree.NameLN.class), true, // isTransactional
099: true, // marshallOutsideLatch
100: true); // isTypeReplicated
101:
102: public static final LogEntryType LOG_NAMELN = new LogEntryType(
103: (byte) 6, (byte) 0, "NameLN", new LNLogEntry(
104: com.sleepycat.je.tree.NameLN.class), false, // isTransactional
105: true, // marshallOutsideLatch
106: false);// isTypeReplicated
107:
108: public static final LogEntryType LOG_DEL_DUPLN_TRANSACTIONAL = new LogEntryType(
109: (byte) 7, (byte) 0, "DelDupLN_TX",
110: new DeletedDupLNLogEntry(), true, // isTransactional
111: true, // marshallOutsideLatch
112: true); // isTypeReplicated
113:
114: public static final LogEntryType LOG_DEL_DUPLN = new LogEntryType(
115: (byte) 8, (byte) 0, "DelDupLN", new DeletedDupLNLogEntry(),
116: false, // isTransactional
117: true, // marshallOutsideLatch
118: false);// isTypeReplicated
119:
120: public static final LogEntryType LOG_DUPCOUNTLN_TRANSACTIONAL = new LogEntryType(
121: (byte) 9, (byte) 0, "DupCountLN_TX", new LNLogEntry(
122: com.sleepycat.je.tree.DupCountLN.class), true, // isTransactional
123: true, // marshallOutsideLatch
124: true); // isTypeReplicated
125:
126: public static final LogEntryType LOG_DUPCOUNTLN = new LogEntryType(
127: (byte) 10, (byte) 0, "DupCountLN", new LNLogEntry(
128: com.sleepycat.je.tree.DupCountLN.class), false, // isTransactional
129: true, // marshallOutsideLatch
130: false);// isTypeReplicated
131:
132: public static final LogEntryType LOG_FILESUMMARYLN = new LogEntryType(
133: (byte) 11, (byte) 3, "FileSummaryLN", new LNLogEntry(
134: com.sleepycat.je.tree.FileSummaryLN.class), false, // isTransactional
135: false, // marshallOutsideLatch
136: false);// isTypeReplicated
137:
138: public static final LogEntryType LOG_IN = new LogEntryType(
139: (byte) 12, (byte) 2, "IN", new INLogEntry(
140: com.sleepycat.je.tree.IN.class), false, // isTransactional
141: true, // marshallOutsideLatch
142: false);// isTypeReplicated
143:
144: public static final LogEntryType LOG_BIN = new LogEntryType(
145: (byte) 13, (byte) 2, "BIN", new INLogEntry(
146: com.sleepycat.je.tree.BIN.class), false, // isTransactional
147: true, // marshallOutsideLatch
148: false);// isTypeReplicated
149:
150: public static final LogEntryType LOG_DIN = new LogEntryType(
151: (byte) 14, (byte) 2, "DIN", new INLogEntry(
152: com.sleepycat.je.tree.DIN.class), false, // isTransactional
153: true, // marshallOutsideLatch
154: false);// isTypeReplicated
155:
156: public static final LogEntryType LOG_DBIN = new LogEntryType(
157: (byte) 15, (byte) 2, "DBIN", new INLogEntry(
158: com.sleepycat.je.tree.DBIN.class), false, // isTransactional
159: true, // marshallOutsideLatch
160: false);// isTypeReplicated
161:
162: public static final LogEntryType[] IN_TYPES = {
163: LogEntryType.LOG_IN, LogEntryType.LOG_BIN,
164: LogEntryType.LOG_DIN, LogEntryType.LOG_DBIN, };
165:
166: /*** If you add new types, be sure to update MAX_TYPE_NUM at the top.***/
167:
168: private static final int MAX_NODE_TYPE_NUM = 15;
169:
170: public static boolean isNodeType(byte typeNum, byte version) {
171: return (typeNum <= MAX_NODE_TYPE_NUM);
172: }
173:
174: /* Root */
175: public static final LogEntryType LOG_ROOT = new LogEntryType(
176: (byte) 16, (byte) 1, "Root", new SingleItemEntry(
177: com.sleepycat.je.dbi.DbTree.class), false, // isTransactional
178: true, // marshallOutsideLatch
179: false);// isTypeReplicated
180:
181: /* Transactional entries */
182: public static final LogEntryType LOG_TXN_COMMIT = new LogEntryType(
183: (byte) 17, (byte) 0, "Commit", new SingleItemEntry(
184: com.sleepycat.je.txn.TxnCommit.class), true, // isTransactional
185: true, // marshallOutsideLatch
186: true); // isTypeReplicated
187:
188: public static final LogEntryType LOG_TXN_ABORT = new LogEntryType(
189: (byte) 18, (byte) 0, "Abort", new SingleItemEntry(
190: com.sleepycat.je.txn.TxnAbort.class), true, // isTransactional
191: true, // marshallOutsideLatch
192: true); // isTypeReplicated
193:
194: public static final LogEntryType LOG_CKPT_START = new LogEntryType(
195: (byte) 19, (byte) 0, "CkptStart", new SingleItemEntry(
196: com.sleepycat.je.recovery.CheckpointStart.class),
197: false, // isTransactional
198: true, // marshallOutsideLatch
199: false);// isTypeReplicated
200:
201: public static final LogEntryType LOG_CKPT_END = new LogEntryType(
202: (byte) 20, (byte) 0, "CkptEnd", new SingleItemEntry(
203: com.sleepycat.je.recovery.CheckpointEnd.class),
204: false, // isTransactional
205: true, // marshallOutsideLatch
206: false);// isTypeReplicated
207:
208: public static final LogEntryType LOG_IN_DELETE_INFO = new LogEntryType(
209: (byte) 21, (byte) 0, "INDelete", new SingleItemEntry(
210: com.sleepycat.je.tree.INDeleteInfo.class), false, // isTransactional
211: true, // marshallOutsideLatch
212: false);// isTypeReplicated
213:
214: public static final LogEntryType LOG_BIN_DELTA = new LogEntryType(
215: (byte) 22, (byte) 0, "BINDelta", new BINDeltaLogEntry(
216: com.sleepycat.je.tree.BINDelta.class), false, // isTransactional
217: true, // marshallOutsideLatch
218: false);// isTypeReplicated
219:
220: public static final LogEntryType LOG_DUP_BIN_DELTA = new LogEntryType(
221: (byte) 23, (byte) 0, "DupBINDelta", new BINDeltaLogEntry(
222: com.sleepycat.je.tree.BINDelta.class), false, // isTransactional
223: true, // marshallOutsideLatch
224: false);// isTypeReplicated
225:
226: /* Administrative entries */
227: public static final LogEntryType LOG_TRACE = new LogEntryType(
228: (byte) 24, (byte) 0, "Trace", new SingleItemEntry(
229: com.sleepycat.je.utilint.Tracer.class), false, // isTransactional
230: true, // marshallOutsideLatch
231: false);// isTypeReplicated
232:
233: /* File header */
234: public static final LogEntryType LOG_FILE_HEADER = new LogEntryType(
235: (byte) 25, (byte) 0, "FileHeader", new SingleItemEntry(
236: com.sleepycat.je.log.FileHeader.class), false, // isTransactional
237: true, // marshallOutsideLatch
238: false);// isTypeReplicated
239:
240: public static final LogEntryType LOG_IN_DUPDELETE_INFO = new LogEntryType(
241: (byte) 26, (byte) 0, "INDupDelete", new SingleItemEntry(
242: com.sleepycat.je.tree.INDupDeleteInfo.class),
243: false, // isTransactional
244: true, // marshallOutsideLatch
245: false);// isTypeReplicated
246:
247: public static final LogEntryType LOG_TXN_PREPARE = new LogEntryType(
248: (byte) 27, (byte) 0, "Prepare", new SingleItemEntry(
249: com.sleepycat.je.txn.TxnPrepare.class), true, // isTransactional
250: true, // marshallOutsideLatch
251: false);// isTypeReplicated
252:
253: /*** If you add new types, be sure to update MAX_TYPE_NUM at the top.***/
254:
255: private static final byte PROVISIONAL_MASK = (byte) 0x80;
256: private static final byte IGNORE_PROVISIONAL = ~PROVISIONAL_MASK;
257: private static final byte REPLICATED_MASK = (byte) 0x40;
258: private static final byte IGNORE_REPLICATED = ~REPLICATED_MASK;
259:
260: /* Persistent fields */
261: private byte typeNum; // persistent value for this entry type
262: private byte version; // persistent version and bit flags
263:
264: /* Transient fields */
265: private String displayName;
266: private LogEntry logEntry;
267:
268: /* If true, the log entry holds a transactional information. */
269: private boolean isTransactional;
270: /* If true, marshal this type of log entry outside log write latch */
271: private boolean marshallOutsideLatch;
272: /* If true, replicate this type of log entry before logging. */
273: private boolean isTypeReplicated;
274:
275: /*
276: * Constructors
277: */
278:
279: /**
280: * For base class support.
281: */
282:
283: /* No log types can be defined outside this package. */
284: LogEntryType(byte typeNum, byte version) {
285: this .typeNum = typeNum;
286: this .version = version;
287: }
288:
289: /**
290: * Create the static log types.
291: * @param isTransactional true if this type of log entry holds data
292: * involved in a transaction. For example, transaction commit and LN data
293: * records are transactional, but INs are not.
294: * @param marshallOutsideLatch true if this type of log entry may be
295: * serialized outside the log write latch. This is true of the majority of
296: * types. Certain types like the FileSummaryLN rely on the log write latch
297: * to enforce serial semantics.
298: * @param isTypeReplicated true if this type of log entry should be shared
299: * with a replication group.
300: */
301: private LogEntryType(byte typeNum, byte version,
302: String displayName, LogEntry logEntry,
303: boolean isTransactional, boolean marshallOutsideLatch,
304: boolean isTypeReplicated) {
305:
306: this .typeNum = typeNum;
307: this .version = version;
308: this .displayName = displayName;
309: this .logEntry = logEntry;
310: this .isTransactional = isTransactional;
311: this .marshallOutsideLatch = marshallOutsideLatch;
312: this .isTypeReplicated = isTypeReplicated;
313: logEntry.setLogType(this );
314: LOG_TYPES[typeNum - 1] = this ;
315: }
316:
317: public boolean isNodeType() {
318: return (typeNum <= MAX_NODE_TYPE_NUM);
319: }
320:
321: /**
322: * @return the static version of this type
323: */
324: public static LogEntryType findType(byte typeNum, byte version) {
325: if (typeNum <= 0 || typeNum > MAX_TYPE_NUM) {
326: return null;
327: }
328: return (LogEntryType) LOG_TYPES[typeNum - 1];
329: }
330:
331: /**
332: * Get a copy of all types for unit testing.
333: */
334: public static Set getAllTypes() {
335: HashSet ret = new HashSet();
336:
337: for (int i = 0; i < MAX_TYPE_NUM; i++) {
338: ret.add(LOG_TYPES[i]);
339: }
340: return ret;
341: }
342:
343: /**
344: * @return the log entry type owned by the shared, static version
345: */
346: public LogEntry getSharedLogEntry() {
347: return logEntry;
348: }
349:
350: /**
351: * @return a clone of the log entry type for a given log type.
352: */
353: LogEntry getNewLogEntry() throws DatabaseException {
354:
355: try {
356: return (LogEntry) logEntry.clone();
357: } catch (CloneNotSupportedException e) {
358: throw new DatabaseException(e);
359: }
360: }
361:
362: /**
363: * Return the version value, clearing away provisional and replicated bits.
364: */
365: public static byte getVersionValue(byte version) {
366: byte value = (byte) (version & IGNORE_PROVISIONAL);
367: value &= IGNORE_REPLICATED;
368: return value;
369: }
370:
371: /**
372: * Set the provisional bit.
373: */
374: static byte setEntryProvisional(byte version) {
375: return (byte) (version | PROVISIONAL_MASK);
376: }
377:
378: /**
379: * @return true if the provisional bit is set.
380: */
381: static boolean isEntryProvisional(byte version) {
382: return ((version & PROVISIONAL_MASK) != 0);
383: }
384:
385: /**
386: * Set the replicated bit
387: */
388: static byte setEntryReplicated(byte version) {
389: return (byte) (version | REPLICATED_MASK);
390: }
391:
392: /**
393: * @return true if the replicated bit is set.
394: */
395: public static boolean isEntryReplicated(byte version) {
396: return ((version & REPLICATED_MASK) != 0);
397: }
398:
399: byte getTypeNum() {
400: return typeNum;
401: }
402:
403: byte getVersion() {
404: return version;
405: }
406:
407: /**
408: * @return true if type number is valid.
409: */
410: static boolean isValidType(byte typeNum) {
411: return typeNum > 0 && typeNum <= MAX_TYPE_NUM;
412: }
413:
414: public String toString() {
415: return displayName + "/" + version;
416: }
417:
418: public String toStringNoVersion() {
419: return displayName;
420: }
421:
422: /**
423: * Check for equality without making a new object.
424: */
425: boolean equalsType(byte typeNum, byte version) {
426: return (this .typeNum == typeNum);
427: }
428:
429: public boolean equalsType(byte typeNum) {
430: return (this .typeNum == typeNum);
431: }
432:
433: /*
434: * Override Object.equals. Ignore provisional bit when checking for
435: * equality.
436: */
437: public boolean equals(Object obj) {
438: // Same instance?
439: if (this == obj) {
440: return true;
441: }
442:
443: // Is it the right type of object?
444: if (!(obj instanceof LogEntryType)) {
445: return false;
446: }
447:
448: return typeNum == ((LogEntryType) obj).typeNum;
449: }
450:
451: /**
452: * This is used as a hash key.
453: */
454: public int hashCode() {
455: return typeNum;
456: }
457:
458: /**
459: * Return true if this log entry has transactional information in it,
460: * like a commit or abort record, or a transactional LN.
461: */
462: public boolean isTransactional() {
463: return isTransactional;
464: }
465:
466: /**
467: * Return true if this log entry should be marshalled into a buffer
468: * outside the log write latch. Currently, only the FileSummaryLN needs
469: * to be logged inside the log write latch.
470: */
471: public boolean marshallOutsideLatch() {
472: return marshallOutsideLatch;
473: }
474:
475: /**
476: * Return true if this log entry should be transmitted to other
477: * sites if the environment is part of a replication group.
478: */
479: public boolean isTypeReplicated() {
480: return isTypeReplicated;
481: }
482: }
|