/**************************************************************** * * * Copyright 2001, 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. * * * ****************************************************************/ #include "mdef.h" #include "min_max.h" #include "gtm_string.h" #ifdef VMS #include "iosb_disk.h" #endif #include "gdsroot.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 "mur_read_file.h" #include "iosp.h" #include "gtmmsg.h" GBLREF mur_opt_struct mur_options; error_def(ERR_DBJNLNOTMATCH); error_def(ERR_JNLBADRECFMT); error_def(ERR_JNLCYCLE); error_def(ERR_JNLTNOUTOFSEQ); error_def(ERR_MUJNLPREVGEN); 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; }