/****************************************************************
 *								*
 *	Copyright 2006, 2012 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.	*
 *								*
 ****************************************************************/

#ifndef _REPL_MSG_H
#define _REPL_MSG_H

enum
{
	REPL_INVALID = -1,		/* -1 */
	REPL_START_JNL_SEQNO = 0,	/* 0 */
	REPL_TR_JNL_RECS,		/* 1 */
	REPL_ROLLBACK_FIRST,		/* 2 */
	REPL_OBSOLETE_WILL_RESTART,	/* 3 */ /* Obsoleted effective V4.4-002 since we no longer support dual site config with
						 * V4.1 versions. But slot# preserved to not perturb other message #s */
	REPL_XOFF,			/* 4 */
	REPL_XON,			/* 5 */
	REPL_BADTRANS,			/* 6 */
	REPL_HEARTBEAT,			/* 7 */
	REPL_FETCH_RESYNC,		/* 8 */
	REPL_RESYNC_SEQNO,		/* 9 */
	REPL_OBSOLETE_STOPSRCFILTER,	/* 10 */ /* message no longer used but slot# 10 preserved to not perturb other message #s */
	REPL_XOFF_ACK_ME,		/* 11 */
	REPL_XOFF_ACK,			/* 12 */
	REPL_WILL_RESTART_WITH_INFO,	/* 13 */
	REPL_MULTISITE_MSG_START,	/* 14 */ /* All messages after this are newly introduced for multi-site support only */
	REPL_OLD_NEED_INSTANCE_INFO,	/* 15 */
	REPL_OLD_INSTANCE_INFO,		/* 16 */
	REPL_NEED_HISTINFO,		/* 17 */
	REPL_OLD_TRIPLEINFO1,		/* 18 */
	REPL_OLD_TRIPLEINFO2,		/* 19 */
	REPL_OLD_TRIPLE,		/* 20 */
	REPL_INST_NOHIST,		/* 21 */
	REPL_LOSTTNCOMPLETE,		/* 22 */
	REPL_CMP_TEST,			/* 23 */
	REPL_CMP_SOLVE,			/* 24 */
	REPL_CMP2UNCMP,			/* 25 */  /* used to signal a transition to uncompressed messages in case of errors */
	REPL_TR_CMP_JNL_RECS,		/* 26 */  /* used to send compressed messages whose pre-compressed length is <  2**24 */
	REPL_TR_CMP_JNL_RECS2,		/* 27 */  /* used to send compressed messages whose pre-compressed length is >= 2**24 */
	REPL_NEED_INSTINFO,		/* 28 */
	REPL_INSTINFO,			/* 29 */
	REPL_HISTINFO,			/* 30 */  /* used to exchange history information as part of a replication handshake */
	REPL_HISTREC,			/* 31 */  /* sent in the middle of a journal record stream to signal start of new history */
	REPL_NEED_STRMINFO,		/* 32 */  /* sent by a supplementary source server to a supplementary receiver server */
	REPL_STRMINFO,			/* 33 */  /* sent in response to a REPL_NEED_STRMINFO message */
	REPL_MSGTYPE_LAST=256		/* 256 */
	/* any new message need to be added before REPL_MSGTYPE_LAST */
};

#define	REPL_PROTO_VER_UNINITIALIZED	(char)0xFF	/* -1, the least of the versions to denote an uninitialized version field */
#define	REPL_PROTO_VER_DUALSITE		(char)0x0	/* Versions GT.M V5.0 and prior that dont support multi site replication */
#define	REPL_PROTO_VER_MULTISITE	(char)0x1	/* Versions V5.1-000 and above that support multi site replication */
#define	REPL_PROTO_VER_MULTISITE_CMP	(char)0x2	/* Versions V5.3-003 and above that suport multisite replication with
							 * the ability to compress the logical records in the replication pipe.
							 */
