1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2002, 2014 Oracle and/or its affiliates.  All rights reserved.
5  *
6  */
7 
8 package com.sleepycat.je.log;
9 
10 import java.util.HashSet;
11 import java.util.Set;
12 
13 import com.sleepycat.je.DatabaseException;
14 import com.sleepycat.je.log.entry.AbortLogEntry;
15 import com.sleepycat.je.log.entry.BINDeltaLogEntry;
16 import com.sleepycat.je.log.entry.CommitLogEntry;
17 import com.sleepycat.je.log.entry.DeletedDupLNLogEntry;
18 import com.sleepycat.je.log.entry.FileHeaderEntry;
19 import com.sleepycat.je.log.entry.INLogEntry;
20 import com.sleepycat.je.log.entry.LNLogEntry;
21 import com.sleepycat.je.log.entry.LogEntry;
22 import com.sleepycat.je.log.entry.MatchpointLogEntry;
23 import com.sleepycat.je.log.entry.NameLNLogEntry;
24 import com.sleepycat.je.log.entry.OldBINDeltaLogEntry;
25 import com.sleepycat.je.log.entry.ReplicableLogEntry;
26 import com.sleepycat.je.log.entry.SingleItemEntry;
27 import com.sleepycat.je.log.entry.TraceLogEntry;
28 
29 /**
30  * LogEntryType is an  enumeration of all log entry types.
31  *
32  * <p>Log entries are versioned. When changing the persistent form of a log
33  * entry in any way that is incompatible with prior releases, make sure the
34  * LogEntry instance is capable of reading in older versions from the log and
35  * be sure to increment LOG_VERSION.  The LogEntry.readEntry and
36  * Loggable.readFromLog methods should check the actual version of the entry.
37  * If it is less than LOG_VERSION, the old version should be converted to the
38  * current version.
39  *
40  * <p>Prior to LOG_VERSION 6, each log entry type had a separate version number
41  * that was incremented only when that log version changed.  From LOG_VERSION 6
42  * onward, all types use the same version, the LOG_VERSION constant.  For
43  * versions prior to 6, the readEntry and readFromLog methods will be checking
44  * the old per-type version.  There is no overlap between the old per-type
45  * versions and the LOG_VERSION values, because the per-type values are all
46  * below 6. [#15365]</p>
47 
48  * <p>The LogEntry instance must be sure that older versions are converted in
49  * memory into a correct instance of the newest version, so when that LogEntry
50  * object is written again as the result of migration, eviction, the resulting
51  * new log entry conforms to the requirements of the new version.  If context
52  * objects are required for data conversion, the conversion can be done in the
53  * Node.postFetchInit method.</p>
54  *
55  * <p>Starting with LOG_VERSION 9, log entries that can be included in the
56  * replication stream must be able to write themselves in the format for the
57  * immediately previous log version, to allow replication during an upgrade
58  * when the master has been upgraded and a replica has not.  Starting with
59  * LOG_VERSION 8, log entries that support replication must implement {@link
60  * ReplicableLogEntry}.  When changes are made to replicable log entries for
61  * LOG_VERSION 9 and later, those entries need to support writing in the
62  * previous version's format.</p>
63  */
64 public class LogEntryType {
65 
66     /**
67      * Version of the file header, which identifies the version of all entries
68      * in that file.
69      *
70      * Changes to log entries for each version are:
71      *
72      * Version 3
73      * ---------
74      * [12328] Add main and dupe tree fanout values for DatabaseImpl.
75      * [12557] Add IN LSN array compression.
76      * [11597] Add a change to FileSummaryLNs: obsolete offset tracking was
77      * added and multiple records are stored for a single file rather than a
78      * single record.  Each record contains the offsets that were tracked since
79      * the last record was written.
80      * [11597] Add the full obsolete LSN in LNLogEntry.
81      *
82      * Version 4
83      * ---------
84      * [#14422] Bump MapLN version from 1 to 2.  Instead of a String for the
85      * comparator class name, store either a serialized string or Comparator.
86      *
87      * Version 5
88      * ---------
89      * [#15195] FileSummaryLN version 3.  Add FileSummary.obsoleteLNSize and
90      * obsoleteLNSizeCounted fields.
91      *
92      * Version 6 (in JE 3.3.X)
93      * ---------
94      * [#15365] From this point onward, all log entries have the same version,
95      * LOG_VERSION, rather than using per-type versions.
96      * [#15365] DatabaseImpl stores a map of DbFileSummaries.
97      *
98      * [#13467] Convert duplicatesAllowed boolean to DUPS_ALLOWED_BIT flag in
99      * DatabaseImpl. Add REPLICATED_BIT flag to DatabaseImpl.
100      * [#13467] Add REPLICATED_BIT to DbTree.
101      * [#13467] Add ReplicatedDatabaseConfig to NameLN_TX to support
102      * replication of database operations.
103      *
104      * [#15581] Add lastAllocateReplicatedDbId to DbTree
105      * [#16083] Add replication master node ID to txn commit/abort
106      *
107      * Version 7 (in JE 4.0)
108      * ---------------------
109      * Add the invisible bit in the entry header version field.
110      * Add the RollbackStart log entry type
111      * Add the RollbackEnd log entry type
112      * Add the Matchpoint log entry type.
113      *
114      * Version 8 (in JE 5.0)
115      * ---------------------
116      * Made provisions for storing Triggers in a DatabaseImpl.
117      *
118      * Database IDs enlarged from int or packed int, to long or packed long
119      * (note that packed int and packed long are compatible).  [#18540]
120      *
121      * Add new log entry types for LN delete, insert and update. [#18055]
122      *
123      * Apply optimization to omit key size for some internal LNs, in addition
124      * to user LNs. [#18055]
125      *
126      * LN no longer has node ID. [#18633]
127      *
128      * Add FileSummary.maxLNSize. [#18633]
129      *
130      * VLSN is optionally maintained in LogEntryHeader for cleaner migrated LNs
131      * and a new VLSN_PRESENT entry header flag is used to signify the presence
132      * of the VLSN.  PRESERVE_VLSN_BIT was added to DbTree to correspond to the
133      * je.env.preserveRecordVersion environment config param. [#19476]
134      *
135      * Dup tree representation changed to use two-part keys. Deprecated: DIN,
136      * DBIN, DupCountLN, INDeleteInfo, INDupDeleteInfo.  Removed
137      * DatabaseImpl.maxDupTreeEntriesPerNode.  [#19165]
138      *
139      * Version 9 (in JE 6.0)
140      * ---------------------
141      * See comment above about ReplicableLogEntry.
142      *
143      * BIN-deltas are now represented as BINs using the new BINDeltaLogEntry
144      * (log entry type NewBINDelta).
145      *
146      * Version 10 (in JE 6.2)
147      * ----------------------
148      *
149      * Each BIN-delta stores the total and max number of entries in the
150      * previous full version of the same BIN. A BIN-delta may also store a
151      * bloom filter for the keys in the full BIN.
152      */
153     public static final int LOG_VERSION = 10;
154 
155     public static final int FIRST_LOG_VERSION = 1;
156 
157     /**
158      * The earliest log version for which replicable log entries support
159      * writing themselves in the previous version, to support replication to
160      * older nodes during upgrades.
161      */
162     public static final int LOG_VERSION_REPLICATE_PREVIOUS = 9;
163 
164     /**
165      * The highest log version of any replicable log entry class, so that
166      * replication can determine the earliest log version it can generate.
167      * This field is needed to account for cases where log entry format changes
168      * only apply to non-replicable entries, as was the case for log version
169      * 10.
170      */
171     /*
172      * TODO: Modify the requirements for writing replicable log entries in the
173      * the current version minus one format to account for the fact that there
174      * is a gap in the numbering, since no replicable entry classes had format
175      * changes for log versions 9 or 10.  Make this change the next time the
176      * format of a replicable log entry is modified.
177      */
178     public static final int LOG_VERSION_HIGHEST_REPLICABLE = 8;
179 
180     /**
181      * Should be used for reading the entry header of the file header, since
182      * the actual version is not known until the FileHeader item is read.
183      */
184     public static final int UNKNOWN_FILE_HEADER_VERSION = -1;
185 
186     /*
187      * Collection of log entry type classes, used to read the log.  Note that
188      * this must be declared before any instances of LogEntryType, since the
189      * constructor uses this map. Each statically defined LogEntryType should
190      * register itself with this collection.
191      */
192     private static final int MAX_TYPE_NUM = 37;
193     private static LogEntryType[] LOG_TYPES = new LogEntryType[MAX_TYPE_NUM];
194 
195     /*
196      * Enumeration of log entry types. The log entry type represents the 2 byte
197      * field that starts every log entry. The top byte is the log type, the
198      * bottom byte holds the version value, provisional bit, replicated bit,
199      * and invisible bit.
200      *
201      * Log type(8 bits)
202      * Provisional(2 bits) Replicated(1 bit) Invisible(1 bit) Version(5 bits)
203      *
204      * The top byte (log type) identifies the type and can be used to lookup
205      * the LogEntryType object, while the bottom byte has information about the
206      * entry (instance) of this type.  The bottom byte is effectively entry
207      * header information that is common to all types and is managed by methods
208      * in LogEntryHeader. See LogEntryHeader.java
209      */
210 
211     /*  Node types */
212 
213     /*
214      * Deprecated transactional LN entry type, use LOG_DEL_LN_TRANSACTIONAL,
215      * LOG_INS_LN_TRANSACTIONAL, LOG_UPD_LN_TRANSACTIONAL instead according to
216      * the operation type.
217      */
218     public static final LogEntryType LOG_OLD_LN_TRANSACTIONAL =
219         createReplicableLogEntryType(
220             (byte) 1, "LN_TX",
221             LNLogEntry.create(com.sleepycat.je.tree.LN.class),
222             Txnal.TXNAL,
223             Marshall.OUTSIDE_LATCH,
224             Replicable.REPLICABLE_NO_MATCH,
225             NodeType.LN_USER);
226 
227     /*
228      * Deprecated LN entry type, use LOG_DEL_LN, LOG_INS_LN, LOG_UPD_LN instead
229      * according to the operation type.
230      */
231     public static final LogEntryType LOG_OLD_LN =
232         createReplicableLogEntryType(
233             (byte) 2, "LN",
234             LNLogEntry.create(com.sleepycat.je.tree.LN.class),
235             Txnal.NON_TXNAL,
236             Marshall.OUTSIDE_LATCH,
237             Replicable.REPLICABLE_NO_MATCH,
238             NodeType.LN_USER);
239 
240     public static final LogEntryType LOG_MAPLN_TRANSACTIONAL =
241         new LogEntryType
242         ((byte) 3, "MapLN_TX",
243          LNLogEntry.create(com.sleepycat.je.tree.MapLN.class),
244          Txnal.TXNAL,
245          Marshall.INSIDE_LATCH,
246          NodeType.LN_INTERNAL);
247 
248     public static final LogEntryType LOG_MAPLN =
249         new LogEntryType
250         ((byte) 4, "MapLN",
251          LNLogEntry.create(com.sleepycat.je.tree.MapLN.class),
252          Txnal.NON_TXNAL,
253          Marshall.INSIDE_LATCH,
254          NodeType.LN_INTERNAL);
255 
256     public static final LogEntryType LOG_NAMELN_TRANSACTIONAL =
257         createReplicableLogEntryType(
258             (byte) 5, "NameLN_TX",
259             new NameLNLogEntry(),
260             Txnal.TXNAL,
261             Marshall.OUTSIDE_LATCH,
262             Replicable.REPLICABLE_NO_MATCH,
263             NodeType.LN_INTERNAL);
264 
265     public static final LogEntryType LOG_NAMELN =
266         createReplicableLogEntryType(
267             (byte) 6, "NameLN",
268             new NameLNLogEntry(),
269             Txnal.NON_TXNAL,
270             Marshall.OUTSIDE_LATCH,
271             Replicable.REPLICABLE_NO_MATCH,
272             NodeType.LN_INTERNAL);
273 
274     /* Obsolete in version 8, only used by some log readers. */
275     public static final LogEntryType LOG_DEL_DUPLN_TRANSACTIONAL =
276         createReplicableLogEntryType(
277             (byte) 7, "DelDupLN_TX",
278             new DeletedDupLNLogEntry(),
279             Txnal.TXNAL,
280             Marshall.OUTSIDE_LATCH,
281             Replicable.REPLICABLE_NO_MATCH,
282             NodeType.LN_USER);
283 
284     /* Obsolete in version 8, only used by some log readers. */
285     public static final LogEntryType LOG_DEL_DUPLN =
286         createReplicableLogEntryType(
287             (byte) 8, "DelDupLN",
288             new DeletedDupLNLogEntry(),
289             Txnal.NON_TXNAL,
290             Marshall.OUTSIDE_LATCH,
291             Replicable.REPLICABLE_NO_MATCH,
292             NodeType.LN_USER);
293 
294     /* Obsolete in version 8, only used by DupConvert and some log readers. */
295     public static final LogEntryType LOG_DUPCOUNTLN_TRANSACTIONAL =
296         new LogEntryType
297         ((byte) 9, "DupCountLN_TX",
298          LNLogEntry.create(com.sleepycat.je.tree.dupConvert.DupCountLN.class),
299          Txnal.TXNAL,
300          Marshall.OUTSIDE_LATCH,
301          NodeType.OLD_DUP);
302 
303     /* Obsolete in version 8, only used by DupConvert and some log readers. */
304     public static final LogEntryType LOG_DUPCOUNTLN =
305         new LogEntryType
306         ((byte) 10, "DupCountLN",
307          LNLogEntry.create(com.sleepycat.je.tree.dupConvert.DupCountLN.class),
308          Txnal.NON_TXNAL,
309          Marshall.OUTSIDE_LATCH,
310          NodeType.OLD_DUP);
311 
312     public static final LogEntryType LOG_FILESUMMARYLN =
313         new LogEntryType
314         ((byte) 11, "FileSummaryLN",
315          LNLogEntry.create(com.sleepycat.je.tree.FileSummaryLN.class),
316          Txnal.NON_TXNAL,
317          Marshall.INSIDE_LATCH,
318          NodeType.LN_INTERNAL);
319 
320     public static final LogEntryType LOG_IN =
321         new LogEntryType
322         ((byte) 12, "IN",
323          INLogEntry.create(com.sleepycat.je.tree.IN.class),
324          Txnal.NON_TXNAL,
325          Marshall.OUTSIDE_LATCH,
326          NodeType.IN);
327 
328     public static final LogEntryType LOG_BIN =
329         new LogEntryType
330         ((byte) 13, "BIN",
331          INLogEntry.create(com.sleepycat.je.tree.BIN.class),
332          Txnal.NON_TXNAL,
333          Marshall.OUTSIDE_LATCH,
334          NodeType.IN);
335 
336     /* Obsolete in version 8, only used by DupConvert and some log readers. */
337     public static final LogEntryType LOG_DIN =
338         new LogEntryType
339         ((byte) 14, "DIN",
340          INLogEntry.create(com.sleepycat.je.tree.dupConvert.DIN.class),
341          Txnal.NON_TXNAL,
342          Marshall.OUTSIDE_LATCH,
343          NodeType.OLD_DUP);
344 
345     /* Obsolete in version 8, only used by DupConvert and some log readers. */
346     public static final LogEntryType LOG_DBIN =
347         new LogEntryType
348         ((byte) 15, "DBIN",
349          INLogEntry.create(com.sleepycat.je.tree.dupConvert.DBIN.class),
350          Txnal.NON_TXNAL,
351          Marshall.OUTSIDE_LATCH,
352          NodeType.OLD_DUP);
353 
354     /*
355      * The root entry of the DbTree, it saves the root information for name
356      * and id database.
357      */
358     public static final LogEntryType LOG_DBTREE =
359         new LogEntryType
360         ((byte) 16, "DbTree",
361          SingleItemEntry.create(
362              com.sleepycat.je.dbi.DbTree.class),
363          Txnal.NON_TXNAL,
364          Marshall.INSIDE_LATCH,
365          NodeType.NONE);
366 
367     /* Transactional entries */
368     public static final LogEntryType LOG_TXN_COMMIT =
369         createReplicableLogEntryType(
370             (byte) 17, "Commit",
371             new CommitLogEntry(),
372             Txnal.TXNAL,
373             Marshall.OUTSIDE_LATCH,
374             Replicable.REPLICABLE_MATCH,
375             NodeType.NONE);
376 
377     public static final LogEntryType LOG_TXN_ABORT =
378         createReplicableLogEntryType(
379             (byte) 18, "Abort",
380             new AbortLogEntry(),
381             Txnal.TXNAL,
382             Marshall.OUTSIDE_LATCH,
383             Replicable.REPLICABLE_MATCH,
384             NodeType.NONE);
385 
386     public static final LogEntryType LOG_CKPT_START =
387         new LogEntryType
388         ((byte) 19, "CkptStart",
389          SingleItemEntry.create(
390              com.sleepycat.je.recovery.CheckpointStart.class),
391          Txnal.NON_TXNAL,
392          Marshall.OUTSIDE_LATCH,
393          NodeType.NONE);
394 
395     public static final LogEntryType LOG_CKPT_END =
396         new LogEntryType
397         ((byte) 20, "CkptEnd",
398          SingleItemEntry.create(
399              com.sleepycat.je.recovery.CheckpointEnd.class),
400          Txnal.NON_TXNAL,
401          Marshall.OUTSIDE_LATCH,
402          NodeType.NONE);
403 
404     /* Obsolete in version 8, only used by some log readers. */
405     public static final LogEntryType LOG_IN_DELETE_INFO =
406         new LogEntryType
407         ((byte) 21, "INDelete",
408          SingleItemEntry.create(
409              com.sleepycat.je.tree.dupConvert.INDeleteInfo.class),
410          Txnal.NON_TXNAL,
411          Marshall.OUTSIDE_LATCH,
412          NodeType.NONE);
413 
414     /* Obsolete in version 9, replaced by "live" LOG_BIN_DELTA. */
415     public static final LogEntryType LOG_OLD_BIN_DELTA =
416         new LogEntryType
417         ((byte) 22, "BINDelta",
418          new OldBINDeltaLogEntry
419          (com.sleepycat.je.tree.OldBINDelta.class),
420          Txnal.NON_TXNAL,
421          Marshall.OUTSIDE_LATCH,
422          NodeType.NONE);
423 
424     /* Obsolete in version 8, only used by some log readers. */
425     public static final LogEntryType LOG_OLD_DUP_BIN_DELTA =
426         new LogEntryType
427         ((byte) 23, "DupBINDelta",
428          new OldBINDeltaLogEntry
429          (com.sleepycat.je.tree.OldBINDelta.class),
430          Txnal.NON_TXNAL,
431          Marshall.OUTSIDE_LATCH,
432          NodeType.NONE);
433 
434     /* Administrative entries */
435     public static final LogEntryType LOG_TRACE =
436         createReplicableLogEntryType(
437             (byte) 24, "Trace",
438             new TraceLogEntry(),
439             Txnal.NON_TXNAL,
440             Marshall.OUTSIDE_LATCH,
441             Replicable.REPLICABLE_NO_MATCH,
442             NodeType.NONE);
443 
444     /* File header */
445     public static final LogEntryType LOG_FILE_HEADER =
446         new LogEntryType
447         ((byte) 25, "FileHeader",
448          new FileHeaderEntry
449          (com.sleepycat.je.log.FileHeader.class),
450          Txnal.NON_TXNAL,
451          Marshall.OUTSIDE_LATCH,
452          NodeType.NONE);
453 
454     /* Obsolete in version 8, only used by some log readers. */
455     public static final LogEntryType LOG_IN_DUPDELETE_INFO =
456         new LogEntryType
457         ((byte) 26, "INDupDelete",
458          SingleItemEntry.create(
459              com.sleepycat.je.tree.dupConvert.INDupDeleteInfo.class),
460          Txnal.NON_TXNAL,
461          Marshall.OUTSIDE_LATCH,
462          NodeType.NONE);
463 
464     public static final LogEntryType LOG_TXN_PREPARE =
465         new LogEntryType
466         ((byte) 27, "Prepare",
467          SingleItemEntry.create(
468              com.sleepycat.je.txn.TxnPrepare.class),
469          Txnal.TXNAL,
470          Marshall.OUTSIDE_LATCH,
471          NodeType.NONE);
472 
473     public static final LogEntryType LOG_ROLLBACK_START =
474         new LogEntryType
475         ((byte) 28, "RollbackStart",
476          SingleItemEntry.create(
477              com.sleepycat.je.txn.RollbackStart.class),
478          Txnal.NON_TXNAL,
479          Marshall.OUTSIDE_LATCH,
480          NodeType.NONE);
481 
482     public static final LogEntryType LOG_ROLLBACK_END =
483         new LogEntryType
484         ((byte) 29, "RollbackEnd",
485          SingleItemEntry.create(
486              com.sleepycat.je.txn.RollbackEnd.class),
487          Txnal.NON_TXNAL,
488          Marshall.OUTSIDE_LATCH,
489          NodeType.NONE);
490 
491     public static final LogEntryType LOG_MATCHPOINT =
492         createReplicableLogEntryType(
493             (byte) 30, "Matchpoint",
494             new MatchpointLogEntry(),
495             Txnal.NON_TXNAL,
496             Marshall.OUTSIDE_LATCH,
497             Replicable.REPLICABLE_MATCH,
498             NodeType.NONE);
499 
500     public static final LogEntryType LOG_DEL_LN_TRANSACTIONAL =
501         new UserLNLogEntryType((byte) 31, "DEL_LN_TX", Txnal.TXNAL);
502 
503     public static final LogEntryType LOG_DEL_LN =
504         new UserLNLogEntryType((byte) 32, "DEL_LN", Txnal.NON_TXNAL);
505 
506     public static final LogEntryType LOG_INS_LN_TRANSACTIONAL =
507         new UserLNLogEntryType((byte) 33, "INS_LN_TX", Txnal.TXNAL);
508 
509     public static final LogEntryType LOG_INS_LN =
510         new UserLNLogEntryType((byte) 34, "INS_LN", Txnal.NON_TXNAL);
511 
512     public static final LogEntryType LOG_UPD_LN_TRANSACTIONAL =
513         new UserLNLogEntryType((byte) 35, "UPD_LN_TX", Txnal.TXNAL);
514 
515     public static final LogEntryType LOG_UPD_LN =
516         new UserLNLogEntryType((byte) 36, "UPD_LN", Txnal.NON_TXNAL);
517 
518     public static final LogEntryType LOG_BIN_DELTA =
519         new LogEntryType(
520             (byte) 37, "NewBINDelta",
521             new BINDeltaLogEntry(com.sleepycat.je.tree.BIN.class),
522             Txnal.NON_TXNAL,
523             Marshall.OUTSIDE_LATCH,
524             NodeType.IN);
525 
526     /*** If you add new types, be sure to update MAX_TYPE_NUM at the top.***/
527 
528     /* Persistent fields */
529     private final byte typeNum; // persistent value for this entry type
530 
531     /* Transient fields */
532     private final String displayName;
533     private final LogEntry logEntry;
534 
535     /*
536      * Attributes
537      */
538 
539     /* Whether the log entry holds a transactional information. */
540     private Txnal isTransactional;
541 
542     /*
543      * Does this log entry be marshalled outside or inside the log write
544      * latch.
545      */
546     private Marshall marshallBehavior;
547 
548     /* Can this log entry be put in the replication stream? */
549     private Replicable replicationPossible;
550 
551     private NodeType nodeType;
552 
553     /*
554      * Constructors
555      */
556 
557     /**
558      * For base class support.
559      */
560 
561     /*
562      * This constructor only used when the LogEntryType is being used as a key
563      * for a map. No log types can be defined outside this package.
564      */
LogEntryType(byte typeNum)565     LogEntryType(byte typeNum) {
566         this.typeNum = typeNum;
567         displayName = null;
568         logEntry = null;
569     }
570 
571     /**
572      * Used to create a map key for reporting that is not a real type.
573      */
LogEntryType(byte typeNum, String displayName)574     LogEntryType(byte typeNum, String displayName) {
575         assert typeNum > MAX_TYPE_NUM;
576         this.typeNum = typeNum;
577         this.displayName = displayName;
578         logEntry = null;
579     }
580 
581     /**
582      * Create a non-replicable log type.
583      *
584      * @param isTransactional whether this type of log entry holds data
585      * involved in a transaction. For example, transaction commit and LN data
586      * records are transactional, but INs are not.
587      * @param marshallBehavior whether this type of log entry may be serialized
588      * outside the log write latch. This is true of the majority of
589      * types. Certain types like the FileSummaryLN rely on the log write latch
590      * to enforce serial semantics.
591      */
LogEntryType(final byte typeNum, final String displayName, final LogEntry logEntry, final Txnal isTransactional, final Marshall marshallBehavior, final NodeType nodeType)592     private LogEntryType(final byte typeNum,
593                          final String displayName,
594                          final LogEntry logEntry,
595                          final Txnal isTransactional,
596                          final Marshall marshallBehavior,
597                          final NodeType nodeType) {
598 
599         this(typeNum, displayName, logEntry, isTransactional, marshallBehavior,
600              Replicable.LOCAL, nodeType);
601     }
602 
603     /**
604      * Create a replicable log type.
605      *
606      * @param isTransactional whether this type of log entry holds data
607      * involved in a transaction
608      * @param marshallBehavior whether this type of log entry may be serialized
609      * outside the log write latch
610      * @param replicationPossible whether this type of log entry can be shared
611      * with a replication group
612      */
createReplicableLogEntryType( final byte typeNum, final String displayName, final ReplicableLogEntry logEntry, final Txnal isTransactional, final Marshall marshallBehavior, final Replicable replicationPossible, final NodeType nodeType)613     private static LogEntryType createReplicableLogEntryType(
614         final byte typeNum,
615         final String displayName,
616         final ReplicableLogEntry logEntry,
617         final Txnal isTransactional,
618         final Marshall marshallBehavior,
619         final Replicable replicationPossible,
620         final NodeType nodeType) {
621 
622         return new LogEntryType(typeNum, displayName, logEntry,
623                                 isTransactional, marshallBehavior,
624                                 replicationPossible, nodeType);
625     }
626 
627     /**
628      * Internal constructor for all log types.  Don't create instances using
629      * this directly, to improve error checking.
630      */
LogEntryType(final byte typeNum, final String displayName, final LogEntry logEntry, final Txnal isTransactional, final Marshall marshallBehavior, final Replicable replicationPossible, final NodeType nodeType)631     private LogEntryType(final byte typeNum,
632                          final String displayName,
633                          final LogEntry logEntry,
634                          final Txnal isTransactional,
635                          final Marshall marshallBehavior,
636                          final Replicable replicationPossible,
637                          final NodeType nodeType) {
638 
639         this.typeNum = typeNum;
640         this.displayName = displayName;
641         this.logEntry = logEntry;
642         this.isTransactional = isTransactional;
643         this.marshallBehavior = marshallBehavior;
644         this.replicationPossible = replicationPossible;
645         this.nodeType = nodeType;
646         logEntry.setLogType(this);
647         LOG_TYPES[typeNum - 1] = this;
648 
649         assert logEntry != null && replicationPossible != null;
650         assert !replicationPossible.isReplicable() ||
651             logEntry instanceof ReplicableLogEntry
652             : "Replicable log types must have replicable log entries";
653     }
654 
655     /**
656      * @return the static version of this type
657      */
findType(byte typeNum)658     public static LogEntryType findType(byte typeNum) {
659         if (typeNum <= 0 || typeNum > MAX_TYPE_NUM) {
660             return null;
661         }
662         return LOG_TYPES[typeNum - 1];
663     }
664 
665     /**
666      * Get a copy of all types for unit testing.
667      */
getAllTypes()668     public static Set<LogEntryType> getAllTypes() {
669         HashSet<LogEntryType> ret = new HashSet<LogEntryType>();
670 
671         for (int i = 0; i < MAX_TYPE_NUM; i++) {
672             ret.add(LOG_TYPES[i]);
673         }
674         return ret;
675     }
676 
677     /**
678      * @return the log entry type owned by the shared, static version
679      */
getSharedLogEntry()680     public LogEntry getSharedLogEntry() {
681         return logEntry;
682     }
683 
684     /**
685      * @return a clone of the log entry type for a given log type.
686      */
getNewLogEntry()687     public LogEntry getNewLogEntry()
688         throws DatabaseException {
689 
690         return logEntry.clone();
691     }
692 
getTypeNum()693     public byte getTypeNum() {
694         return typeNum;
695     }
696 
697     /**
698      * @return true if type number is valid.
699      */
isValidType(byte typeNum)700     static boolean isValidType(byte typeNum) {
701         return typeNum > 0 && typeNum <= MAX_TYPE_NUM;
702     }
703 
toStringNoVersion()704     public String toStringNoVersion() {
705         return displayName;
706     }
707 
708     @Override
toString()709     public String toString() {
710         return displayName;
711     }
712 
713     /**
714      * Check for equality without making a new object.
715      */
equalsType(byte type)716     public boolean equalsType(byte type) {
717         return (this.typeNum == type);
718     }
719 
720     /*
721      * Override Object.equals. Ignore provisional bit when checking for
722      * equality.
723      */
724     @Override
equals(Object obj)725     public boolean equals(Object obj) {
726         /* Same instance? */
727         if (this == obj) {
728             return true;
729         }
730 
731         /* Is it the right type of object? */
732         if (!(obj instanceof LogEntryType)) {
733             return false;
734         }
735 
736         return typeNum == ((LogEntryType) obj).typeNum;
737     }
738 
739     /**
740      * This is used as a hash key.
741      */
742     @Override
hashCode()743     public int hashCode() {
744         return typeNum;
745     }
746 
747     static enum Txnal {
748         TXNAL(true),
749         NON_TXNAL(false);
750 
751         private final boolean isTxnal;
752 
Txnal(boolean isTxnal)753         Txnal(boolean isTxnal) {
754             this.isTxnal = isTxnal;
755         }
756 
isTransactional()757         boolean isTransactional() {
758             return isTxnal;
759         }
760     }
761 
762     /**
763      * Return true if this log entry has transactional information in it,
764      * like a commit or abort record, or a transactional LN.
765      */
isTransactional()766     public boolean isTransactional() {
767         return isTransactional.isTransactional();
768     }
769 
770     static enum Marshall {
771         OUTSIDE_LATCH(true),
772         INSIDE_LATCH(false);
773 
774         private final boolean marshallOutsideLatch;
775 
Marshall(boolean marshallOutsideLatch)776         Marshall(boolean marshallOutsideLatch) {
777             this.marshallOutsideLatch = marshallOutsideLatch;
778         }
779 
marshallOutsideLatch()780         boolean marshallOutsideLatch() {
781             return marshallOutsideLatch;
782         }
783     }
784 
785     /**
786      * Return true if this log entry should be marshalled into a buffer outside
787      * the log write latch. Currently, only the FileSummaryLN and MapLN (which
788      * contains DbFileSummary objects) need to be logged inside the log write
789      * latch.
790      */
marshallOutsideLatch()791     public boolean marshallOutsideLatch() {
792         return marshallBehavior.marshallOutsideLatch();
793     }
794 
795     /**
796      * Return true if the type of this LogEntryType is equivalent to typeB.
797      * Version is used as a factor in the comparison when new log entry types
798      * are introduced in one release, which supercede existing types.
799      */
compareTypeAndVersion(@uppressWarningsR) int versionA, @SuppressWarnings(R) int versionB, final byte typeB)800     public boolean compareTypeAndVersion(@SuppressWarnings("unused")
801                                          int versionA,
802                                          @SuppressWarnings("unused")
803                                          int versionB,
804                                          final byte typeB) {
805         return typeNum == typeB;
806     }
807 
808     /*
809      * Indicates whether this type of log entry is shared in a replicated
810      * environment or not, and whether it can be used as a replication
811      * matchpoint.
812      */
813     static enum Replicable {
814         REPLICABLE_MATCH(true, true),
815         REPLICABLE_NO_MATCH(true, false),
816         LOCAL(false, false);
817 
818         private final boolean isReplicable;
819         private final boolean isMatchable;
820 
Replicable(boolean isReplicable, boolean isMatchable)821         Replicable(boolean isReplicable, boolean isMatchable) {
822             this.isReplicable = isReplicable;
823             this.isMatchable = isMatchable;
824         }
825 
isReplicable()826         boolean isReplicable() {
827             return isReplicable;
828         }
829 
isMatchable()830         boolean isMatchable() {
831             return isMatchable;
832         }
833     }
834 
835     /**
836      * Return true if this type of log entry can be part of the replication
837      * stream. For example, INs can never be replicated, while LNs are
838      * replicated only if their owning database is replicated.
839      */
isReplicationPossible()840     public boolean isReplicationPossible() {
841         return replicationPossible.isReplicable();
842     }
843 
844     /**
845      * Return true if this type of log entry can serve as the synchronization
846      * matchpoint for the replication stream. That generally means that this
847      * log entry contains an replication node ID.
848      */
isSyncPoint()849     public boolean isSyncPoint() {
850         return replicationPossible.isMatchable();
851     }
852 
853     /**
854      * Return true if this type of log entry can serve as the synchronization
855      * matchpoint for the replication stream.
856      */
isSyncPoint(byte entryType)857     public static boolean isSyncPoint(byte entryType) {
858         return findType(entryType).isSyncPoint();
859     }
860 
861     /* Type of Btree node. */
862     static enum NodeType {
863 
864         /* Not a Btree node. */
865         NONE,
866 
867         /* Internal node. Does not include old-format DIN/DBIN. */
868         IN,
869 
870         /* DIN/DBIN/DupCountLN in old-format duplicates database. */
871         OLD_DUP,
872 
873         /* LNs representing records in internal databases. */
874         LN_INTERNAL,
875 
876         /* LNs representing ordinary user records.  */
877         LN_USER;
878     }
879 
isNodeType()880     public boolean isNodeType() {
881         return nodeType != NodeType.NONE;
882     }
883 
isUserLNType()884     public boolean isUserLNType() {
885         return nodeType == NodeType.LN_USER;
886     }
887 
isLNType()888     public boolean isLNType() {
889         return nodeType == NodeType.LN_INTERNAL || isUserLNType();
890     }
891 
isINType()892     public boolean isINType() {
893         return nodeType == NodeType.IN;
894     }
895 
isOldDupType()896     public boolean isOldDupType() {
897         return nodeType == NodeType.OLD_DUP;
898     }
899 
900     /**
901      * Return true if the two types are equal. Handles the situation where new
902      * log entry types were introduced in one release, that are actually
903      * equivalent to old, deprecated types.
904      */
compareTypeAndVersion(int versionA, byte typeA, int versionB, byte typeB)905     public static boolean compareTypeAndVersion(int versionA,
906                                                 byte typeA,
907                                                 int versionB,
908                                                 byte typeB) {
909         LogEntryType entryA = findType(typeA);
910         return entryA.compareTypeAndVersion(versionA, versionB, typeB);
911     }
912 
913     private static class UserLNLogEntryType extends LogEntryType {
UserLNLogEntryType(byte typeNum, String displayName, Txnal txnal)914         public UserLNLogEntryType(byte typeNum,
915                                   String displayName,
916                                   Txnal txnal) {
917             super(typeNum, displayName,
918                   LNLogEntry.create(com.sleepycat.je.tree.LN.class),
919                   txnal, Marshall.OUTSIDE_LATCH,
920                   Replicable.REPLICABLE_NO_MATCH, NodeType.LN_USER);
921         }
922 
923         @Override
compareTypeAndVersion(int versionA, int versionB, byte typeB)924         public boolean compareTypeAndVersion(int versionA,
925                                              int versionB,
926                                              byte typeB) {
927             /* If the other entry is newer, the types should match. */
928             if (versionA <= versionB && getTypeNum() == typeB) {
929                 return true;
930             }
931 
932             /*
933              * If the other entry is older, the type might be an old,
934              * deprecated, equivalent type.
935              */
936             if ((versionA > versionB) && isEquivalentOldType(typeB)) {
937                 return true;
938             }
939 
940             /*
941              * In this case, the other entry's version is older or newer but it
942              * doesn't matter -- it's completely the wrong type.
943              */
944             return false;
945         }
946 
isEquivalentOldType(byte typeB)947         private boolean isEquivalentOldType(byte typeB) {
948             if ((!isTransactional() && (typeB == LOG_OLD_LN.getTypeNum())) ||
949                 (isTransactional() &&
950                  (typeB == LOG_OLD_LN_TRANSACTIONAL.getTypeNum()))) {
951                 return true;
952             }
953 
954             return false;
955         }
956     }
957 }
958