/****************************************************************
 *								*
 * Copyright (c) 2001-2017 Fidelity National Information	*
 * Services, Inc. and/or its subsidiaries. All rights reserved.	*
 *								*
 *	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.	*
 *								*
 ****************************************************************/

#ifndef REPL_INSTANCE_INCLUDED
#define REPL_INSTANCE_INCLUDED

/* MAJOR format of the instance file; Any change to this means recreating instance file.
 * This needs to be changed whenever the layout of the instance file (file header and/or contents) changes in a major way.
 */
#define GDS_REPL_INST_LABEL 		"GDSRPLUNX05"
#define GDS_REPL_INST_LABEL_SZ		12

/* The current MINOR version. Changes to this would mean an on-the-fly upgrade of the instance file.
 * This needs to be changed whenever the changes to the file header layout of the instance file are small enough
 * that it is possible to do an online upgrade of the file header.
 */
#define GDS_REPL_INST_MINOR_LABEL 	1	/* can go upto 255 at which point the major version has to change */

#define	IN_REPL_INST_EDIT_FALSE		FALSE	/* to indicate we are not in a MUPIP REPLIC -EDITINSTANCE */
#define	IN_REPL_INST_EDIT_TRUE		TRUE	/* to indicate we are MUPIP REPLIC -EDITINSTANCE */
#define	IN_REPL_INST_EDIT_CHANGE_OFFSET	2	/* to indicate we are in MUPIP REPLIC -EDITINSTANCE -CHANGE */

/* Replication Instance file format
 *
 *	[size =  512 bytes] File-Header structure "repl_inst_hdr" (size 512 bytes)
 *	[size = 1024 bytes] Array of 16 "gtmsrc_lcl" structures (each size 64 bytes)
 *	[size = 64*n bytes] Variable-length Array of structure "repl_histinfo" (each size 64 bytes)
 *		Each "repl_histinfo" defines the beginning of a range of seqnos (identified by the "start_seqno" field)
 *		that was received from a particular invocation of a root primary instance. The range ends with the
 *		"start_seqno" field of the next histinfo record.
 * Note: "repl_histinfo" structure is defined in mdef.h (not in this file).
 *
 * An uptodate copy of the fixed length section of the instance file (file header and array of gtmsrc_lcl structures)
 * is maintained in the journal pool. The file on disk is not as uptodate but periodically flushed.
 */

#define DEF_INST_FN "mumps.repl"