#define	REPL_PROTO_VER_SUPPLEMENTARY	(char)0x3	/* Versions V5.5-000 and above that suport supplementary instances */
#define	REPL_PROTO_VER_THIS		REPL_PROTO_VER_SUPPLEMENTARY
							/* The current/latest version of the communication protocol between the
							 * primary (source server) and secondary (receiver server or rollback)
							 */

/* A few of these flag bits (e.g. START_FLAG_SRCSRV_IS_VMS) are no longer used but they should not be removed just in case prior
 * versions that used those bitslots communicate with a newer version that assigns a different meaning to those slots. Any new
 * slot additions need to happen at the end of the list. No replacements of unused slots.
 */
#define	START_FLAG_NONE				0x00000000
#define	START_FLAG_STOPSRCFILTER		0x00000001
#define	START_FLAG_UPDATERESYNC			0x00000002
#define	START_FLAG_HASINFO			0x00000004
#define	START_FLAG_COLL_M			0x00000008
#define	START_FLAG_VERSION_INFO			0x00000010
#define	START_FLAG_TRIGGER_SUPPORT		0x00000020
#define	START_FLAG_SRCSRV_IS_VMS		0x00000040	/* Obsolete but preserve slot */
#define	START_FLAG_NORESYNC			0x00000080

#define	MIN_REPL_MSGLEN		32 /* To keep compiler happy with
				    * the definition of repl_msg_t as well
				    * as to accommodate a seq_num */

#define	REPL_MSG_CMPINFOLEN	(SIZEOF(repl_cmpinfo_msg_t))
#define	REPL_MSG_CMPDATALEN	256	/* length of data part of message exchanged between source/receiver to test compression */
#define	REPL_MSG_CMPDATAMASK	0xff
#define	MAX_CMP_EXPAND_FACTOR	2	/* the worst case factor by which compression could actually expand input data */
#define	REPL_MSG_CMPEXPDATALEN	(MAX_CMP_EXPAND_FACTOR * REPL_MSG_CMPDATALEN)

/* The "datalen" field of the REPL_CMP_SOLVE message is set to the following value by the receiver server in case of errors. */
#define	REPL_RCVR_CMP_TEST_FAIL		(-1)

#define	REPL_MSG_ALIGN	8	/* every message sent across the pipe is expected to be at least 8-byte aligned */

#define	REPL_MSG_TYPE	(uint4)(SIZEOF(int4))
#define	REPL_MSG_LEN	(uint4)(SIZEOF(int4))
#define	REPL_MSG_HDRLEN	(uint4)(REPL_MSG_TYPE + REPL_MSG_LEN) /* For type and len fields */

typedef struct	/* Used also to send a message of type REPL_INST_NOHIST */
{
	int4		type;
	int4		len;	/* Is 8-byte aligned for ALL messages except REPL_TR_CMP_JNL_RECS message */
	unsigned char	msg[MIN_REPL_MSGLEN - REPL_MSG_HDRLEN];
	/* All that we need is msg[1], but keep the  compiler happy with
	 * this definition for msg. Also provide space to accommodate a seq_num
	 * so that a static definition would suffice instead of malloc'ing a
	 * small message buffer */
} repl_msg_t;

/* To send a REPL_TR_CMP_JNL_RECS type of message, we include the pre-compressed length as part of the 4-byte type field
 * to keep the replication message header overhead to the current 8-bytes. Define macros to access those fields.
 * If the pre-compressed length cannot fit in 24 bits, then we send a REPL_TR_CMP_JNL_RECS2 message which has 8-more
 * byte overhead as part of the replication message header. It is considered ok to take this extra 8-byte hit for huge messages.
 * The threshold is defined as 2**23 (instead of 2**24) so we ensure the most significant bit is 0 and does not give us
 * problems while doing >> operations (e.g. (((repl_msg_ptr_t)buffp)->type >> REPL_TR_CMP_MSG_TYPE_BITS);
 */
