/* Returns 0 (SS_NORMAL) on success. Non-zero on failure */
uint4	mur_jctl_from_next_gen(reg_ctl_list *rctl)
{
    jnl_ctl_list	*jctl, *temp_jctl;
    uint4		status;

    status = gtm_pthread_init_key(rctl->gd);
    if (0 != status)
        return status;
    if (!rctl->jfh_recov_interrupted)
        return SS_NORMAL;
    assert(rctl->jctl_apply_pblk == rctl->jctl_head);
    jctl = rctl->jctl_apply_pblk;	/* journal file that has the turn around point of interrupted recovery */
    assert(rctl->jctl == jctl);
    assert(NULL != rctl->jctl_alt_head);	/* should have been set in mur_apply_pblk */
    assert(NULL != jctl->jfh);
    assert(!jctl->jfh->recover_interrupted);
    for ( ; NULL != jctl->next_gen; jctl = jctl->next_gen)
        assert(!jctl->next_gen->jfh->recover_interrupted);
    while (0 != jctl->jfh->next_jnl_file_name_length)
    {   /* create the linked list of journal files created by GT.M originally */
        if (multi_thread_in_use)
        {   /* exit thread if master process got signal (e.g. SIGTERM) to request exit */
            PTHREAD_EXIT_IF_FORCED_EXIT;
        }
        temp_jctl = (jnl_ctl_list *)malloc(SIZEOF(jnl_ctl_list));	/* gtm_malloc is now thread safe */
        memset(temp_jctl, 0, SIZEOF(jnl_ctl_list));
        temp_jctl->jnl_fn_len = jctl->jfh->next_jnl_file_name_length;
        memcpy(temp_jctl->jnl_fn, jctl->jfh->next_jnl_file_name, jctl->jfh->next_jnl_file_name_length);
        if (SS_NORMAL != (status = mur_fopen(temp_jctl, rctl)))
        {
            free(temp_jctl);
            return status;
        }
        if (SS_NORMAL != (jctl->status = mur_fread_eof(temp_jctl, rctl)))
        {
            gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(9) ERR_JNLBADRECFMT, 3,
                           temp_jctl->jnl_fn_len, temp_jctl->jnl_fn, temp_jctl->rec_offset,
                           ERR_TEXT, 2, LEN_AND_LIT("mur_jctl_from_next_gen"));
            free(temp_jctl);
            return ERR_JNLBADRECFMT;
        }
        temp_jctl->prev_gen = jctl;
        temp_jctl->next_gen = NULL;
        jctl->next_gen = temp_jctl;
        jctl = temp_jctl;
    }
    rctl->jctl = jctl;
    assert(jctl->reg_ctl == rctl);
    return SS_NORMAL;
}
Beispiel #2
0
boolean_t mur_insert_prev(jnl_ctl_list **jjctl)
{
	reg_ctl_list	*rctl;
	jnl_ctl_list	*new_jctl, *cur_jctl, *jctl;
	redirect_list	*rl_ptr;
	boolean_t	proceed;

	jctl = *jjctl;
	rctl = jctl->reg_ctl;
   	assert(rctl->jctl_head == jctl);
   	assert(rctl->jctl == jctl);
	new_jctl = (jnl_ctl_list *)malloc(SIZEOF(jnl_ctl_list));
	memset(new_jctl, 0, SIZEOF(jnl_ctl_list));
	memcpy(new_jctl->jnl_fn, jctl->jfh->prev_jnl_file_name, jctl->jfh->prev_jnl_file_name_length);
	new_jctl->jnl_fn_len = jctl->jfh->prev_jnl_file_name_length;
	assert(0 != new_jctl->jnl_fn_len);
	if (FALSE == mur_fopen(new_jctl))
	{
		free(new_jctl);
		return FALSE;	/* "mur_fopen" would have printed the appropriate error message */
	}
	if (SS_NORMAL != (new_jctl->status = mur_fread_eof(new_jctl, rctl)))
	{
		gtm_putmsg(VARLSTCNT(6) ERR_JNLBADRECFMT, 3, new_jctl->jnl_fn_len, new_jctl->jnl_fn,
				new_jctl->rec_offset, new_jctl->status);
		free(new_jctl);
		return FALSE;
	}
	/* It is NOT possible for a previous generation journal file to have jfh->crash to be TRUE. Assert that.
	 * This also indicates that jctl->properly_closed will always be TRUE for a previous generation journal
	 * file. The only exception is if the current generation journal file is created by recovery. In this
	 * case the previous generation journal file (not created by recover) can have the crash field set to TRUE.
	 */
	assert((new_jctl->properly_closed && !new_jctl->jfh->crash) || (jctl->jfh->recover_interrupted &&
			!new_jctl->jfh->recover_interrupted));
	assert(!mur_options.forward || (!(jctl->jfh->recover_interrupted && !new_jctl->jfh->recover_interrupted)));
	/* Skip the continuty of journal files check if both of these are true:
	 * 1) if current generation was created by recover and
	 * 2) the new one to be inserted was not created by recover
	 */
	if (!(jctl->jfh->recover_interrupted && !new_jctl->jfh->recover_interrupted))
	{
		if (!new_jctl->properly_closed)
		{
			proceed = (FALSE == mur_report_error(jctl, MUR_PREVJNLNOEOF)); /* message report left to mur_report_error */
			if (mur_options.update || !proceed)
			{
				free(new_jctl);
				return FALSE;
			}
		}
		if ((!mur_options.forward || !mur_options.notncheck) && (new_jctl->jfh->eov_tn != jctl->jfh->bov_tn))
		{
			gtm_putmsg(VARLSTCNT(8) ERR_JNLTNOUTOFSEQ, 6,
				&new_jctl->jfh->eov_tn, new_jctl->jnl_fn_len, new_jctl->jnl_fn,
				&jctl->jfh->bov_tn, jctl->jnl_fn_len, jctl->jnl_fn);
			free(new_jctl);
			return FALSE;
		}
	}
	if ((rctl->gd->dyn.addr->fname_len != new_jctl->jfh->data_file_name_length) ||
		(0 != memcmp(new_jctl->jfh->data_file_name, rctl->gd->dyn.addr->fname, rctl->gd->dyn.addr->fname_len)))
	{
		for (rl_ptr = mur_options.redirect;  (NULL != rl_ptr);  rl_ptr = rl_ptr->next)
		{
			if ((new_jctl->jfh->data_file_name_length == rl_ptr->org_name_len)
				&& (0 == memcmp(new_jctl->jfh->data_file_name,
					rl_ptr->org_name, rl_ptr->org_name_len)))
				break;
		}
		if (NULL == rl_ptr)
		{
			gtm_putmsg(VARLSTCNT(8) ERR_DBJNLNOTMATCH, 6, DB_LEN_STR(rctl->gd), new_jctl->jnl_fn_len,
					new_jctl->jnl_fn, new_jctl->jfh->data_file_name_length,
					new_jctl->jfh->data_file_name);
			free(new_jctl);
			return FALSE;
		}
	}
	for (cur_jctl = rctl->jctl_head; cur_jctl; cur_jctl = cur_jctl->next_gen)
	{
		if (new_jctl->jfh->prev_jnl_file_name_length == cur_jctl->jnl_fn_len &&
			0 == memcmp(new_jctl->jfh->prev_jnl_file_name, cur_jctl->jnl_fn, cur_jctl->jnl_fn_len))
		{
			gtm_putmsg(VARLSTCNT(6) ERR_JNLCYCLE, 4, cur_jctl->jnl_fn_len, cur_jctl->jnl_fn, DB_LEN_STR(rctl->gd));
			free(new_jctl);
			return FALSE;
		}
		if (new_jctl->jfh->turn_around_offset && cur_jctl->jfh->turn_around_offset)
		{
			if (rctl->recov_interrupted)
			{	/* Possible if a first recovery with a turn-around-point (T2) got interrupted and a second
				 * recovery with a new turn-around-point (T1 which is in a previous generation journal file)
				 * was re-interrupted while in the middle of mur_process_intrpt_recov just after it had
				 * recorded the new turn-around-point (T1) but before it had erased the former one (T2).
				 * In this case, erase the turn-around-point T2 so this recovery goes back to T1. Here we
				 * erase the value only in memory. The value on disk is reset later in mur_process_intrpt_recov.
				 */
				cur_jctl->jfh->turn_around_offset = 0;
				cur_jctl->jfh->turn_around_time = 0;
			} else
				GTMASSERT; /* out of design situation */
		}
	}
	new_jctl->prev_gen = NULL;
	new_jctl->next_gen = jctl;
	jctl->prev_gen = new_jctl;
	rctl->jctl = rctl->jctl_head = new_jctl;
	assert(new_jctl->reg_ctl == rctl);
	*jjctl = new_jctl;
	gtm_putmsg(VARLSTCNT(6) ERR_MUJNLPREVGEN, 4, new_jctl->jnl_fn_len, new_jctl->jnl_fn, DB_LEN_STR(rctl->gd));
	return TRUE;
}