typedef struct repl_inst_hdr_struct
{
	unsigned char	label[GDS_REPL_INST_LABEL_SZ];	/* format of instance file. initialized to GDS_REPL_INST_LABEL */
	unsigned char	replinst_minorver;		/* minor version of the GT.M release that last touched this file */
	unsigned char	is_little_endian;		/* TRUE if little-endian, FALSE if big-endian */
	unsigned char	is_64bit;			/* TRUE if created by 64-bit GT.M, FALSE if created by 32-bit GT.M */
	unsigned char	filler_16[1];
	int4		jnlpool_semid;			/* id of IPC_PRIVATE semaphore created for jnlpool */
	int4		jnlpool_shmid;			/* id of IPC_PRIVATE shared memory created for jnlpool */
	int4		recvpool_semid;			/* id of IPC_PRIVATE semaphore created for recvpool */
	int4		recvpool_shmid;			/* id of IPC_PRIVATE semaphore created for recvpool */
	/* All time fields have a NON_GTM64_ONLY filler so all fields in the file header start
	 * at the same offset irrespective of whether time_t is 4-bytes or 8-bytes.
	 */
	time_t		jnlpool_semid_ctime;		/* creation time of IPC_PRIVATE semaphore for jnlpool */
	NON_GTM64_ONLY(int4	filler8bytealign_1;)
	time_t		jnlpool_shmid_ctime;		/* creation time of IPC_PRIVATE shared memory for jnlpool */
	NON_GTM64_ONLY(int4	filler8bytealign_2;)
	time_t		recvpool_semid_ctime;		/* creation time of IPC_PRIVATE semaphore for recvpool */
	NON_GTM64_ONLY(int4	filler8bytealign_3;)
	time_t		recvpool_shmid_ctime;		/* creation time of IPC_PRIVATE shared memory for recvpool */
	NON_GTM64_ONLY(int4	filler8bytealign_4;)
	repl_inst_uuid	inst_info;		/* Initialized at instance file creation time */
	repl_inst_uuid	lms_group_info;		/* Set to NULL at instance file creation time;
						 * Set to a non-NULL value ONLY IF current value is NULL and
						 *	a) the instance is brought up as a rootprimary.
						 *		In this case, the value is inherited from the "inst_info" field
						 *		of the current instance file
						 *	OR
						 *	b) the instance is brought up as a propagating primary.
						 *		In this case, the value is inherited from the "lms_group_info"
						 *		field of the instance file from the root primary instance
						 *		that this instance connects to directly or indirectly (through
						 *		a sequence of propagating primary instances in between).
						 */
	seq_num		jnl_seqno;		/* Holds the current seqno of the instance when the journal pool was last shutdown.
						 * Compared with db reg_seqno at open time to check if both are in sync.
						 */
	uint4		root_primary_cycle;	/* Incremented every time this instance is brought up as root primary */
	int4		num_histinfo;		/* Number of histinfo records currently USED in this file. Usually incremented as
						 * new histinfo records get added to the file. Usually maintained in tandem with
						 * "num_alloc_histinfo". When MUPIP ROLLBACK virtually truncates the histinfo
						 * history it only updates this field to reflect the decrement.
						 */
	int4		num_alloc_histinfo;	/* Actual number of histinfo record slots ALLOCATED in this file. Incremented
						 * whenever a new histinfo record is allocated at the end of the instance file.
						 * Not incremented if a new histinfo record reuses virtually truncated space
						 * (possible by MUPIP ROLLBACK). This field is never decremented.
						 */
	boolean_t	crash;			/* This is set to TRUE if the journal pool exists and set to FALSE whenever
						 * it is cleanly shutdown. Used to identify abnormal shutdowns and require rollback.
						 */
	boolean_t	was_rootprimary;	/* Set to TRUE when this instance starts up as a root primary. Set to FALSE when
						 * this instance is brought up as a propagating primary and the receiver server
						 * connects to the new primary source server successfully.
						 */
	boolean_t	is_supplementary;	/* Whether this instance is a supplementary instance or not */
	int4		last_histinfo_num[MAX_SUPPL_STRMS];	/* Maintained whether "is_supplementary" is TRUE or FALSE.
								 * the slot number corresponding to the most recent history record
							 	 * written for each stream */
	seq_num		strm_seqno[MAX_SUPPL_STRMS];		/* Maintained only if "is_supplementary" is TRUE.
								 * The current jnl seqno of each stream when the jnl pool was last
								 * shutdown. Used to initialize similarly-named field in the
								 * jnlpool_ctl structure at jnlpool_init time. Not as frequently
								 * updated/maintained as the jnlpool_ctl->strm_seqno[] field */
	repl_inst_uuid	strm_group_info[MAX_SUPPL_STRMS - 1];	/* Maintained only if "is_supplementary" is TRUE.
								 * The "lms_group_info" field of the non-supplementary source
								 * that connects to this supplementary root primary instance.
								 * Initialized by a -UPDATERESYNC= receiver server startup on a
								 * supplementary root primary instance. Used by the receiver server
								 * on the supplementary instance when it connects to a source
								 * server from the non-supplementary instance. Note: We dont need
								 * this for the 0th stream as its group info is the "lms_group_info"
								 * member of the instance file header. Hence the MAX_SUPPL_STRMS-1.
								 */
	boolean_t	file_corrupt;		/* Set to TRUE by online rollback at start up. Set to FALSE when online rollback
						 * completes successfully.
						 */
	boolean_t	filler_ftok_counter_halted;/* Used only in V6.3-000. Kept as a filler to be safe */
	boolean_t	qdbrundown;		/* TRUE if -QDBRUNDOWN was specified at time of instance file creation.
						 * FALSE otherwise.
						 */
	unsigned char   filler_1024[44];
} repl_inst_hdr;