#define	REPL_TR_CMP_MSG_TYPE_BITS	8
#define	REPL_TR_CMP_MSG_UNCMPLEN_BITS	24
#define	REPL_TR_CMP_THRESHOLD		(1 << (REPL_TR_CMP_MSG_UNCMPLEN_BITS - 1))
#define	REPL_TR_CMP_MSG_TYPE_MASK	((1 << REPL_TR_CMP_MSG_TYPE_BITS) - 1)

/* Defines for sending REPL_TR_CMP_JNL_RECS2 message */
#define	REPL_MSG_UNCMPLEN	SIZEOF(int4)
#define	REPL_MSG_CMPLEN		SIZEOF(int4)
#define	REPL_MSG_HDRLEN2	(REPL_MSG_HDRLEN + REPL_MSG_UNCMPLEN + REPL_MSG_CMPLEN)	/* 16-byte header */
typedef struct	/* Used also to send a message of type REPL_TR_CMP_JNL_RECS2 */
{
	int4		type;
	int4		len;
	int4		uncmplen;
	int4		cmplen;
	unsigned char	msg[MIN_REPL_MSGLEN - REPL_MSG_HDRLEN2];
	/* All that we need is msg[1], but keep the  compiler happy with
	 * this definition for msg. Also provide space to accommodate a seq_num
	 * so that a static definition would suffice instead of malloc'ing a
	 * small message buffer */
} repl_cmpmsg_t;

/* This should ideally match the TCP send/recv buffer size of source/receiver server. However, since the maximum TCP buffer
 * varies by system, and on many systems it is less than 2 MB or even 1 MB, we keep GTMRECV_TCP_RECV_BUFSIZE and
 * GTMSOURCE_TCP_SEND_BUFSIZE at 1 MB to avoid extra attempts to send/receive TCP packets before the limit is lowered enough
 * for the OS to support it.
 */
#define	MAX_REPL_MSGLEN	(2 * 1024 * 1024)
#define MAX_TR_BUFFSIZE	(MAX_REPL_MSGLEN - REPL_MSG_HDRLEN2) /* allow for biggest replication message header */

typedef struct	/* used to send a message of type REPL_START_JNL_SEQNO */
{
	int4		type;
	int4		len;
	unsigned char	start_seqno[SIZEOF(seq_num)];
	uint4		start_flags;
	unsigned char	jnl_ver;
	char		proto_ver;	/* Needs to be "signed char" in order to be able to do signed comparisons of this with
					 * the macros REPL_PROTO_VER_DUALSITE (0) and REPL_PROTO_VER_UNINITIALIZED (-1) */
	char		node_endianness;	/* 'L' if this machine is little endian, 'B' if it is big endian */
	char		is_supplementary;	/* TRUE for a supplementary instance; FALSE otherwise */
	char		filler_32[8];
} repl_start_msg_t; /* The first two fields should be as in repl_msg_t */

typedef struct	/* used to send a message of type REPL_WILL_RESTART_WITH_INFO or REPL_ROLLBACK_FIRST or REPL_RESYNC_SEQNO */
{
	int4		type;
	int4		len;
	unsigned char	start_seqno[SIZEOF(seq_num)];
	unsigned char	jnl_ver;
	char		start_flags[4];
	char		proto_ver;	/* Needs to be "signed char" in order to be able to do signed comparisons of this with
					 * the macros REPL_PROTO_VER_DUALSITE (0) and REPL_PROTO_VER_UNINITIALIZED (-1) */
	char		node_endianness;	/* 'L' if this machine is little endian, 'B' if it is big endian */
	char		is_supplementary;	/* TRUE for a supplementary instance; FALSE otherwise */
	char		filler_32[8];
} repl_start_reply_msg_t; /* The first two fields should be as in repl_msg_t */

