/****************************************************************
 *								*
 * Copyright (c) 2003-2015 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.	*
 *								*
 ****************************************************************/

#include "mdef.h"

#include "gtm_time.h"

#include "error.h"
#include "gdsroot.h"
#include "gdsblk.h"
#include "gdsbt.h"
#include "gtm_facility.h"
#include "fileinfo.h"
#include "gdsfhead.h"
#include "filestruct.h"
#include "jnl.h"
#include "buddy_list.h"
#include "hashtab_int4.h"	/* needed for muprec.h */
#include "hashtab_int8.h"	/* needed for muprec.h */
#include "hashtab_mname.h"	/* needed for muprec.h */
#include "muprec.h"
#include "iosp.h"
#include "jnl_typedef.h"
#include "gtmmsg.h"			/* for "gtm_putmsg" prototype */
#include "mur_validate_checksum.h"	/* for "mur_validate_checksum" prototype */
#include "interlock.h"
#include "gtm_multi_proc.h"

GBLREF reg_ctl_list		*mur_ctl;
GBLREF mur_gbls_t		murgbl;
GBLREF mur_opt_struct 		mur_options;

error_def(ERR_NOPREVLINK);
error_def(ERR_TEXT);

boolean_t mur_ztp_lookback(void)
{
	multi_struct		*multi;
	reg_ctl_list		*rctl, *rctl_top;
	jnl_ctl_list		*jctl;
	uint4			status;
	jnl_record		*jrec;
	pini_list_struct	*plst;
	enum jnl_record_type 	rectype;
	token_num		token;

	assert(FENCE_NONE != mur_options.fences);
	for (rctl = mur_ctl, rctl_top = mur_ctl + murgbl.reg_total; rctl < rctl_top; rctl++)
	{
		jctl = rctl->jctl;
		assert(jctl->reg_ctl == rctl);
		assert(NULL != rctl->jctl_turn_around);
		assert(jctl == rctl->jctl_turn_around);
		assert(jctl->rec_offset == jctl->turn_around_offset);
		status = mur_prev(jctl, jctl->rec_offset);
		assert(SS_NORMAL == status);
		for ( ; SS_NORMAL == status; )
		{
			status = mur_prev_rec(&jctl);	/* scan journal file in reverse order */
			if (SS_NORMAL != status)
				break;
			jrec = jctl->reg_ctl->mur_desc->jnlrec;
			rectype = (enum jnl_record_type)jrec->prefix.jrec_type;
			if (mur_options.verify && !mur_validate_checksum(jctl))
			{
				gtm_putmsg_csa(CSA_ARG(rctl->csa)
					VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT("Checksum validation failed"));
				return FALSE;
			}
			if (mur_options.lookback_time_specified && jrec->prefix.time <= mur_options.lookback_time)
				break;
			if (mur_options.lookback_opers_specified)
			{
				if (IS_FUPD_TUPD(rectype) || (!IS_FENCED(rectype) && IS_SET_KILL_ZKILL_ZTRIG(rectype)))
				{
					rctl->lookback_count++;
					if (rctl->lookback_count > mur_options.lookback_opers)
						break;
				}
			}
			if (IS_FUPD(rectype))
			{
				token = ((struct_jrec_upd *)jrec)->token_seq.token;
			    	if ((NULL != (multi = MUR_TOKEN_LOOKUP(token, 0, ZTPFENCE))) && (0 < multi->partner))
				{	/* this transaction has already been identified as broken */
					/* see turn-around-point code in mur_back_process/mur_apply_pblk for the fields to clear */
					rctl->jctl_turn_around->turn_around_offset = 0;
					rctl->jctl_turn_around->turn_around_time = 0;
					rctl->jctl_turn_around->turn_around_seqno = 0;
					rctl->jctl_turn_around->turn_around_tn = 0;
					/* Now save new turn around point.
					 * Force the entire Z transaction beginning from ZTSTART (FUPD actually)
					 * to be reported as broken and undo this transaction from the db */
					rctl->jctl_turn_around = jctl;
					jctl->turn_around_offset = jctl->rec_offset;
					if (multi->time > jrec->prefix.time)
						multi->time = jrec->prefix.time;
					if (mur_options.verbose)
						PRINT_VERBOSE_STAT(jctl, "mur_ztp_lookback");
				}
			}
		}
		if (ERR_NOPREVLINK == status)
		{
			if (mur_options.lookback_time_specified)
			{
				gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(4) ERR_NOPREVLINK, 2, jctl->jnl_fn_len, jctl->jnl_fn);
				return FALSE;
			}
			gtm_putmsg_csa(CSA_ARG(rctl->csa)
					VARLSTCNT(4) MAKE_MSG_INFO(ERR_NOPREVLINK), 2, jctl->jnl_fn_len, jctl->jnl_fn);
		} else if (SS_NORMAL != status)
			return FALSE;
	}
	return TRUE;
}
