1287 lines
55 KiB
C
1287 lines
55 KiB
C
|
/****************************************************************
|
||
|
* *
|
||
|
* Copyright 2001, 2011 Fidelity Information Services, Inc *
|
||
|
* *
|
||
|
* This source code contains the intellectual property *
|
||
|
* of its copyright holder(s), and is made available *
|
||
|
* under a license. If you do not know the terms of *
|
||
|
* the license, please stop and do not read further. *
|
||
|
* *
|
||
|
****************************************************************/
|
||
|
#include "mdef.h"
|
||
|
#ifndef JNL_H_INCLUDED
|
||
|
#define JNL_H_INCLUDED
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
#include <stddef.h> /* for offsetof macro (see OFFSETOF usage in assert below) */
|
||
|
#endif
|
||
|
|
||
|
#ifndef JNLSP_H_INCLUDED
|
||
|
#include "jnlsp.h"
|
||
|
#endif
|
||
|
#ifdef GTM_CRYPT
|
||
|
#include "gtmcrypt.h"
|
||
|
#endif
|
||
|
|
||
|
#define TID_STR_SIZE 8
|
||
|
#define JPV_LEN_NODE 16
|
||
|
#define JPV_LEN_USER 12
|
||
|
#define JPV_LEN_PRCNAM 16
|
||
|
#define JPV_LEN_TERMINAL 15
|
||
|
|
||
|
/* Whenever JNL_LABEL_TEXT changes, also change the following
|
||
|
* 1) Update JNL_VER_THIS
|
||
|
* 2) Add REPL_JNL_Vxx enum to repl_jnl_t typedef AND Vxx_JNL_VER #define in repl_filter.h
|
||
|
* 3) Add an entry each to repl_filter_old2cur & repl_filter_cur2old arrays in repl_filter.c.
|
||
|
* If the FILTER format is also changing, then do the following as well
|
||
|
* 4) Add REPL_FILTER_Vxx enum to repl_filter_t typedef in repl_filter.h
|
||
|
* 5) Add/Edit IF_xTOy macros in repl_filter.h to transform from/to the NEW jnl format version only.
|
||
|
* Remove all entries that dont have the new jnl format in either the from or to part of the conversion.
|
||
|
* 6) Add/Edit prototype and implement functions jnl_xTOy() and jnl_yTOx() in repl_filter.c
|
||
|
* 7) Enhance repl_tr_endian_convert() to endian convert journal records from previous jnl formats to new format.
|
||
|
* This is similar to the jnl_xTOy() filter conversion functions except that lot of byte-swaps are needed.
|
||
|
* 8) Periodically determine if the size of the array repl_filter_old2cur is huge and if so trim support of
|
||
|
* rolling upgrade (using replication internal filters) for older GT.M versions/jnl-formats.
|
||
|
* This would mean bumping the macro JNL_VER_EARLIEST_REPL and examining all arrays that are defined
|
||
|
* using this macro and changing the entries in all those arrays accordingly (e.g. repl_filter_old2cur
|
||
|
* array currently assumes earliest supported version is V15 and hence has the function named IF_curTO15
|
||
|
* which needs to change to say IF_curTO17 if the earliest supported version changes to V17 or so).
|
||
|
*
|
||
|
*/
|
||
|
#define JNL_LABEL_TEXT "GDSJNL21" /* see above comment paragraph for todos whenever this is changed */
|
||
|
#define JNL_VER_THIS 21
|
||
|
#define JNL_VER_EARLIEST_REPL 15 /* Replication filter support starts here GDSJNL15 = GT.M V4.4-002 */
|
||
|
#define JRT_MAX_V15 JRT_AIMG /* Maximum jnl record type in GDSJNL15 that can be input to replication filter */
|
||
|
#define JRT_MAX_V17 JRT_AIMG /* Maximum jnl record type in GDSJNL17 that can be input to replication filter.
|
||
|
* Actually JRT_TRIPLE is a higher record type than JRT_AIMG but it is only
|
||
|
* sent through the replication pipe and never seen by filter routines.
|
||
|
*/
|
||
|
#define JRT_MAX_V19 JRT_UZTWORM /* Maximum jnl record type in GDSJNL19 that can be input to replication filter */
|
||
|
#define ALIGN_KEY 0xdeadbeef
|
||
|
|
||
|
#ifdef UNIX
|
||
|
#define JNL_ALLOC_DEF 2048
|
||
|
#define JNL_ALLOC_MIN 200
|
||
|
#elif defined(VMS)
|
||
|
#define JNL_ALLOC_DEF 100
|
||
|
#define JNL_ALLOC_MIN 10
|
||
|
#endif
|
||
|
|
||
|
/* JNL_BUFFER_MIN database block size / 512 + 1 */
|
||
|
#define JNL_BUFFER_MAX 32768 /* # of 512-byte blocks = 16Mb journal buffer size */
|
||
|
|
||
|
/* JNL_EXTEND_DEF allocation size / 10
|
||
|
#define JNL_EXTEND_DEF_PERC 0.1
|
||
|
* Uncomment this section when code is ready to use extension = 10% of allocation
|
||
|
*/
|
||
|
|
||
|
#define JNL_EXTEND_MIN 0
|
||
|
#ifdef UNIX
|
||
|
#define JNL_EXTEND_DEF 2048
|
||
|
#else
|
||
|
#define JNL_EXTEND_DEF 100
|
||
|
#endif
|
||
|
#define JNL_EXTEND_MAX 65535
|
||
|
#define JNL_MIN_WRITE 32768
|
||
|
#define JNL_MAX_WRITE 65536
|
||
|
/* FE was changed to EB because, the bit pattern there seems to vary more than the one for "FE".
|
||
|
* Also a research in ELWOOD journal file showed that "EB" was one of the few patterns that had the least occurrences */
|
||
|
#define JNL_REC_SUFFIX_CODE 0xEB
|
||
|
|
||
|
/* In Unix, with sync_io, we do journal writes to disk at filesystem block size boundaries.
|
||
|
* In VMS, the writes are at 512-byte boundaries only.
|
||
|
*/
|
||
|
#ifdef UNIX
|
||
|
# define JNL_WRT_START_MODULUS(jb) jb->fs_block_size
|
||
|
#elif defined(VMS)
|
||
|
# define JNL_WRT_START_MODULUS(jb) 512
|
||
|
#endif
|
||
|
#define JNL_WRT_START_MASK(jb) ~(JNL_WRT_START_MODULUS(jb) - 1)
|
||
|
|
||
|
#define JNL_WRT_END_MODULUS 8
|
||
|
#define JNL_WRT_END_MASK ~(JNL_WRT_END_MODULUS - 1)
|
||
|
|
||
|
#ifdef UNIX
|
||
|
#define JNL_MIN_ALIGNSIZE (1 << 8) /* 256 disk blocks effectively 128K alignsize */
|
||
|
#define JNL_DEF_ALIGNSIZE (1 << 11) /* 2048 disk blocks effectively 1M alignsize */
|
||
|
#else
|
||
|
#define JNL_MIN_ALIGNSIZE (1 << 5) /* 32 disk blocks effectively 16K alignsize */
|
||
|
#define JNL_DEF_ALIGNSIZE (1 << 7) /* 128 disk blocks effectively 64K alignsize */
|
||
|
#endif
|
||
|
#define JNL_MAX_ALIGNSIZE (1 << 22) /* 4194304 disk blocks effectively 2G alignsize */
|
||
|
#define JNL_REC_START_BNDRY 8
|
||
|
#define MAX_LOGI_JNL_REC_SIZE (MAX_DB_BLK_SIZE) /* maximum logical journal record size */
|
||
|
#define MAX_JNL_REC_SIZE (MAX_LOGI_JNL_REC_SIZE + DISK_BLOCK_SIZE) /* one more disk-block for PBLK record header/footer */
|
||
|
|
||
|
#ifdef GTM_TRIGGER
|
||
|
/* Define maximum size that $ZTWORMHOLE can be. Since $ZTWORMHOLE should be able to fit in a journal record and the
|
||
|
* minimum alignsize is 128K, we do not want it to go more than 128K (that way irrespective of whatever alignsize the user
|
||
|
* specifies for the journal file, $ZTWORMHOLE will fit in the journal record). Leaving a max of 512 bytes for the
|
||
|
* journal record prefix/suffix (32-byte overhead) and MIN_ALIGN_RECLEN (see comment in JNL_MAX_RECLEN macro for why
|
||
|
* this is needed) we allow for a max of 128K-512 bytes in $ZTWORMHOLE.
|
||
|
*/
|
||
|
#define MAX_ZTWORMHOLE_LEN (128 * 1024)
|
||
|
#define MAX_ZTWORMHOLE_SIZE (MAX_ZTWORMHOLE_LEN - 512)
|
||
|
#define MAX_ZTWORM_JREC_LEN (MAX_ZTWORMHOLE_LEN - MIN_ALIGN_RECLEN)
|
||
|
#endif
|
||
|
|
||
|
#define MIN_YIELD_LIMIT 0
|
||
|
#define MAX_YIELD_LIMIT 2048
|
||
|
#define DEFAULT_YIELD_LIMIT 8
|
||
|
|
||
|
#ifdef UNIX
|
||
|
/* Have a minimum jnl-file-auto-switch-limit of 16 align boundaries (currently each align boundary is 128K) */
|
||
|
#define JNL_AUTOSWITCHLIMIT_MIN (16 * JNL_MIN_ALIGNSIZE)
|
||
|
#define JNL_AUTOSWITCHLIMIT_DEF 8386560 /* Instead of 8388607 it is adjusted for default allocation = extension = 2048 */
|
||
|
#else
|
||
|
/* Have a minimum jnl-file-auto-switch-limit of 128 align boundaries (currently each align boundary is 16K) */
|
||
|
#define JNL_AUTOSWITCHLIMIT_MIN (128 * JNL_MIN_ALIGNSIZE)
|
||
|
#define JNL_AUTOSWITCHLIMIT_DEF 8388600 /* Instead of 8388607 it is adjusted for default allocation = extension = 100 */
|
||
|
#endif
|
||
|
|
||
|
/* options (4-bytes unsigned integer) to wcs_flu() (currently flush_hdr, write_epoch, sync_epoch) are bit-wise ored */
|
||
|
#define WCSFLU_NONE 0
|
||
|
#define WCSFLU_FLUSH_HDR 1
|
||
|
#define WCSFLU_WRITE_EPOCH 2
|
||
|
#define WCSFLU_SYNC_EPOCH 4
|
||
|
#define WCSFLU_FSYNC_DB 8 /* Currently used only in Unix wcs_flu() */
|
||
|
#define WCSFLU_IN_COMMIT 16 /* Set if caller is t_end or tp_tend. See wcs_flu for explanation of when this is set */
|
||
|
#define WCSFLU_MSYNC_DB 32 /* Force a full msync if NO_MSYNC is defined. Currently used only in Unix wcs_flu(). */
|
||
|
|
||
|
/* options for error_on_jnl_file_lost */
|
||
|
#define JNL_FILE_LOST_TURN_OFF 0 /* Turn off journaling. */
|
||
|
#define JNL_FILE_LOST_ERRORS 1 /* Throw an rts_error. */
|
||
|
#define MAX_JNL_FILE_LOST_OPT JNL_FILE_LOST_ERRORS
|
||
|
|
||
|
/* EPOCHs are written unconditionally in Unix (assuming jnl is ON) while they are written only for BEFORE_IMAGE in VMS */
|
||
|
#define JNL_HAS_EPOCH(jnlfile) UNIX_ONLY(TRUE) VMS_ONLY(jnlfile->before_images)
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
#define DEFAULT_EPOCH_INTERVAL_IN_SECONDS 30 /* exercise epoch-syncing code relatively more often in DBG */
|
||
|
#else
|
||
|
#define DEFAULT_EPOCH_INTERVAL_IN_SECONDS 300
|
||
|
#endif
|
||
|
|
||
|
#define DEFAULT_EPOCH_INTERVAL SECOND2EPOCH_SECOND(DEFAULT_EPOCH_INTERVAL_IN_SECONDS) /* ***MUST*** include math.h for VMS */
|
||
|
|
||
|
#define MAX_EPOCH_INTERVAL 32767 /* in seconds. Amounts to nearly 10 hours. Don't want to keep db stale so long */
|
||
|
|
||
|
#define JNL_ENABLED(X) ((X)->jnl_state == jnl_open) /* If TRUE, journal records are to be written */
|
||
|
#define JNL_ALLOWED(X) ((X)->jnl_state != jnl_notallowed) /* If TRUE, journaling is allowed for the file */
|
||
|
#define REPL_ENABLED(X) ((X)->repl_state == repl_open) /* If TRUE, replication records are to be written */
|
||
|
#define REPL_WAS_ENABLED(X) ((X)->repl_state == repl_was_open) /* If TRUE, replication is now closed, but was open earlier */
|
||
|
/* In this state, replication records are not written */
|
||
|
#define REPL_ALLOWED(X) ((X)->repl_state != repl_closed) /* If TRUE, replication records are/were written */
|
||
|
|
||
|
/* Logical records should be written if journaling is enabled in the region OR if replication state is WAS_ON (repl_was_open).
|
||
|
* In the former case, the journal records will be written to the journal pool, journal buffer and journal file.
|
||
|
* In the latter case, the journal records will be written to the journal pool but not to the journal buffer and journal file.
|
||
|
* All code that generates logical journal records should use the below macro instead of JNL_ENABLED macro.
|
||
|
* Note that replication does not care about non-logical records (PBLK/AIMG/INCTN etc.) and hence code that generates them does
|
||
|
* not need to (and should not) use this macro.
|
||
|
*/
|
||
|
#define JNL_WRITE_LOGICAL_RECS(X) (JNL_ENABLED(X) || REPL_WAS_ENABLED(X))
|
||
|
|
||
|
/* The following macro should be used to invoke the function "jnl_write" for any logical record. This macro
|
||
|
* checks if journaling is enabled and if so invokes "jnl_write" else it invokes "jnl_write_poolonly" which
|
||
|
* writes only to the journal pool.
|
||
|
*/
|
||
|
#define JNL_WRITE_APPROPRIATE(CSA, JPC, RECTYPE, JREC, BLKPTR, JFB) \
|
||
|
{ \
|
||
|
assert(JNL_ENABLED(CSA) || REPL_WAS_ENABLED(CSA)); \
|
||
|
assert((NULL == JFB) || (RECTYPE == ((jnl_record *)(((jnl_format_buffer *)JFB)->buff))->prefix.jrec_type)); \
|
||
|
if (JNL_ENABLED(CSA)) \
|
||
|
jnl_write(JPC, RECTYPE, JREC, BLKPTR, JFB); /* write to jnlbuffer, jnlfile, jnlpool */ \
|
||
|
else \
|
||
|
jnl_write_poolonly(JPC, RECTYPE, JREC, JFB); /* write to jnlpool only */ \
|
||
|
}
|
||
|
|
||
|
#define MUEXTRACT_TYPE(A) (((A)[0]-'0')*10 + ((A)[1]-'0')) /* A is a character pointer */
|
||
|
|
||
|
#define PADDED PADDING
|
||
|
|
||
|
#ifdef BIGENDIAN
|
||
|
#define THREE_LOW_BYTES(x) ((uchar_ptr_t)((uchar_ptr_t)&x + 1))
|
||
|
#else
|
||
|
#define THREE_LOW_BYTES(x) ((uchar_ptr_t)(&x))
|
||
|
#endif
|
||
|
#define EXTTIME(S) extract_len = exttime(S, murgbl.extr_buff, extract_len)
|
||
|
|
||
|
/* This macro should be used to initialize jgbl.gbl_jrec_time to the system time. The reason is that it does additional checks. */
|
||
|
#define SET_GBL_JREC_TIME \
|
||
|
{ \
|
||
|
assert(!jgbl.dont_reset_gbl_jrec_time); \
|
||
|
JNL_SHORT_TIME(jgbl.gbl_jrec_time); \
|
||
|
}
|
||
|
|
||
|
/* This macro ensures that journal records are written in non-decreasing time order in each journal file.
|
||
|
* It is passed the time field to adjust and a pointer to the journal buffer of the region.
|
||
|
* The journal buffer holds the timestamp of the most recently written journal record.
|
||
|
*/
|
||
|
#define ADJUST_GBL_JREC_TIME(jgbl, jbp) \
|
||
|
{ \
|
||
|
if (jgbl.gbl_jrec_time < jbp->prev_jrec_time) \
|
||
|
{ \
|
||
|
assert(!jgbl.dont_reset_gbl_jrec_time); \
|
||
|
jgbl.gbl_jrec_time = jbp->prev_jrec_time; \
|
||
|
} \
|
||
|
}
|
||
|
|
||
|
/* Check if journal file is usable from the fields in the file header.
|
||
|
* Currently, the fields tested are LABEL and ENDIANNESS.
|
||
|
*/
|
||
|
#define JNL_HDR_ENDIAN_OFFSET 8
|
||
|
|
||
|
#define CHECK_JNL_FILE_IS_USABLE(JFH, STATUS, DO_GTMPUTMSG, JNL_FN_LEN, JNL_FN) \
|
||
|
{ \
|
||
|
boolean_t check_failed = FALSE; \
|
||
|
uint4 lcl_status; \
|
||
|
\
|
||
|
error_def(ERR_JNLBADLABEL); \
|
||
|
error_def(ERR_JNLENDIANLITTLE); \
|
||
|
error_def(ERR_JNLENDIANBIG); \
|
||
|
\
|
||
|
assert(JNL_HDR_ENDIAN_OFFSET == OFFSETOF(jnl_file_header, is_little_endian)); \
|
||
|
if (0 != MEMCMP_LIT(JFH->label, JNL_LABEL_TEXT)) \
|
||
|
{ \
|
||
|
lcl_status = ERR_JNLBADLABEL; \
|
||
|
check_failed = TRUE; \
|
||
|
} \
|
||
|
BIGENDIAN_ONLY( \
|
||
|
else if (JFH->is_little_endian) \
|
||
|
{ \
|
||
|
lcl_status = ERR_JNLENDIANLITTLE; \
|
||
|
check_failed = TRUE; \
|
||
|
} \
|
||
|
) \
|
||
|
LITTLEENDIAN_ONLY( \
|
||
|
else if (!JFH->is_little_endian) \
|
||
|
{ \
|
||
|
lcl_status = ERR_JNLENDIANBIG; \
|
||
|
check_failed = TRUE; \
|
||
|
} \
|
||
|
) \
|
||
|
/* Currently, we can do one gtm_putmsg for any of the above 3 error messages \
|
||
|
* because all of them have a fao count of 2 and expect jnl_fn_len and jnl_fn \
|
||
|
* as arguments. If a new error gets added and has a different fao format, \
|
||
|
* then the below gtm_putmsg has to be done differently based on that error. \
|
||
|
*/ \
|
||
|
if (check_failed) \
|
||
|
{ \
|
||
|
STATUS = lcl_status; \
|
||
|
if (DO_GTMPUTMSG) \
|
||
|
gtm_putmsg(VARLSTCNT(4) lcl_status, 2, JNL_FN_LEN, JNL_FN); \
|
||
|
} \
|
||
|
}
|
||
|
|
||
|
/* Token generation used in non-replicated journaled environment. Note the assumption here
|
||
|
that SIZEOF(token_split_t) == SIZEOF(token_build) which will be asserted in gvcst_init().
|
||
|
The TOKEN_SET macro below depends on this assumption.
|
||
|
*/
|
||
|
typedef struct token_split_t_struct
|
||
|
{
|
||
|
# ifdef BIGENDIAN
|
||
|
uint4 process_id;
|
||
|
uint4 local_tn;
|
||
|
# else
|
||
|
uint4 local_tn;
|
||
|
uint4 process_id;
|
||
|
# endif
|
||
|
} token_split_t;
|
||
|
|
||
|
typedef union
|
||
|
{
|
||
|
token_split_t t_piece;
|
||
|
token_num token;
|
||
|
} token_build;
|
||
|
|
||
|
/* To assist in setting token value, the following macro is supplied to handle the two token parts */
|
||
|
#define TOKEN_SET(BASE, TN, PID) (((token_build_ptr_t)(BASE))->t_piece.local_tn = (uint4)(TN), \
|
||
|
((token_build_ptr_t)(BASE))->t_piece.process_id = (PID))
|
||
|
|
||
|
enum jpv_types
|
||
|
{
|
||
|
CURR_JPV = 0,
|
||
|
ORIG_JPV,
|
||
|
JPV_COUNT
|
||
|
};
|
||
|
/* Note we have two process verctors now for a pini record */
|
||
|
typedef struct jnl_process_vector_struct /* name needed since this is used in cmmdef.h for "pvec" member */
|
||
|
{
|
||
|
uint4 jpv_pid; /* Process id */
|
||
|
int4 jpv_image_count; /* Image activations [VMS only] */
|
||
|
jnl_proc_time jpv_time; /* Timestamp of the process genarating this.
|
||
|
(This could be different than the journal record timestamp) */
|
||
|
jnl_proc_time jpv_login_time; /* Used for process initialization time */
|
||
|
char jpv_node[JPV_LEN_NODE], /* Node name */
|
||
|
jpv_user[JPV_LEN_USER], /* User name */
|
||
|
jpv_prcnam[JPV_LEN_PRCNAM], /* Process name [VMS only] */
|
||
|
jpv_terminal[JPV_LEN_TERMINAL]; /* Login terminal */
|
||
|
unsigned char jpv_mode; /* a la JPI$_MODE [VMS only] */
|
||
|
int4 filler;
|
||
|
/* SIZEOF(jnl_process_vector) must be a multiple of SIZEOF(int4) */
|
||
|
} jnl_process_vector;
|
||
|
|
||
|
enum pini_rec_stat
|
||
|
{
|
||
|
IGNORE_PROC = 0,
|
||
|
ACTIVE_PROC = 1,
|
||
|
FINISHED_PROC = 2,
|
||
|
BROKEN_PROC = 4
|
||
|
};
|
||
|
|
||
|
typedef struct pini_list
|
||
|
{
|
||
|
uint4 pini_addr;
|
||
|
uint4 new_pini_addr; /* used in forward phase of recovery */
|
||
|
jnl_process_vector jpv; /* CURR_JPV. Current process's JPV. For GTCM server we also use this. */
|
||
|
jnl_process_vector origjpv; /* ORIG_JPV. Used for GTCM client only */
|
||
|
enum pini_rec_stat state; /* used for show qualifier */
|
||
|
} pini_list_struct;
|
||
|
|
||
|
enum jnl_record_type
|
||
|
{
|
||
|
#define JNL_TABLE_ENTRY(rectype, extract_rtn, label, update, fixed_size, is_replicated) rectype,
|
||
|
#include "jnl_rec_table.h"
|
||
|
#undef JNL_TABLE_ENTRY
|
||
|
|
||
|
JRT_RECTYPES /* Total number of JOURNAL record types */
|
||
|
};
|
||
|
|
||
|
#include "jnl_typedef.h"
|
||
|
|
||
|
enum jnl_state_codes
|
||
|
{
|
||
|
jnl_notallowed,
|
||
|
jnl_closed,
|
||
|
jnl_open
|
||
|
};
|
||
|
|
||
|
enum repl_state_codes
|
||
|
{
|
||
|
repl_closed, /* region not replicated, no records are written */
|
||
|
repl_open, /* region is replicated, and records are written */
|
||
|
repl_was_open /* region is currently not replicated, but it was earlier; jnl_file_lost() changes open to was_open */
|
||
|
};
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
trans_num eov_tn; /* curr_tn is saved as eov_tn by jnl_write_epoch. Used by recover/rollback */
|
||
|
volatile trans_num epoch_tn; /* Transaction number for current epoch */
|
||
|
seq_num end_seqno; /* reg_seqno saved by jnl_write_epoch. Used by recover/rollback */
|
||
|
int4 min_write_size, /* if unwritten data gets to this size, write it */
|
||
|
max_write_size, /* maximum size of any single write */
|
||
|
size; /* buffer size */
|
||
|
int4 epoch_interval; /* Time between successive epochs in epoch-seconds */
|
||
|
boolean_t before_images; /* If TRUE, before-image processing is enabled */
|
||
|
/* end not volatile QUAD */
|
||
|
uintszofptr_t buff_off; /* relative offset to filesystem-block-size aligned buffer start */
|
||
|
volatile int4 free; /* relative index of first byte to write in buffer */
|
||
|
volatile uint4 freeaddr, /* virtual on-disk address which will correspond to free, when it is written */
|
||
|
end_of_data, /* Synched offset updated by jnl_write_epoch. Used by recover/rollback */
|
||
|
filesize; /* highest virtual address available in the file (units in disk-blocks) */
|
||
|
/* end mainline QUAD */
|
||
|
volatile int4 blocked;
|
||
|
volatile uint4 fsync_dskaddr; /* dskaddr upto which fsync is done */
|
||
|
volatile int4 dsk; /* relative index of 1st byte to write to disk;
|
||
|
* if free == dsk, buffer is empty */
|
||
|
volatile int4 wrtsize; /* size of write in progress */
|
||
|
volatile uint4 dskaddr, /* virtual on-disk address corresponding to dsk */
|
||
|
now_writer, /* current owner of io_in_prog (VMS-only) */
|
||
|
image_count; /* for VMS is_proc_alive */
|
||
|
volatile struct /* must be at least word aligned for memory coherency */
|
||
|
{
|
||
|
short cond;
|
||
|
unsigned short length;
|
||
|
int4 dev_specific;
|
||
|
} iosb;
|
||
|
/* alignsize is removed and log2_of_alignsize introduced */
|
||
|
uint4 log2_of_alignsize; /* Ceiling of log2(alignsize) */
|
||
|
jnl_tm_t eov_timestamp; /* jgbl.gbl_jrec_time saved by jnl_write_epoch. Used by recover/rollback */
|
||
|
uint4 cycle; /* shared copy of the number of the current journal file generation */
|
||
|
volatile int4 qiocnt, /* Number of qio's issued */
|
||
|
bytcnt, /* Number of bytes written */
|
||
|
errcnt, /* Number of errors during writing */
|
||
|
reccnt[JRT_RECTYPES]; /* Number of records written per opcode */
|
||
|
int filler_align[35 - JRT_RECTYPES]; /* So buff below starts on even (QW) keel */
|
||
|
/* Note the above filler will fail if JRT_RECTYPES grows beyond 31 elements and give compiler warning in VMS
|
||
|
* if JRT_RECTYPES equals 31. In that case, change the start num to the next odd number above MAX(31,JRT_RECTYPES).
|
||
|
*/
|
||
|
volatile jnl_tm_t prev_jrec_time; /* to ensure that time never decreases across successive jnl records */
|
||
|
volatile int4 free_update_pid; /* pid that is updating jb->free and jb->freeaddr */
|
||
|
volatile uint4 next_epoch_time; /* Time when next epoch is to be written (in epoch-seconds) */
|
||
|
volatile boolean_t need_db_fsync; /* need an fsync of the db file */
|
||
|
volatile int4 io_in_prog; /* VMS only: write in progress indicator (NOTE: must manipulate
|
||
|
only with interlocked instructions */
|
||
|
uint4 enospc_errcnt; /* number of times jb->errcnt was last incremented due to ENOSPC error
|
||
|
* when writing to this journal file */
|
||
|
uint4 max_jrec_len; /* copy of max_jrec_len from journal file header */
|
||
|
uint4 fs_block_size; /* underlying journal file system block size;
|
||
|
* primarily used in Unix, 512 in VMS */
|
||
|
/* CACHELINE_PAD macros provide spacing between the following latches so that they do
|
||
|
not interfere with each other which can happen if they fall in the same data cacheline
|
||
|
of a processor.
|
||
|
*/
|
||
|
CACHELINE_PAD(SIZEOF(global_latch_t), 0) /* start next latch at a different cacheline than previous fields */
|
||
|
global_latch_t io_in_prog_latch; /* UNIX only: write in progress indicator */
|
||
|
CACHELINE_PAD(SIZEOF(global_latch_t), 1) /* pad enough space so next latch falls in different cacheline */
|
||
|
global_latch_t fsync_in_prog_latch; /* fsync in progress indicator */
|
||
|
CACHELINE_PAD(SIZEOF(global_latch_t), 2) /* pad enough space so next non-filler byte falls in different cacheline */
|
||
|
/**********************************************************************************************/
|
||
|
/* Important: must keep header structure quadword (8 byte) aligned for buffers used in QIO's */
|
||
|
/**********************************************************************************************/
|
||
|
unsigned char buff[1]; /* Actually buff[size] */
|
||
|
} jnl_buffer;
|
||
|
|
||
|
#define FIX_NONZERO_FREE_UPDATE_PID(csa, jbp) \
|
||
|
{ \
|
||
|
assert(csa->now_crit); /* hold crit before manipulating freeaddr/free */ \
|
||
|
assert(jbp->free_update_pid); \
|
||
|
UNIX_ONLY(assert(!is_proc_alive(jbp->free_update_pid, 0));) \
|
||
|
VMS_ONLY(assert(FALSE);) /* secshr_db_clnup should have cleaned up this field even in case of STOP/ID */ \
|
||
|
if ((jbp->freeaddr % jbp->size) != jbp->free) \
|
||
|
{ /* Previous process in jnl_write got killed after incrementing freeaddr but before incrementing \
|
||
|
* free. Recalculate jbp->free based on current value of jbp->freeaddr. */ \
|
||
|
jbp->free = jbp->freeaddr % jbp->size; \
|
||
|
jbp->free_update_pid = 0; \
|
||
|
} \
|
||
|
DBG_CHECK_JNL_BUFF_FREEADDR(jbp); \
|
||
|
}
|
||
|
|
||
|
#define DBG_CHECK_JNL_BUFF_FREEADDR(jbp) \
|
||
|
{ \
|
||
|
assert((jbp->freeaddr % jbp->size) == jbp->free); \
|
||
|
assert((jbp->freeaddr >= jbp->dskaddr) \
|
||
|
|| (gtm_white_box_test_case_enabled \
|
||
|
&& (WBTEST_JNL_FILE_LOST_DSKADDR == gtm_white_box_test_case_number))); \
|
||
|
}
|
||
|
|
||
|
#ifdef DB64
|
||
|
# ifdef __osf__
|
||
|
# pragma pointer_size(save)
|
||
|
# pragma pointer_size(long)
|
||
|
# else
|
||
|
# error UNSUPPORTED PLATFORM
|
||
|
# endif
|
||
|
#endif
|
||
|
|
||
|
typedef jnl_buffer *jnl_buffer_ptr_t;
|
||
|
typedef token_build *token_build_ptr_t;
|
||
|
|
||
|
#ifdef DB64
|
||
|
# ifdef __osf__
|
||
|
# pragma pointer_size(restore)
|
||
|
# endif
|
||
|
#endif
|
||
|
|
||
|
typedef struct jnl_private_control_struct
|
||
|
{
|
||
|
jnl_buffer_ptr_t jnl_buff; /* pointer to shared memory */
|
||
|
gd_region *region; /* backpointer to region head */
|
||
|
fd_type channel, /* output channel, aka fd in UNIX */
|
||
|
old_channel; /* VMS only - for dealing with deferred deassign */
|
||
|
gd_id fileid; /* currently initialized and used only by source-server */
|
||
|
vms_lock_sb *jnllsb; /* VMS only */
|
||
|
uint4 pini_addr, /* virtual on-disk address for JRT_PINI record, if journaling */
|
||
|
new_freeaddr;
|
||
|
int4 temp_free; /* M Temp copy of free relative index until full write done */
|
||
|
double filler_q0; /* reset QUAD end mainline */
|
||
|
int4 new_dsk; /* A VMS only */
|
||
|
uint4 new_dskaddr; /* A VMS only */
|
||
|
int4 status; /* A for error reporting */
|
||
|
volatile boolean_t dsk_update_inprog; /* A VMS only */
|
||
|
volatile boolean_t qio_active; /* jnl buffer write in progress in THIS process (recursion indicator) */
|
||
|
boolean_t fd_mismatch; /* TRUE when jpc->channel does not point to the active journal */
|
||
|
volatile boolean_t sync_io; /* TRUE if the process is using O_SYNC/O_DSYNC for this jnl (UNIX) */
|
||
|
/* TRUE if writers open NOCACHING to bypass XFC cache (VMS) */
|
||
|
boolean_t error_reported; /* TRUE if jnl_file_lost already reported the journaling error */
|
||
|
uint4 status2; /* for secondary error status, currently used only in VMS */
|
||
|
uint4 cycle; /* private copy of the number of this journal file generation */
|
||
|
} jnl_private_control;
|
||
|
|
||
|
typedef enum
|
||
|
{
|
||
|
JNL_KILL,
|
||
|
JNL_SET,
|
||
|
JNL_ZKILL,
|
||
|
# ifdef GTM_TRIGGER
|
||
|
JNL_ZTWORM,
|
||
|
JNL_ZTRIG,
|
||
|
# endif
|
||
|
JA_MAX_TYPES
|
||
|
} jnl_action_code;
|
||
|
|
||
|
typedef enum
|
||
|
{
|
||
|
#define MUEXT_TABLE_ENTRY(muext_rectype, code0, code1) muext_rectype,
|
||
|
#include "muext_rec_table.h"
|
||
|
#undef MUEXT_TABLE_ENTRY
|
||
|
|
||
|
MUEXT_MAX_TYPES /* Total number of EXTRACT JOURNAL record types */
|
||
|
} muextract_type;
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
jnl_action_code operation;
|
||
|
uint4 nodeflags;
|
||
|
} jnl_action;
|
||
|
|
||
|
#define JNL_FENCE_LIST_END ((sgmnt_addrs *)-1L)
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
sgmnt_addrs *fence_list;
|
||
|
int level;
|
||
|
token_num token;
|
||
|
} jnl_fence_control;
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
uint4 jrec_type : 8; /* Offset:0 :: Actually, enum jnl_record_type */
|
||
|
uint4 forwptr : 24; /* Offset:1 :: Offset to beginning of next record */
|
||
|
off_jnl_t pini_addr; /* Offset:4 :: Offset in the journal file which contains pini record */
|
||
|
jnl_tm_t time; /* Offset:8 :: 4-byte time stamp both for UNIX and VMS */
|
||
|
uint4 checksum; /* Offset:12 :: Generated from journal record */
|
||
|
trans_num tn; /* Offset:16 */
|
||
|
} jrec_prefix; /* 24-byte */
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
uint4 backptr : 24; /* Offset to beginning of current record */
|
||
|
uint4 suffix_code : 8; /* JNL_REC_SUFFIX_CODE */
|
||
|
} jrec_suffix; /* 4-byte */
|
||
|
|
||
|
typedef union
|
||
|
{
|
||
|
seq_num jnl_seqno;
|
||
|
token_num token;
|
||
|
} token_seq_t;
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
char label[SIZEOF(JNL_LABEL_TEXT) - 1];
|
||
|
char is_little_endian; /* this field's offset (JNL_HDR_ENDIAN_OFFSET) should not change
|
||
|
* across journal versions and is checked right after reading the header.
|
||
|
*/
|
||
|
char filler_align8[7];
|
||
|
jnl_process_vector who_created, /* Process who created */
|
||
|
who_opened; /* Process who last opened */
|
||
|
jnl_proc_time bov_timestamp, /* 8-byte time when journal was created */
|
||
|
eov_timestamp; /* 8-byte time when journal was last updated
|
||
|
Updated by cre_jnl_file/jnl_file_extend/jnl_file_close */
|
||
|
trans_num bov_tn, /* Beginning journal record's transaction number */
|
||
|
eov_tn; /* End transaction number.
|
||
|
Updated by cre_jnl_file/jnl_file_extend/jnl_file_close */
|
||
|
seq_num start_seqno; /* reg_seqno when this journal file was created */
|
||
|
seq_num end_seqno; /* reg_seqno when this journal file was closed or last extended.
|
||
|
Updated by cre_jnl_file/jnl_file_extend/jnl_file_close */
|
||
|
off_jnl_t end_of_data; /* Offset of beginning of last record.
|
||
|
Updated by cre_jnl_file/jnl_file_extend/jnl_file_close */
|
||
|
off_jnl_t prev_recov_end_of_data; /* Recovered/Rolled back journal's turn around point's offset.
|
||
|
This offset was supposed to have EOF_RECORD before recover switched journal.
|
||
|
A non-zero value means this journal was recovered and had the turn around point. */
|
||
|
off_jnl_t virtual_size; /* Allocation + n * Extension (in blocks). jnl_file_extend updates it */
|
||
|
boolean_t crash; /* crashed before jnl_file_close() completed */
|
||
|
boolean_t recover_interrupted; /* true when recover creates the journal file; false after success. */
|
||
|
off_jnl_t turn_around_offset; /* At turn around point journal record's (EPOCH) offset */
|
||
|
jnl_tm_t turn_around_time; /* At turn around point journal record's timestamp */
|
||
|
boolean_t before_images; /* before image enabled in this journal */
|
||
|
uint4 alignsize; /* align size of journal (where a valid record start) */
|
||
|
int4 epoch_interval; /* Time between successive epochs in epoch-seconds */
|
||
|
int4 repl_state; /* To state whether replication is turned on for this journal file */
|
||
|
uint4 autoswitchlimit;/* Limit in disk blocks (max 4GBytes) when jnl should be auto switched */
|
||
|
uint4 jnl_alq; /* initial allocation (in blocks) */
|
||
|
uint4 jnl_deq; /* extension (in blocks) */
|
||
|
#ifdef VMS
|
||
|
boolean_t update_disabled;/* If the secondary side has database update disabled. For rollback. */
|
||
|
#else
|
||
|
boolean_t filler_update_disabled; /* obsoleted as part of multi-site replication changes */
|
||
|
#endif
|
||
|
int4 max_jrec_len; /* Maximum length in bytes of a journal record.
|
||
|
* Although computed from the database block size, we need this
|
||
|
* stored as well in case database is not available */
|
||
|
uint4 data_file_name_length; /* Length of data_file_name */
|
||
|
uint4 prev_jnl_file_name_length; /* Length of prev_jnl_file_name */
|
||
|
uint4 next_jnl_file_name_length; /* Length of next_jnl_file_name */
|
||
|
uint4 checksum; /* Calculate from journal file id */
|
||
|
uint4 prev_recov_blks_to_upgrd_adjust; /* amount to adjust filehdr "blks_to_upgrd" if ever
|
||
|
* backward recovery goes back past this journal file */
|
||
|
unsigned char data_file_name[JNL_NAME_SIZE]; /* Database file name */
|
||
|
unsigned char prev_jnl_file_name[JNL_NAME_SIZE]; /* Previous generation journal file name */
|
||
|
unsigned char next_jnl_file_name[JNL_NAME_SIZE]; /* Next generation journal file name */
|
||
|
/* encryption related fields */
|
||
|
uint4 is_encrypted;
|
||
|
char encryption_hash[GTMCRYPT_RESERVED_HASH_LEN];
|
||
|
|
||
|
/* filler remaining */
|
||
|
char filler[696];
|
||
|
} jnl_file_header;
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
int4 status,
|
||
|
alloc,
|
||
|
extend,
|
||
|
buffer;
|
||
|
sgmnt_data_ptr_t csd;
|
||
|
seq_num reg_seqno;
|
||
|
unsigned char jnl[JNL_NAME_SIZE],
|
||
|
*fn;
|
||
|
uint4 max_jrec_len;
|
||
|
short fn_len,
|
||
|
jnl_len,
|
||
|
jnl_def_len;
|
||
|
bool before_images;
|
||
|
bool filler_bool[1];
|
||
|
uint4 alignsize;
|
||
|
int4 autoswitchlimit; /* limit in disk blocks (8388607 blocks)
|
||
|
* when jnl should be auto switched */
|
||
|
int4 epoch_interval; /* Time between successive epochs in epoch-seconds */
|
||
|
char *prev_jnl;
|
||
|
int4 prev_jnl_len;
|
||
|
int4 jnl_state; /* current csd->jnl_state */
|
||
|
int4 repl_state;
|
||
|
uint4 status2; /* for secondary error status information in VMS */
|
||
|
boolean_t no_rename;
|
||
|
boolean_t no_prev_link;
|
||
|
int4 blks_to_upgrd; /* Blocks not at current block version level */
|
||
|
uint4 checksum;
|
||
|
uint4 free_blocks; /* free blocks counter at time of epoch */
|
||
|
uint4 total_blks; /* total blocks counter at time of epoch */
|
||
|
uint4 is_encrypted;
|
||
|
char encryption_hash[GTMCRYPT_HASH_LEN];
|
||
|
} jnl_create_info;
|
||
|
|
||
|
/* Journal record definitions */
|
||
|
|
||
|
#define jnl_str_len_t uint4 /* 4 byte length (which is in turn split into bit fields below) */
|
||
|
|
||
|
/* Bit masks for the "nodeflags" field. Note that there is no flag to indicate whether this update actually invoked any triggers.
|
||
|
* That is because we have to format the journal record BEFORE invoking any triggers (that way the triggering update comes ahead
|
||
|
* of its corresponding triggered updates in the journal file as this ordering is relied upon by the update process) and as part
|
||
|
* of formatting, we also compute the checksum that includes the "nodeflags" field and so fixing this field AFTER trigger
|
||
|
* invocation to reflect if any triggers were invoked would mean recomputing the checksum all over again. Currently there is no
|
||
|
* need for the "triggers actually invoked" bit. If it is later desired, care should be taken to recompute the checksum.
|
||
|
*/
|
||
|
#define JS_NOT_REPLICATED_MASK (1 << 0) /* 1 if this update should NOT be replicated.
|
||
|
* All updates done inside of a trigger and a SET redo (because of changes to $ztval)
|
||
|
* fall in this category.
|
||
|
*/
|
||
|
#define JS_HAS_TRIGGER_MASK (1 << 1) /* 1 if the global being updated had at least one trigger defined (not necessarily
|
||
|
* invoked for this particular update)
|
||
|
*/
|
||
|
#define JS_NULL_ZTWORM_MASK (1 << 2) /* 1 if $ZTWORMHOLE for this update should be "" string, 0 otherwise */
|
||
|
#define JS_SKIP_TRIGGERS_MASK (1 << 3) /* 1 if MUPIP LOAD update so triggers are not invoked on replay by update process */
|
||
|
#define JS_MAX_MASK (1 << 8) /* max of 8 bits we have for mask */
|
||
|
|
||
|
/* Note that even though mumps_node, ztworm_str, ztrig_str and align_str are members defined as type "jnl_string" below,
|
||
|
* the "nodeflags" field is initialized to non-zero values ONLY in the case of the mumps_node member.
|
||
|
* For ztworm_str and align_str, nodeflags is guaranteed to be zero so the 24-bit "length" member
|
||
|
* can even be used as a 32-bit length (if necessary) without issues. This is why nodeflags is
|
||
|
* defined in a different order (BEFORE or AFTER the "length" member) based on big-endian or little-endian.
|
||
|
*/
|
||
|
typedef struct
|
||
|
{
|
||
|
# ifdef BIGENDIAN
|
||
|
unsigned int nodeflags : 8;
|
||
|
unsigned int length : 24;
|
||
|
# else
|
||
|
unsigned int length : 24;
|
||
|
unsigned int nodeflags : 8;
|
||
|
# endif
|
||
|
char text[1]; /* Actually text[length] */
|
||
|
} jnl_string;
|
||
|
|
||
|
typedef struct jnl_format_buff_struct
|
||
|
{
|
||
|
que_ent free_que;
|
||
|
struct jnl_format_buff_struct *next;
|
||
|
# ifdef GTM_TRIGGER
|
||
|
struct jnl_format_buff_struct *prev;
|
||
|
# endif
|
||
|
enum jnl_record_type rectype;
|
||
|
int4 record_size;
|
||
|
char *buff;
|
||
|
uint4 checksum;
|
||
|
jnl_action ja;
|
||
|
# ifdef GTM_CRYPT
|
||
|
char *alt_buff; /* for storing the unencrypted jnl *SET and *KILL records to be pushed
|
||
|
* into the jnl pool. */
|
||
|
NON_GTM64_ONLY(int4 dummy_filler;) /* for alignment in 32 bit machines. */
|
||
|
# endif
|
||
|
} jnl_format_buffer;
|
||
|
|
||
|
/* All fixed size records are 8-byte-multiple size.
|
||
|
* All variable size records are made 8-byte multiple size by run-time process */
|
||
|
|
||
|
/* struct_jrec_upd for non-TP, TP or ZTP. For replication we use 8-byte jnl_seqno. Otherwise we use 8-byte token.
|
||
|
* Currently we dont support ZTP + replication.
|
||
|
*/
|
||
|
typedef struct /* variable length */
|
||
|
{
|
||
|
jrec_prefix prefix;
|
||
|
token_seq_t token_seq; /* must start at 8-byte boundary */
|
||
|
uint4 update_num; /* 'n' where this is the nth journaled update (across all regions) in this TP
|
||
|
* transaction. n=1 for the first update inside TP, 2 for the second update
|
||
|
* inside TP and so on. Needed so journal recovery and update process can play
|
||
|
* all the updates inside of one TP transaction in the exact same order as GT.M.
|
||
|
*/
|
||
|
unsigned short filler_short;
|
||
|
unsigned short num_participants; /* # of regions that wrote a TCOM record in their jnl files.
|
||
|
* Currently written only for TSET/TKILL/TZTWORM records.
|
||
|
* Uninitialized for all other types of SET/KILL/ZTWORM records.
|
||
|
*/
|
||
|
jnl_string mumps_node; /* For set/kill/zkill : {jnl_str_len_t key_len, char key[key_len]} */
|
||
|
/* For set additionally : {mstr_len_t data_len, char data[data_len]} */
|
||
|
} struct_jrec_upd;
|
||
|
|
||
|
/* $ztwormhole record */
|
||
|
typedef struct /* variable length */
|
||
|
{
|
||
|
jrec_prefix prefix;
|
||
|
token_seq_t token_seq; /* must start at 8-byte boundary */
|
||
|
uint4 update_num; /* 'n' where this is the nth journaled update (across all regions) in this TP
|
||
|
* transaction. n=1 for the first update inside TP, 2 for the second update
|
||
|
* inside TP and so on. Needed so journal recovery and update process can play
|
||
|
* all the updates inside of one TP transaction in the exact same order as GT.M.
|
||
|
*/
|
||
|
unsigned short filler_short;
|
||
|
unsigned short num_participants; /* # of regions that wrote a TCOM record in their jnl files.
|
||
|
* Currently written only for TSET/TKILL/TZTWORM records.
|
||
|
* Uninitialized for all other types of SET/KILL/ZTWORM records.
|
||
|
*/
|
||
|
jnl_string ztworm_str; /* jnl_str_len_t ztworm_str_len, char ztworm_str[ztworm_str_len]} */
|
||
|
} struct_jrec_ztworm;
|
||
|
|
||
|
#define INVALID_UPDATE_NUM (uint4)-1
|
||
|
|
||
|
typedef struct /* variable length */
|
||
|
{
|
||
|
jrec_prefix prefix;
|
||
|
block_id blknum;
|
||
|
uint4 bsiz;
|
||
|
enum db_ver ondsk_blkver; /* Previous version of block from cache_rec */
|
||
|
int4 filler;
|
||
|
char blk_contents[1]; /* Actually blk_contents[bsiz] */
|
||
|
} struct_jrec_blk;
|
||
|
|
||
|
typedef struct /* variable length */
|
||
|
{
|
||
|
jrec_prefix prefix;
|
||
|
jnl_string align_str;
|
||
|
/* Note: Actual string (potentially 0-length too) follows the align_string and then jrec_suffix */
|
||
|
} struct_jrec_align;
|
||
|
|
||
|
/* Please change the "GBLDEF struct_jrec_tcom" initialization, if below is changed */
|
||
|
typedef struct /* fixed length */
|
||
|
{
|
||
|
jrec_prefix prefix;
|
||
|
token_seq_t token_seq; /* must start at 8-byte boundary */
|
||
|
unsigned short filler_short;
|
||
|
unsigned short num_participants; /* # of regions that wrote a TCOM record in their jnl files */
|
||
|
char jnl_tid[TID_STR_SIZE];
|
||
|
jrec_suffix suffix;
|
||
|
} struct_jrec_tcom;
|
||
|
|
||
|
/* Please change the "static struct_jrec_ztcom" initialization in op_ztcommit.c, if below is changed */
|
||
|
typedef struct /* fixed length */
|
||
|
{
|
||
|
jrec_prefix prefix;
|
||
|
token_num token; /* must start at 8-byte boundary */
|
||
|
unsigned short filler_short;
|
||
|
unsigned short participants; /* # of regions that wrote ZTCOM record in their jnl files for this fenced tn */
|
||
|
jrec_suffix suffix;
|
||
|
} struct_jrec_ztcom;
|
||
|
|
||
|
/* Below are different inctn_detail_*_t type definitions based on the inctn record opcode.
|
||
|
* Each of them need to ensure the following.
|
||
|
* a) SIZEOF(inctn_detail_*_t) is identical.
|
||
|
* b) "opcode" member is at the same offset.
|
||
|
* c) "suffix" is the last member.
|
||
|
* Any new inctn_detail_*_t type definitions should have corresponding code changes in jnl_write_inctn_rec.c
|
||
|
*/
|
||
|
typedef struct
|
||
|
{
|
||
|
block_id blknum; /* block that got upgraded or downgraded (opcode = inctn_blk*grd) */
|
||
|
uint4 filler_uint4;
|
||
|
unsigned short filler_short;
|
||
|
unsigned short opcode;
|
||
|
jrec_suffix suffix;
|
||
|
} inctn_detail_blknum_t;
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
int4 blks_to_upgrd_delta; /* Delta to adjust csd->blks_to_upgrade (opcode = inctn_gdsfilext_*) */
|
||
|
uint4 filler_uint4;
|
||
|
unsigned short filler_short;
|
||
|
unsigned short opcode;
|
||
|
jrec_suffix suffix;
|
||
|
} inctn_detail_blks2upgrd_t;
|
||
|
|
||
|
typedef union
|
||
|
{
|
||
|
inctn_detail_blknum_t blknum_struct;
|
||
|
inctn_detail_blks2upgrd_t blks2upgrd_struct;
|
||
|
} inctn_detail_t;
|
||
|
|
||
|
typedef struct /* fixed length */
|
||
|
{
|
||
|
jrec_prefix prefix;
|
||
|
inctn_detail_t detail;
|
||
|
/* jrec_suffix is already part of inctn_detail_t */
|
||
|
} struct_jrec_inctn;
|
||
|
|
||
|
typedef struct /* fixed length */
|
||
|
{
|
||
|
jrec_prefix prefix;
|
||
|
jnl_process_vector process_vector[JPV_COUNT];
|
||
|
int4 filler;
|
||
|
jrec_suffix suffix;
|
||
|
} struct_jrec_pini;
|
||
|
|
||
|
typedef struct /* fixed length */
|
||
|
{
|
||
|
jrec_prefix prefix;
|
||
|
uint4 filler;
|
||
|
jrec_suffix suffix;
|
||
|
} struct_jrec_pfin;
|
||
|
|
||
|
/* Following 3 are same structures. In case we change it in future, let's define them separately */
|
||
|
typedef struct /* fixed length */
|
||
|
{
|
||
|
jrec_prefix prefix;
|
||
|
seq_num jnl_seqno; /* must start at 8-byte boundary */
|
||
|
uint4 filler;
|
||
|
jrec_suffix suffix;
|
||
|
} struct_jrec_null;
|
||
|
|
||
|
typedef struct /* fixed length */
|
||
|
{
|
||
|
jrec_prefix prefix;
|
||
|
seq_num jnl_seqno; /* must start at 8-byte boundary */
|
||
|
uint4 blks_to_upgrd; /* blocks-to-upgrade counter at time of epoch */
|
||
|
uint4 free_blocks; /* free blocks counter at time of epoch */
|
||
|
uint4 total_blks; /* total blocks counter at time of epoch */
|
||
|
jrec_suffix suffix;
|
||
|
} struct_jrec_epoch;
|
||
|
|
||
|
typedef struct /* fixed length */
|
||
|
{
|
||
|
jrec_prefix prefix;
|
||
|
seq_num jnl_seqno; /* must start at 8-byte boundary */
|
||
|
uint4 filler;
|
||
|
jrec_suffix suffix;
|
||
|
} struct_jrec_eof;
|
||
|
|
||
|
typedef union
|
||
|
{
|
||
|
jrec_prefix prefix;
|
||
|
struct_jrec_upd jrec_set_kill;
|
||
|
struct_jrec_ztworm jrec_ztworm;
|
||
|
struct_jrec_blk jrec_pblk,
|
||
|
jrec_aimg;
|
||
|
struct_jrec_align jrec_align;
|
||
|
/** All below are fixed size and above are variable size records */
|
||
|
struct_jrec_tcom jrec_tcom;
|
||
|
struct_jrec_ztcom jrec_ztcom;
|
||
|
struct_jrec_inctn jrec_inctn;
|
||
|
struct_jrec_pini jrec_pini;
|
||
|
struct_jrec_pfin jrec_pfin;
|
||
|
struct_jrec_null jrec_null;
|
||
|
struct_jrec_epoch jrec_epoch;
|
||
|
struct_jrec_eof jrec_eof;
|
||
|
} jnl_record;
|
||
|
|
||
|
|
||
|
/* Macro to access fixed size record's size */
|
||
|
#define TCOM_RECLEN SIZEOF(struct_jrec_tcom)
|
||
|
#define ZTCOM_RECLEN SIZEOF(struct_jrec_ztcom)
|
||
|
#define INCTN_RECLEN SIZEOF(struct_jrec_inctn)
|
||
|
#define PINI_RECLEN SIZEOF(struct_jrec_pini)
|
||
|
#define PFIN_RECLEN SIZEOF(struct_jrec_pfin)
|
||
|
#define NULL_RECLEN SIZEOF(struct_jrec_null)
|
||
|
#define EPOCH_RECLEN SIZEOF(struct_jrec_epoch)
|
||
|
#define EOF_RECLEN SIZEOF(struct_jrec_eof)
|
||
|
/* Macro to access variable size record's fixed part's size */
|
||
|
#define FIXED_ZTWORM_RECLEN OFFSETOF(struct_jrec_ztworm, ztworm_str)
|
||
|
#define FIXED_UPD_RECLEN OFFSETOF(struct_jrec_upd, mumps_node)
|
||
|
#define MIN_ALIGN_RECLEN (OFFSETOF(struct_jrec_align, align_str.text[0]) + JREC_SUFFIX_SIZE)
|
||
|
#define FIXED_ALIGN_RECLEN OFFSETOF(struct_jrec_align, align_str.text[0])
|
||
|
#define FIXED_BLK_RECLEN OFFSETOF(struct_jrec_blk, blk_contents[0])
|
||
|
#define FIXED_PBLK_RECLEN OFFSETOF(struct_jrec_blk, blk_contents[0])
|
||
|
#define FIXED_AIMG_RECLEN OFFSETOF(struct_jrec_blk, blk_contents[0])
|
||
|
#define MIN_PBLK_RECLEN (OFFSETOF(struct_jrec_blk, blk_contents[0]) + JREC_SUFFIX_SIZE)
|
||
|
#define MIN_AIMG_RECLEN (OFFSETOF(struct_jrec_blk, blk_contents[0]) + JREC_SUFFIX_SIZE)
|
||
|
|
||
|
#define JREC_PREFIX_SIZE SIZEOF(jrec_prefix)
|
||
|
#define JREC_SUFFIX_SIZE SIZEOF(jrec_suffix)
|
||
|
#define MIN_JNLREC_SIZE (JREC_PREFIX_SIZE + JREC_SUFFIX_SIZE)
|
||
|
#define JREC_PREFIX_UPTO_LEN_SIZE (offsetof(jrec_prefix, pini_addr))
|
||
|
|
||
|
typedef struct set_jnl_options_struct
|
||
|
{
|
||
|
int cli_journal, cli_enable, cli_on, cli_replic_on;
|
||
|
boolean_t alignsize_specified,
|
||
|
allocation_specified,
|
||
|
autoswitchlimit_specified,
|
||
|
image_type_specified, /* beofre/nobefore option specified */
|
||
|
buffer_size_specified,
|
||
|
epoch_interval_specified,
|
||
|
extension_specified,
|
||
|
filename_specified,
|
||
|
sync_io_specified,
|
||
|
yield_limit_specified;
|
||
|
/* since jnl_create_info does not have following fields, we need them here */
|
||
|
boolean_t sync_io;
|
||
|
int4 yield_limit;
|
||
|
} set_jnl_options;
|
||
|
|
||
|
/* rlist_state needed to be moved here to use with mu_set_reglist */
|
||
|
enum rlist_state {
|
||
|
NONALLOCATED,
|
||
|
ALLOCATED,
|
||
|
DEALLOCATED
|
||
|
};
|
||
|
|
||
|
/* mu_set_reglist needed to be moved here for the journal specific fields */
|
||
|
/* ATTN: the first four items in this structure need to be identical to those
|
||
|
* in structure tp_region in tp.h.
|
||
|
*/
|
||
|
typedef struct mu_set_reglist
|
||
|
{
|
||
|
struct mu_set_reglist *fPtr; /* all fields after this are used for mupip_set_journal.c */
|
||
|
gd_region *reg;
|
||
|
char unique_id[UNIQUE_ID_SIZE];
|
||
|
enum rlist_state state;
|
||
|
sgmnt_data_ptr_t sd;
|
||
|
bool exclusive; /* standalone access is required for this region */
|
||
|
int fd;
|
||
|
enum jnl_state_codes jnl_new_state;
|
||
|
enum repl_state_codes repl_new_state;
|
||
|
boolean_t before_images;
|
||
|
} mu_set_rlist;
|
||
|
|
||
|
/* The enum codes below correspond to code-paths that can call set_jnl_file_close() in VMS */
|
||
|
typedef enum
|
||
|
{
|
||
|
SET_JNL_FILE_CLOSE_BACKUP = 1, /* just for safety a non-zero value to start with */
|
||
|
SET_JNL_FILE_CLOSE_SETJNL,
|
||
|
SET_JNL_FILE_CLOSE_EXTEND,
|
||
|
SET_JNL_FILE_CLOSE_RUNDOWN,
|
||
|
SET_JNL_FILE_CLOSE_INVALID_OP
|
||
|
} set_jnl_file_close_opcode_t;
|
||
|
|
||
|
typedef void (*pini_addr_reset_fnptr)(sgmnt_addrs *csa);
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
token_num mur_jrec_seqno; /* This is jnl_seqno */
|
||
|
VMS_ONLY(seq_num max_resync_seqno;) /* for update process and rollback fetchresync */
|
||
|
UNIX_ONLY(seq_num max_dualsite_resync_seqno;) /* for update process and rollback fetchresync */
|
||
|
unsigned short filler_short;
|
||
|
unsigned short mur_jrec_participants;
|
||
|
jnl_tm_t gbl_jrec_time;
|
||
|
jnl_tm_t mur_tp_resolve_time; /* tp resolve time as determined by journal recovery.
|
||
|
* Time of the point upto which a region will be processed for
|
||
|
* TP token resolution for backward or forward recover.
|
||
|
* Note : This is what prevents user to change system time.
|
||
|
*/
|
||
|
boolean_t forw_phase_recovery;
|
||
|
boolean_t mur_rollback; /* a copy of mur_options.rollback to be accessible to runtime code */
|
||
|
boolean_t mupip_journal; /* the current command is a MUPIP JOURNAL command */
|
||
|
boolean_t dont_reset_gbl_jrec_time; /* Do not reset gbl_jrec_time */
|
||
|
pini_addr_reset_fnptr mur_pini_addr_reset_fnptr; /* function pointer to invoke "mur_pini_addr_reset" */
|
||
|
uint4 cumul_jnl_rec_len; /* cumulative length of the replicated journal records
|
||
|
* for the current TP or non-TP transaction */
|
||
|
boolean_t wait_for_jnl_hard;
|
||
|
uint4 tp_ztp_jnl_upd_num; /* Incremented whenever a journaled update happens inside of
|
||
|
* TP or ZTP. Copied over to the corresponding journal record
|
||
|
* to record the sequence of all updates inside TP/ZTP transaction.
|
||
|
*/
|
||
|
uint4 mur_jrec_nodeflags; /* copy of "nodeflags" from jnl record currently being played */
|
||
|
# ifdef GTM_TRIGGER
|
||
|
unsigned char *prev_ztworm_ptr; /* Non-NULL if at least one ztwormhole record was successfully
|
||
|
* formatted in this transaction. Note that ZTWORMHOLE records are
|
||
|
* formatted ONLY in case of journaled & replicated databases.
|
||
|
* 1. If replicated database is unencrypted, this points to
|
||
|
* jfb->buff + FIXED_UPD_RECLEN
|
||
|
* 2. If replicated database is encrypted, this points to
|
||
|
* jfb->alt_buff + FIXED_UPD_RECLEN
|
||
|
* If no ztwormhole record is yet formatted, then points to NULL
|
||
|
*/
|
||
|
unsigned char *save_ztworm_ptr; /* copy of prev_ztworm_ptr saved until we know for sure whether
|
||
|
* a ZTWORMHOLE journal record will be written or not.
|
||
|
*/
|
||
|
# endif
|
||
|
# ifdef DEBUG
|
||
|
boolean_t mur_fences_none; /* a copy of mur_options.fences to be accessible to runtime code */
|
||
|
uint4 cumul_index;
|
||
|
uint4 cu_jnl_index;
|
||
|
uint4 max_tp_ztp_jnl_upd_num; /* Max of all <jgbl.tp_ztp_jnl_upd_num> values processed in this
|
||
|
* potentially multi-region transaction. Used only by jnl recovery.
|
||
|
*/
|
||
|
# endif
|
||
|
} jnl_gbls_t;
|
||
|
|
||
|
|
||
|
#define JNL_SHARE_SIZE(X) (JNL_ALLOWED(X) ? \
|
||
|
(ROUND_UP(JNL_NAME_EXP_SIZE + SIZEOF(jnl_buffer), OS_PAGE_SIZE) \
|
||
|
+ ROUND_UP(((sgmnt_data_ptr_t)X)->jnl_buffer_size * DISK_BLOCK_SIZE, \
|
||
|
OS_PAGE_SIZE) + OS_PAGE_SIZE) : 0)
|
||
|
|
||
|
/* pass address of jnl_buffer to get address of expanded jnl file name */
|
||
|
#define JNL_GDID_PVT(CSA) ((CSA)->jnl->fileid)
|
||
|
|
||
|
#ifdef UNIX
|
||
|
#define JNL_GDID_PTR(CSA) ((gd_id_ptr_t)(&((CSA)->nl->jnl_file.u)))
|
||
|
#else
|
||
|
#define JNL_GDID_PTR(CSA) ((gd_id_ptr_t)(&((CSA)->nl->jnl_file.jnl_file_id)))
|
||
|
#endif
|
||
|
|
||
|
/* Note that since "cycle" (in jpc and jb below) can rollover the 4G limit back to 0, it should
|
||
|
* only be used to do "!=" checks and never to do ordered checks like "<", ">", "<=" or ">=".
|
||
|
*/
|
||
|
#define JNL_FILE_SWITCHED(JPC) ((JPC)->cycle != (JPC)->jnl_buff->cycle)
|
||
|
|
||
|
#define REG_STR "region"
|
||
|
#define FILE_STR "database file"
|
||
|
|
||
|
/* Given a journal record, get_jnl_seqno returns the jnl_seqno field
|
||
|
* Now all replication type records, EOF and EPOCH have the jnl_seqno at the same offset.
|
||
|
* Modify the macro GET_JNL_SEQNO if offset of jnl_seqno is changed for any journal records
|
||
|
*/
|
||
|
#define GET_JNL_SEQNO(j) (((jnl_record *)(j))->jrec_null.jnl_seqno)
|
||
|
#define GET_REPL_JNL_SEQNO(j) (IS_REPLICATED(((jrec_prefix *)j)->jrec_type) ? GET_JNL_SEQNO(j) : 0)
|
||
|
|
||
|
/* Given a journal record, GET_TN returns the tn field
|
||
|
*/
|
||
|
#define GET_TN(j) (((*jrec_prefix)(j))->prefix.tn)
|
||
|
|
||
|
/* In t_end(), we need to write the after-image if DSE or mupip recover/rollback is playing it.
|
||
|
* But to write it out, we should have it already built before bg_update().
|
||
|
* Hence, we pre-build the block here itself before invoking t_end().
|
||
|
*/
|
||
|
#define BUILD_AIMG_IF_JNL_ENABLED(CSD, JFB, TN) \
|
||
|
{ \
|
||
|
GBLREF cw_set_element cw_set[]; \
|
||
|
GBLREF unsigned char cw_set_depth; \
|
||
|
\
|
||
|
cw_set_element *cse; \
|
||
|
\
|
||
|
if (JNL_ENABLED(CSD)) \
|
||
|
{ \
|
||
|
assert(1 == cw_set_depth); /* Only DSE uses this macro and it updates one block at a time */ \
|
||
|
cse = (cw_set_element *)(&cw_set[0]); \
|
||
|
cse->new_buff = JFB; \
|
||
|
gvcst_blk_build(cse, (uchar_ptr_t)cse->new_buff, TN); \
|
||
|
cse->done = TRUE; \
|
||
|
} \
|
||
|
}
|
||
|
|
||
|
/* In Unix, the journal file header size is currently set to 64K so it is aligned with any possible filesystem block size
|
||
|
* known at this point. This will help us do aligned writes to the journal file header as well as the journal file contents
|
||
|
* without needing to mix both of them in the same aligned disk write. In VMS, we continue with 512-byte alignment so no change.
|
||
|
* Note that the journal_file_header structure is only 2K currently and is captured using the REAL_JNL_HDR_LEN macro while
|
||
|
* the padded 64K file header is captured using the JNL_HDR_LEN macro. Use either one as appropriate in the code. Both of them
|
||
|
* are identical in VMS where it is currently 2K.
|
||
|
*/
|
||
|
#define REAL_JNL_HDR_LEN SIZEOF(jnl_file_header)
|
||
|
#ifdef UNIX
|
||
|
# define JNL_HDR_LEN 64*1024
|
||
|
#elif defined(VMS)
|
||
|
# define JNL_HDR_LEN REAL_JNL_HDR_LEN
|
||
|
#endif
|
||
|
#define JNL_FILE_FIRST_RECORD JNL_HDR_LEN
|
||
|
|
||
|
/* Minimum possible journal file size */
|
||
|
#define MIN_JNL_FILE_SIZE (JNL_HDR_LEN + PINI_RECLEN + EPOCH_RECLEN + PFIN_RECLEN + EOF_RECLEN)
|
||
|
|
||
|
/* maximum required journal file size (in 512-byte blocks), if the current transaction was the only one in a fresh journal file */
|
||
|
#define MAX_REQD_JNL_FILE_SIZE(tot_jrec_size) DIVIDE_ROUND_UP((tot_jrec_size + MIN_JNL_FILE_SIZE), DISK_BLOCK_SIZE)
|
||
|
|
||
|
/* this macro aligns the input size to account that journal file sizes can increase only in multiples of the extension size */
|
||
|
#define ALIGNED_ROUND_UP(tmp_tot_jrec_size, jnl_alq, jnl_deq) \
|
||
|
(((tmp_tot_jrec_size) <= (jnl_alq) || !(jnl_deq)) \
|
||
|
? (jnl_alq) \
|
||
|
: ((jnl_alq) + ROUND_UP((tmp_tot_jrec_size) - (jnl_alq), (jnl_deq))))
|
||
|
|
||
|
/* this macro aligns the input size to account that journal file sizes can increase only in multiples of the extension size */
|
||
|
#define ALIGNED_ROUND_DOWN(tmp_tot_jrec_size, jnl_alq, jnl_deq) \
|
||
|
(((tmp_tot_jrec_size) <= (jnl_alq) || !(jnl_deq)) \
|
||
|
? (jnl_alq) \
|
||
|
: ((jnl_alq) + ROUND_DOWN((tmp_tot_jrec_size) - (jnl_alq), (jnl_deq))))
|
||
|
|
||
|
/* the following macro uses 8-byte quantities (gtm_uint64_t) to perform additions that might cause a 4G overflow */
|
||
|
#define DISK_BLOCKS_SUM(freeaddr, jrec_size) DIVIDE_ROUND_UP((((gtm_uint64_t)(freeaddr)) + (jrec_size)), DISK_BLOCK_SIZE)
|
||
|
|
||
|
#if defined(UNIX)
|
||
|
/* For future portability JNLBUFF_ALLOC is defined in jnl.h instead of jnlsp.h */
|
||
|
#define JPC_ALLOC(csa) \
|
||
|
{ \
|
||
|
csa->jnl = (jnl_private_control *)malloc(SIZEOF(*csa->jnl)); \
|
||
|
memset(csa->jnl, 0, SIZEOF(*csa->jnl)); \
|
||
|
}
|
||
|
#define ASSERT_JNLFILEID_NOT_NULL(csa) \
|
||
|
{ \
|
||
|
assert(0 != csa->nl->jnl_file.u.inode); \
|
||
|
assert(0 != csa->nl->jnl_file.u.device); \
|
||
|
}
|
||
|
#define NULLIFY_JNL_FILE_ID(csa) \
|
||
|
{ \
|
||
|
csa->nl->jnl_file.u.inode = 0; \
|
||
|
csa->nl->jnl_file.u.device = 0; \
|
||
|
}
|
||
|
#elif defined(VMS)
|
||
|
#define JPC_ALLOC(csa) \
|
||
|
{ \
|
||
|
vms_lock_sb *tmp_jnllsb; \
|
||
|
if (NULL == csa->jnl) \
|
||
|
{ \
|
||
|
csa->jnl = (jnl_private_control *)malloc(SIZEOF(*csa->jnl)); \
|
||
|
memset(csa->jnl, 0, SIZEOF(*csa->jnl)); \
|
||
|
csa->jnl->jnllsb = malloc(SIZEOF(vms_lock_sb)); \
|
||
|
} else \
|
||
|
{ \
|
||
|
tmp_jnllsb = csa->jnl->jnllsb; \
|
||
|
memset(csa->jnl, 0, SIZEOF(*csa->jnl)); \
|
||
|
csa->jnl->jnllsb = tmp_jnllsb; \
|
||
|
} \
|
||
|
memset(csa->jnl->jnllsb, 0, SIZEOF(vms_lock_sb)); \
|
||
|
}
|
||
|
#define ASSERT_JNLFILEID_NOT_NULL(csa) assert(0 != memcmp(csa->nl->jnl_file.jnl_file_id.fid, zero_fid, SIZEOF(zero_fid)));
|
||
|
#define NULLIFY_JNL_FILE_ID(csa) memset(&csa->nl->jnl_file.jnl_file_id, 0, SIZEOF(gds_file_id))
|
||
|
#endif
|
||
|
#define JNL_INIT(csa, reg, csd) \
|
||
|
{ \
|
||
|
csa->jnl_state = csd->jnl_state; \
|
||
|
csa->jnl_before_image = csd->jnl_before_image; \
|
||
|
csa->repl_state = csd->repl_state; \
|
||
|
if JNL_ALLOWED(csa) \
|
||
|
{ \
|
||
|
JPC_ALLOC(csa); \
|
||
|
csa->jnl->region = reg; \
|
||
|
csa->jnl->jnl_buff = (jnl_buffer_ptr_t)((sm_uc_ptr_t)(csa->nl) + NODE_LOCAL_SPACE + JNL_NAME_EXP_SIZE); \
|
||
|
csa->jnl->channel = NOJNL; \
|
||
|
} else \
|
||
|
csa->jnl = NULL; \
|
||
|
}
|
||
|
#define JNL_FD_CLOSE(CHANNEL, RC) \
|
||
|
{ \
|
||
|
fd_type lcl_channel; \
|
||
|
\
|
||
|
/* Reset incoming channel BEFORE closing it. This way, if we get interrupted BEFORE the close but \
|
||
|
* after we have reset channel, we could at most end up with a file descriptor leak. Doing it the \
|
||
|
* other way around could cause us to close the channel but yet have a dangling pointer to it that \
|
||
|
* could result in more than one close of the same file descriptor where the second close could \
|
||
|
* be on some other valid open file descriptor. \
|
||
|
*/ \
|
||
|
lcl_channel = CHANNEL; \
|
||
|
CHANNEL = NOJNL; \
|
||
|
F_CLOSE(lcl_channel, RC); /* resets "lcl_channel" to FD_INVALID */ \
|
||
|
assert(SS_NORMAL == RC); \
|
||
|
}
|
||
|
|
||
|
#define MAX_EPOCH_DELAY 30
|
||
|
#define EXT_NEW "_new"
|
||
|
#define PREFIX_ROLLED_BAK "rolled_bak_"
|
||
|
#define REC_TOKEN(jnlrec) ((struct_jrec_upd *)jnlrec)->token_seq.token
|
||
|
#define REC_JNL_SEQNO(jnlrec) ((struct_jrec_upd *)jnlrec)->token_seq.jnl_seqno
|
||
|
#define REC_LEN_FROM_SUFFIX(ptr, reclen) ((jrec_suffix *)((unsigned char *)ptr + reclen - JREC_SUFFIX_SIZE))->backptr
|
||
|
|
||
|
#define JNL_MAX_SET_KILL_RECLEN(CSD) (uint4)ROUND_UP2(FIXED_UPD_RECLEN + JREC_SUFFIX_SIZE \
|
||
|
+ ((CSD)->blk_size - SIZEOF(blk_hdr) - SIZEOF(rec_hdr)) \
|
||
|
+ SIZEOF(jnl_str_len_t) + SIZEOF(mstr_len_t), JNL_REC_START_BNDRY) \
|
||
|
/* fixed size part of update record + MAX possible (key + data) len + keylen-len + datalen-len */
|
||
|
|
||
|
#define JNL_MAX_PBLK_RECLEN(CSD) (uint4)ROUND_UP2(MIN_PBLK_RECLEN + (CSD)->blk_size, JNL_REC_START_BNDRY)
|
||
|
|
||
|
/* Macro to compute the maximum possible journal record length in the journal file.
|
||
|
* In order to compute the maximum jnl record length, note that an align record is written whenever
|
||
|
* a <non-align-record + an-align-record> would cause the jnl file offset to move past an aligned boundary.
|
||
|
* Therefore after computing the maximum possible non-align-jnl-record-length, we need to add MIN_ALIGN_RECLEN
|
||
|
* as this is the maximum possible align-jnl-record-length and should be the eventual max_jrec_len.
|
||
|
*/
|
||
|
#define JNL_MAX_RECLEN(JINFO, CSD) \
|
||
|
{ \
|
||
|
int4 max_logi_reclen, max_pblk_reclen; \
|
||
|
\
|
||
|
/* A logical record is a SET/KILL record. The SET could be as big as (CSD)->max_rec_size, but since \
|
||
|
* csd->max_rec_size can be changed independent of journal file creation (through DSE), we consider \
|
||
|
* the max possible record size that can fit in a GDS block. After that we consider $ZTWORMHOLE too. \
|
||
|
*/ \
|
||
|
max_logi_reclen = JNL_MAX_SET_KILL_RECLEN(CSD); \
|
||
|
GTMTRIG_ONLY(max_logi_reclen = MAX(max_logi_reclen, MAX_ZTWORM_JREC_LEN);) \
|
||
|
max_pblk_reclen = JNL_MAX_PBLK_RECLEN(CSD); \
|
||
|
(JINFO)->max_jrec_len = MAX(max_logi_reclen, max_pblk_reclen) + MIN_ALIGN_RECLEN; \
|
||
|
}
|
||
|
|
||
|
/* Macro that checks that the region seqno in the filehdr is never more than the seqno in the journal pool */
|
||
|
#define ASSERT_JNL_SEQNO_FILEHDR_JNLPOOL(csd, jnlpool_ctl) \
|
||
|
{ /* The seqno in the file header should be at most 1 greater than that in the journal pool. \
|
||
|
* See step (5) of of commit logic flow in secshr_db_clnup.c for why. Assert that. \
|
||
|
*/ \
|
||
|
assert((NULL == jnlpool_ctl) || (csd->reg_seqno <= (jnlpool_ctl->jnl_seqno + 1))); \
|
||
|
}
|
||
|
#ifdef GTM_CRYPT
|
||
|
#define DECODE_SET_KILL_ZKILL_ZTRIG(mumps_node_ptr, rec_size, key_handle, RC) \
|
||
|
{ \
|
||
|
int span_length, fixed_prefix; \
|
||
|
\
|
||
|
RC = 0; \
|
||
|
assert(FIXED_UPD_RECLEN == FIXED_ZTWORM_RECLEN); \
|
||
|
fixed_prefix = FIXED_UPD_RECLEN; \
|
||
|
ASSERT_ENCRYPTION_INITIALIZED; \
|
||
|
span_length = rec_size - fixed_prefix - JREC_SUFFIX_SIZE; \
|
||
|
GTMCRYPT_DECODE_FAST(key_handle, (char *)mumps_node_ptr, span_length, NULL, RC); \
|
||
|
}
|
||
|
|
||
|
#endif /* GTM_CRYPT */
|
||
|
/* jnl_ prototypes */
|
||
|
uint4 jnl_file_extend(jnl_private_control *jpc, uint4 total_jnl_rec_size);
|
||
|
uint4 jnl_file_lost(jnl_private_control *jpc, uint4 jnl_stat);
|
||
|
uint4 jnl_qio_start(jnl_private_control *jpc);
|
||
|
uint4 jnl_write_attempt(jnl_private_control *jpc, uint4 threshold);
|
||
|
void jnl_prc_vector(jnl_process_vector *pv);
|
||
|
void jnl_send_oper(jnl_private_control *jpc, uint4 status);
|
||
|
uint4 cre_jnl_file(jnl_create_info *info);
|
||
|
uint4 cre_jnl_file_common(jnl_create_info *info, char *rename_fn, int rename_fn_len);
|
||
|
void jfh_from_jnl_info (jnl_create_info *info, jnl_file_header *header);
|
||
|
uint4 jnl_ensure_open(void);
|
||
|
void set_jnl_info(gd_region *reg, jnl_create_info *set_jnl_info);
|
||
|
void jnl_write_epoch_rec(sgmnt_addrs *csa);
|
||
|
void jnl_write_inctn_rec(sgmnt_addrs *csa);
|
||
|
void jnl_write_logical(sgmnt_addrs *csa, jnl_format_buffer *jfb);
|
||
|
void jnl_write_ztp_logical(sgmnt_addrs *csa, jnl_format_buffer *jfb);
|
||
|
void jnl_write_eof_rec(sgmnt_addrs *csa, struct_jrec_eof *eof_record);
|
||
|
void jnl_write_poolonly(jnl_private_control *jpc, enum jnl_record_type rectype, jnl_record *jnl_rec, jnl_format_buffer *jfb);
|
||
|
|
||
|
jnl_format_buffer *jnl_format(jnl_action_code opcode, gv_key *key, mval *val, uint4 nodeflags);
|
||
|
|
||
|
#ifdef VMS
|
||
|
void finish_active_jnl_qio(void);
|
||
|
void jnl_start_ast(jnl_private_control *jpc);
|
||
|
uint4 jnl_permit_ast(jnl_private_control *jpc);
|
||
|
void jnl_qio_end(jnl_private_control *jpc);
|
||
|
#endif
|
||
|
|
||
|
void wcs_defer_wipchk_ast(jnl_private_control *jpc);
|
||
|
uint4 set_jnl_file_close(set_jnl_file_close_opcode_t set_jnl_file_close_opcode);
|
||
|
uint4 jnl_file_open_common(gd_region *reg, off_jnl_t os_file_size);
|
||
|
uint4 jnl_file_open_switch(gd_region *reg, uint4 sts);
|
||
|
void jnl_file_close(gd_region *reg, bool clean, bool dummy);
|
||
|
|
||
|
/* Consider putting followings in a mupip only header file : Layek 2/18/2003 */
|
||
|
boolean_t mupip_set_journal_parse(set_jnl_options *jnl_options, jnl_create_info *jnl_info);
|
||
|
uint4 mupip_set_journal_newstate(set_jnl_options *jnl_options, jnl_create_info *jnl_info, mu_set_rlist *rptr);
|
||
|
void mupip_set_journal_fname(jnl_create_info *jnl_info);
|
||
|
uint4 mupip_set_jnlfile_aux(jnl_file_header *header, char *jnl_fname);
|
||
|
void jnl_setver(void);
|
||
|
void jnl_extr_init(void);
|
||
|
int exttime(uint4 time, char *buffer, int extract_len);
|
||
|
char *ext2jnlcvt(char *ext_buff, int4 ext_len, jnl_record *rec);
|
||
|
char *ext2jnl(char *ptr, jnl_record *rec);
|
||
|
char *jnl2extcvt(jnl_record *rec, int4 jnl_len, char *ext_buff);
|
||
|
char *jnl2ext(char *jnl_buff, char *ext_buff);
|
||
|
|
||
|
#endif /* JNL_H_INCLUDED */
|