/* Any changes to the following structure might have to be reflected in "gtmsource_local_struct" structure in gtmsource.h as well.
 * All fields here have a corresponding parallel field in the latter structure.
 */
typedef struct gtmsrc_lcl_struct
{
	unsigned char	secondary_instname[MAX_INSTNAME_LEN];	/* Secondary instance corresponding to this structure */
	seq_num		resync_seqno;				/* Next seqno to be sent from this primary instance.
								 * Maintained in parallel with "read_jnl_seqno" in the corresponding
								 * gtmsource_local structure in the journal pool.
								 */
	seq_num		connect_jnl_seqno;			/* jnl_seqno of the instance when last connection with secondary
								 * was made. Used to determine least recently used slot for reuse */
	unsigned char	filler_64[32];				/* For future expansion */
} gtmsrc_lcl;

#define	COPY_GTMSOURCELOCAL_TO_GTMSRCLCL(sourcelocal, srclcl)							\
{														\
	memcpy(&(srclcl)->secondary_instname[0], &(sourcelocal)->secondary_instname[0], MAX_INSTNAME_LEN - 1);	\
	(srclcl)->resync_seqno = (sourcelocal)->read_jnl_seqno;							\
	(srclcl)->connect_jnl_seqno = (sourcelocal)->connect_jnl_seqno;						\
}

#define	COPY_GTMSRCLCL_TO_GTMSOURCELOCAL(srclcl, sourcelocal)							\
{														\
	memcpy(&(sourcelocal)->secondary_instname[0], &(srclcl)->secondary_instname[0], MAX_INSTNAME_LEN - 1);	\
	(sourcelocal)->read_jnl_seqno = (srclcl)->resync_seqno;							\
	(sourcelocal)->connect_jnl_seqno = (srclcl)->connect_jnl_seqno;						\
}

#define	COPY_JCTL_STRMSEQNO_TO_INSTHDR_IF_NEEDED								\
{														\
	int				idx;									\
	GBLREF	jnlpool_addrs_ptr_t	jnlpool;	/* used by the below macro */				\
														\
	/* Keep the file header copy of "strm_seqno" uptodate with jnlpool_ctl */				\
	if (jnlpool->repl_inst_filehdr->is_supplementary)							\
	{													\
		for (idx = 0; idx < MAX_SUPPL_STRMS; idx++)							\
			jnlpool->repl_inst_filehdr->strm_seqno[idx] = jnlpool->jnlpool_ctl->strm_seqno[idx];	\
	}													\
}

/* The below assert ensures that on a supplementary instance, an update to any stream only occurs if there is a history record
 * corresponding to that stream in the instance file. If this is not the case, those history-less updates will have no way of
 * being replicated (propagated downstream) from this instance as there is no history record to identify the update originator.
 */
#define	ASSERT_INST_FILE_HDR_HAS_HISTREC_FOR_STRM(STRM_IDX, JNLPOOL)					\
{													\
	assert(INVALID_HISTINFO_NUM != JNLPOOL->repl_inst_filehdr->last_histinfo_num[STRM_IDX]);	\
}

#define	OK_TO_LOG_FALSE		FALSE
#define	OK_TO_LOG_TRUE		TRUE

#define INST_NOT_GLD			(struct gd_addr_struct *)1
#define IS_INST_FROM_GLD(REPL_GLD)	(INST_NOT_GLD != REPL_GLD)	/* where repl_inst_get_name found instance file name */

#define GET_INSTFILE_NAME(sendmsg, err_act)										\
{															\
	if (((SS_NORMAL == (status = TRANS_LOG_NAME(&log_nam, &trans_name, temp_inst_fn,				\
					SIZEOF(temp_inst_fn), sendmsg))) || (inst_from_gld && (SS_NOLOGNAM == status)))	\
		&& (0 != trans_name.len))										\
	{														\
		temp_inst_fn[trans_name.len] = '\0';									\
		if (!get_full_path(trans_name.addr, trans_name.len, fn, fn_len, bufsize, &ustatus) && err_act)		\
		{													\
			gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_REPLINSTACC, 2, trans_name.len, trans_name.addr,	\
				ERR_TEXT, 2, RTS_ERROR_LITERAL("full path could not be found"), ustatus);		\
		} else													\
			ret = TRUE;											\
	}														\
}