typedef struct	/* used to send a message of type REPL_FETCH_RESYNC */
{
	int4		type;
	int4		len;
	seq_num		resync_seqno;
	char		proto_ver;	/* Needs to be "signed char" in order to be able to do signed comparisons of this with
					 * the macros REPL_PROTO_VER_DUALSITE (0) and REPL_PROTO_VER_UNINITIALIZED (-1) */
	char		node_endianness;	/* 'L' if this machine is little endian, 'B' if it is big endian */
	char		is_supplementary;	/* TRUE for a supplementary instance; FALSE otherwise */
	char		filler_32[13];
} repl_resync_msg_t; /* The first two fields should be as in repl_msg_t */

typedef struct	/* used to send a message of type REPL_OLD_NEED_INSTANCE_INFO */
{
	int4		type;
	int4		len;
	unsigned char	instname[MAX_INSTNAME_LEN];
	char		proto_ver;	/* Needs to be "signed char" in order to be able to do signed comparisons of this with
					 * the macros REPL_PROTO_VER_DUALSITE (0) and REPL_PROTO_VER_UNINITIALIZED (-1) */
	char		node_endianness;	/* 'L' if this machine is little endian, 'B' if it is big endian */
	char		is_rootprimary;	/* Whether the source server that is sending this message is a root primary or not. */
	char		filler_32[5];
} repl_old_needinst_msg_t; /* The first two fields should be as in repl_msg_t */

typedef struct	/* used to send a message of type REPL_NEED_INSTINFO */
{
	int4		type;
	int4		len;
	unsigned char	instname[MAX_INSTNAME_LEN];
	repl_inst_uuid	lms_group_info;
	char		proto_ver;	/* Needs to be "signed char" in order to be able to do signed comparisons of this with
					 * the macros REPL_PROTO_VER_DUALSITE (0) and REPL_PROTO_VER_UNINITIALIZED (-1) */
	char		is_rootprimary;	/* Whether the source server that is sending this message is a root primary or not. */
	char		is_supplementary;	/* TRUE for a supplementary instance; FALSE otherwise */
	char		filler_32[5];
} repl_needinst_msg_t; /* The first two fields should be as in repl_msg_t */

typedef struct	/* used to send a message of type REPL_OLD_INSTANCE_INFO */
{
	int4		type;
	int4		len;
	unsigned char	instname[MAX_INSTNAME_LEN];	/* The name of this replication instance */
	unsigned char	was_rootprimary;
	char		filler_32[7];
} repl_old_instinfo_msg_t; /* The first two fields should be as in repl_msg_t */

typedef struct	/* used to send a message of type REPL_INSTINFO */
{
	int4		type;
	int4		len;
	unsigned char	instname[MAX_INSTNAME_LEN];	/* The name of this replication instance */
	seq_num		strm_jnl_seqno;		/* Whenever a supplementary receiver handshakes with a non-supplementary source,
						 * the current jnl seqno (which is across all streams) is sent in the initial
						 * REPL_START_JNL_SEQNO message. Only after the source server sends the
						 * REPL_NEED_INSTINFO message does the receiver know which non-supplementary stream
						 * the source corresponds to and can therefore determine the stream specific
						 * jnl seqno. Once this is known, instead of re-sending the REPL_START_JNL_SEQNO
						 * message, the receiver sends this new seqno in the "strm_jnl_seqno" field as
						 * part of the REPL_INSTINFO message. In cases where the receiver is not
						 * supplementary or if the soruce is supplementary, this field is set to 0.
						 */
	repl_inst_uuid	lms_group_info;
	unsigned char	was_rootprimary;
	char		filler_32[7];
} repl_instinfo_msg_t; /* The first two fields should be as in repl_msg_t */

typedef struct	/* used to send messages of type REPL_CMP_TEST or REPL_CMP_SOLVE */
{
	int4		type;
	int4		len;
	int4		datalen;		   /* length of compressed or uncompressed data */
	char		proto_ver;
	char		filler_16[3];
	char		data[REPL_MSG_CMPDATALEN]; /* compressed (if REPL_CMP_TEST) or uncompressed (if REPL_CMP_SOLVE) data */
	char		overflowdata[(MAX_CMP_EXPAND_FACTOR - 1) * REPL_MSG_CMPDATALEN];
					/* buffer to hold overflow in case compression expands data */
} repl_cmpinfo_msg_t; /* The first two fields should be as in repl_msg_t */