#define SETUP_INST_INFO(GDPTR, LOGNAM, INSTFROMGLD)			\
{									\
	if (IS_MUMPS_IMAGE && GDPTR && GDPTR->instinfo)			\
	{	/* use global directory information */			\
		LOGNAM.addr = GDPTR->instinfo->instfilename;		\
		LOGNAM.len = STRLEN(GDPTR->instinfo->instfilename);	\
		INSTFROMGLD = TRUE;					\
	} else								\
	{								\
		LOGNAM.addr = GTM_REPL_INSTANCE;			\
		LOGNAM.len = SIZEOF(GTM_REPL_INSTANCE) - 1;		\
		INSTFROMGLD = FALSE;					\
	}								\
}

typedef enum {
	return_on_error,
	issue_rts_error,
	issue_gtm_putmsg
} instname_act;

/* return and gd_ptr are really gd_addr * but gdsfhead.h would be needed */
struct gd_addr_struct	*repl_inst_get_name(char *, unsigned int *, unsigned int, instname_act error_action,
						struct gd_addr_struct *gd_ptr);
void		repl_inst_create(void);
void		repl_inst_edit(void);
void		repl_inst_read(char *fn, off_t offset, sm_uc_ptr_t buff, size_t buflen);
void		repl_inst_write(char *fn, off_t offset, sm_uc_ptr_t buff, size_t buflen);
void		repl_inst_sync(char *fn);
void		repl_inst_jnlpool_reset(void);
void		repl_inst_recvpool_reset(void);
void		repl_inst_ftok_sem_lock(void);
void		repl_inst_ftok_sem_release(void);
int4		repl_inst_histinfo_get(int4 index, repl_histinfo *histinfo);
int4		repl_inst_histinfo_find_seqno(seq_num seqno, int4 strm_idx, repl_histinfo *histinfo);
int4		repl_inst_wrapper_histinfo_find_seqno(seq_num seqno, int4 strm_idx, repl_histinfo *local_histinfo);
void		repl_inst_histinfo_add(repl_histinfo *histinfo);
seq_num		repl_inst_histinfo_truncate(seq_num rollback_seqno);
void		repl_inst_flush_filehdr(void);
void		repl_inst_flush_gtmsrc_lcl(void);
void		repl_inst_flush_jnlpool(boolean_t reset_recvpool_fields, boolean_t reset_crash);
boolean_t	repl_inst_was_rootprimary(void);
int4		repl_inst_reset_zqgblmod_seqno_and_tn(void);

boolean_t	gtmsource_get_cmp_info(int4 *repl_zlib_cmp_level_ptr);
void            repl_cmp_solve_src_timeout(void);
void            repl_cmp_solve_rcv_timeout(void);
boolean_t	gtmsource_get_instance_info(boolean_t *secondary_was_rootprimary, seq_num *strm_jnl_seqno);
boolean_t	gtmsource_get_remote_histinfo(seq_num seqno, repl_histinfo *histinfo);
boolean_t	gtmsource_check_remote_strm_histinfo(seq_num seqno, boolean_t *rollback_first);
void		gtmsource_histinfo_get(int4 index, repl_histinfo *histinfo);
boolean_t	gtmsource_is_histinfo_identical(repl_histinfo *remote_histinfo, repl_histinfo *local_histinfo,
										seq_num jnl_seqno, boolean_t ok_to_log);
seq_num		gtmsource_find_resync_seqno(repl_histinfo *local_histinfo, repl_histinfo *remote_histinfo);
void		gtmsource_set_next_histinfo_seqno(boolean_t detect_new_histinfo);

#endif /* REPL_INSTANCE_INCLUDED */