typedef struct	/* used to send a message of type REPL_NEED_HISTINFO */
{
	int4		type;
	int4		len;
	seq_num		seqno;		/* The histinfo requested is that of "seqno-1" */
	int4		strm_num;	/* used only in case of supplementary instances */
	int4		histinfo_num;	/* if not INVALID_HISTINFO_NUM, then we want the histinfo_num'th history record
					 * on the remote side. in this case ignore seqno & strm_num.
					 */
	char		filler_32[8];
} repl_needhistinfo_msg_t; /* The first two fields should be as in repl_msg_t */

typedef struct	/* used to send a message of type REPL_OLD_TRIPLEINFO1 */
{
	int4		type;
	int4		len;
	seq_num		start_seqno;	/* the starting seqno of the histinfo range */
	unsigned char	instname[MAX_INSTNAME_LEN];
} repl_histinfo1_msg_t; /* The first two fields should be as in repl_msg_t */

typedef struct	/* used to send a message of type REPL_OLD_TRIPLEINFO2 */
{
	int4		type;
	int4		len;
	seq_num		start_seqno;	/* the starting seqno of the histinfo range */
	uint4		cycle;
	int4		histinfo_num;
	char		filler_32[8];
} repl_histinfo2_msg_t; /* The first two fields should be as in repl_msg_t */

typedef struct	/* used to send a message of type REPL_HISTINFO */
{
	int4		type;
	int4		len;
	repl_histinfo	history;
} repl_histinfo_msg_t; /* The first two fields should be as in repl_msg_t */

/* A REPL_OLD_TRIPLE message is sent in such a form that the receiver server can copy it (after removing the 8-byte header
 * containing the "type" and "len") as such into the receive pool. The update process treats this content as yet another
 * journal record type. Therefore we need to introduce a new journal record type (JRT_TRIPLE) for this purpose and define a
 * structure (repl_old_triple_jnl_t) that has this type information and the triple related information. This will then be a
 * member of the REPL_OLD_TRIPLE message.
 * Note: GT.M versions that support supplementary instances send a REPL_HISTREC message instead of REPL_OLD_TRIPLE.
 */
typedef struct	/* sub-structure used to send a message of type REPL_OLD_TRIPLE */
{
	uint4		jrec_type : 8;	/* This definition is copied from that of "jrec_prefix" */
	uint4		forwptr : 24;	/* This definition is copied from that of "jrec_prefix" */
	uint4		cycle;		/* The cycle of the instance at the time of generating this triple */
	seq_num		start_seqno;	/* The starting seqno of the triple range */
	unsigned char	instname[MAX_INSTNAME_LEN];	/* The instance name that generated this triple */
	unsigned char	rcvd_from_instname[MAX_INSTNAME_LEN];	/* instance name this triple was received from (on the secondary) */
} repl_old_triple_jnl_t;

typedef struct	/* used to send a message of type REPL_OLD_TRIPLE */
{
	int4			type;
	int4			len;
	repl_old_triple_jnl_t	triplecontent;
} repl_old_triple_msg_t; /* The first two fields should be as in repl_msg_t */

typedef struct	/* sub-structure used to send a message of type REPL_HISTREC */
{
	uint4		jrec_type : 8;	/* This definition is copied from that of "jrec_prefix" */
	uint4		forwptr : 24;	/* This definition is copied from that of "jrec_prefix" */
	uint4		filler_8byte_align;
	repl_histinfo	histcontent;	/* the structure containing the history information */
} repl_histrec_jnl_t;

typedef struct	/* used to send a message of type REPL_HISTREC */
{
	int4			type;
	int4			len;
	repl_histrec_jnl_t	histjrec;	/* the journal record containing the history information */
} repl_histrec_msg_t; /* The first two fields should be as in repl_msg_t */

typedef struct	/* used to send a message of type REPL_NEED_STRMINFO */
{
	int4		type;
	int4		len;
	seq_num		seqno;	/* The strminfo requested is that of "seqno-1" */
	char		filler_32[16];
} repl_needstrminfo_msg_t; /* The first two fields should be as in repl_msg_t */

typedef struct	/* used to send a message of type REPL_STRMINFO */
{
	int4		type;
	int4		len;
	int4		last_histinfo_num[MAX_SUPPL_STRMS];
} repl_strminfo_msg_t; /* The first two fields should be as in repl_msg_t */

typedef struct
{
	int4		type;
	int4		len;
	unsigned char	ack_seqno[SIZEOF(seq_num)];
	unsigned char	ack_time[SIZEOF(gtm_time4_t)];
	unsigned char	filler_32[12];
} repl_heartbeat_msg_t; /* The first two fields should be as in repl_msg_t */

typedef struct
{
	struct
	{
		sm_off_t	fl;
		sm_off_t	bl;
	} que;
	repl_heartbeat_msg_t	heartbeat;
} repl_heartbeat_que_entry_t;

typedef struct		/* Used to send a message of type REPL_BADTRANS or REPL_CMP2UNCMP */
{
	int4		type;
	int4		len;
	seq_num		start_seqno;	/* The seqno that source server should restart sending from */
	char		filler_32[16];
} repl_badtrans_msg_t;

#if defined(__osf__) && defined(__alpha)
# pragma pointer_size(save)
# pragma pointer_size(long)
#endif

typedef repl_msg_t		*repl_msg_ptr_t;
typedef repl_cmpmsg_t		*repl_cmpmsg_ptr_t;
typedef repl_start_msg_t	*repl_start_msg_ptr_t;
typedef repl_start_reply_msg_t	*repl_start_reply_msg_ptr_t;
typedef repl_resync_msg_t	*repl_resync_msg_ptr_t;
typedef repl_old_needinst_msg_t	*repl_old_needinst_msg_ptr_t;
typedef repl_needinst_msg_t	*repl_needinst_msg_ptr_t;
typedef repl_old_instinfo_msg_t	*repl_old_instinfo_msg_ptr_t;
typedef repl_instinfo_msg_t	*repl_instinfo_msg_ptr_t;
typedef repl_needhistinfo_msg_t	*repl_needhistinfo_msg_ptr_t;
typedef repl_histinfo1_msg_t	*repl_histinfo1_msg_ptr_t;
typedef repl_histinfo2_msg_t	*repl_histinfo2_msg_ptr_t;
typedef repl_old_triple_jnl_t	*repl_old_triple_jnl_ptr_t;
typedef repl_histrec_jnl_t	*repl_histrec_jnl_ptr_t;
typedef repl_histinfo_msg_t	*repl_histinfo_msg_ptr_t;
typedef repl_needstrminfo_msg_t	*repl_needstrminfo_msg_ptr_t;
typedef repl_strminfo_msg_t	*repl_strminfo_msg_ptr_t;
typedef repl_heartbeat_msg_t	*repl_heartbeat_msg_ptr_t;
typedef repl_cmpinfo_msg_t	*repl_cmpinfo_msg_ptr_t;

#if defined(__osf__) && defined(__alpha)
# pragma pointer_size(restore)
#endif

void	gtmsource_repl_send(repl_msg_ptr_t msg, char *msgtypestr, seq_num optional_seqno, int4 optional_strm_num);
void	gtmsource_send_new_histrec(void);

void	gtmrecv_repl_send(repl_msg_ptr_t msgp, int4 type, int4 len, char *msgtypestr, seq_num optional_seqno);
void	gtmrecv_send_histinfo(repl_histinfo *histinfo);
void	gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg, boolean_t is_rcvr_srvr);

#endif
