fis-gtm/sr_port/mur_open_files.c

734 lines
27 KiB
C
Raw Normal View History

/****************************************************************
* *
* Copyright 2003, 2011 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 "gtm_string.h"
#include "min_max.h"
#include "cli.h"
#include "gdsroot.h"
#include "gdsbt.h"
#include "gtm_facility.h"
#include "fileinfo.h"
#include "gdsblk.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 "hashtab.h"
#include "muprec.h"
#include "io.h"
#include "iosp.h"
#include "dpgbldir.h"
#include "have_crit.h"
#ifdef UNIX
#include "ftok_sems.h"
#include "repl_instance.h"
#include "mu_rndwn_replpool.h"
#include "mu_rndwn_repl_instance.h"
#include "deferred_signal_handler.h"
#elif defined(VMS)
#include <descrip.h>
#include "gtm_inet.h"
#include "iosb_disk.h" /* For mur_read_file.h */
#include "dpgbldir_sysops.h"
#include "gbldirnam.h"
#include "repl_sem.h"
#include "gtmrecv.h"
#endif
#include "mu_rndwn_file.h"
#include "read_db_files_from_gld.h"
#include "mur_db_files_from_jnllist.h"
#include "gtm_rename.h"
#include "gtmmsg.h"
#include "file_head_read.h"
#include "mupip_exit.h"
#include "mu_gv_cur_reg_init.h"
#include "dbfilop.h"
#include "mur_read_file.h" /* for "mur_fread_eof" prototype */
#include "tp_change_reg.h"
#include "gds_rundown.h"
#include "is_file_identical.h"
#include "repl_msg.h"
#include "gtmsource.h"
#include "gtm_logicals.h"
GBLREF boolean_t blocksig_initialized;
GBLREF sigset_t block_sigsent;
GBLREF reg_ctl_list *mur_ctl;
GBLREF mur_opt_struct mur_options;
GBLREF mur_gbls_t murgbl;
GBLREF gd_region *gv_cur_region;
GBLREF jnlpool_addrs jnlpool;
GBLREF boolean_t have_standalone_access;
GBLREF gd_addr *gd_header;
#if defined(VMS)
error_def (ERR_MUJPOOLRNDWNFL);
error_def (ERR_MUJPOOLRNDWNSUC);
error_def (ERR_MURPOOLRNDWNFL);
error_def (ERR_MURPOOLRNDWNSUC);
#elif defined(UNIX)
error_def (ERR_JNLFILEOPNERR);
error_def (ERR_SYSCALL);
#endif
error_def (ERR_DBFILOPERR);
error_def (ERR_DBFRZRESETFL);
error_def (ERR_DBFRZRESETSUC);
error_def (ERR_DBJNLNOTMATCH);
error_def (ERR_DBRDONLY);
error_def (ERR_FILENOTFND);
error_def (ERR_FILEPARSE);
error_def (ERR_JNLBADRECFMT);
error_def (ERR_JNLDBTNNOMATCH);
error_def (ERR_JNLFILEDUP);
error_def (ERR_JNLNMBKNOTPRCD);
error_def (ERR_JNLSTATEOFF);
error_def (ERR_JNLTNOUTOFSEQ);
error_def (ERR_MUPCLIERR);
error_def (ERR_MUPJNLINTERRUPT);
error_def (ERR_MUSTANDALONE);
error_def (ERR_NOPREVLINK);
error_def (ERR_NOSTARFILE);
error_def (ERR_NOTALLJNLEN);
error_def (ERR_NOTALLREPLON);
error_def (ERR_REPLSTATEOFF);
error_def (ERR_RLBKNOBIMG);
error_def (ERR_ROLLBKINTERRUPT);
error_def (ERR_STARFILE);
error_def (ERR_TEXT);
#define STAR_QUOTE "\"*\""
boolean_t mur_open_files()
{
int jnl_total, jnlno, regno, max_reg_total;
unsigned short jnl_file_list_len; /* cli_get_str requires a short */
char jnl_file_list[MAX_LINE];
char *cptr, *cptr_last, *ctop;
jnl_ctl_list *jctl, *temp_jctl;
reg_ctl_list *rctl, *rctl_top, tmp_rctl;
gld_dbname_list *gld_db_files, *curr;
gd_addr *temp_gd_header;
boolean_t star_specified, outofsync;
redirect_list *rl_ptr;
unsigned int full_len;
replpool_identifier replpool_id;
sgmnt_data_ptr_t csd;
sgmnt_addrs *csa;
file_control *fc;
freeze_status reg_frz_status;
#if defined(VMS)
uint4 status;
boolean_t sgmnt_found;
mstr gbldir_mstr, *tran_name;
gds_file_id file_id;
struct dsc$descriptor_s name_dsc;
char res_name[MAX_NAME_LEN + 2];/* +1 for the terminating null and
another +1 for the length stored in [0] by global_name() */
#endif
jnl_file_list_len = MAX_LINE;
if (FALSE == CLI_GET_STR_ALL("FILE", jnl_file_list, &jnl_file_list_len))
mupip_exit(ERR_MUPCLIERR);
if ((1 == jnl_file_list_len && '*' == jnl_file_list[0]) ||
(STR_LIT_LEN(STAR_QUOTE) == jnl_file_list_len &&
0 == memcmp(jnl_file_list, STAR_QUOTE, STR_LIT_LEN(STAR_QUOTE))))
{
star_specified = TRUE;
if (NULL != mur_options.redirect)
{
gtm_putmsg(VARLSTCNT(4) ERR_STARFILE, 2, LEN_AND_LIT("REDIRECT qualifier"));
mupip_exit(ERR_MUPCLIERR);
}
} else
{
star_specified = FALSE;
if (mur_options.rollback)
{
gtm_putmsg(VARLSTCNT(4) ERR_NOSTARFILE, 2, LEN_AND_LIT("ROLLBACK qualifier"));
mupip_exit(ERR_MUPCLIERR);
}
}
/* We assume recovery will be done only on current global directory.
* That is, journal file names specified must be from current global directory.
*/
if (star_specified || mur_options.update && !mur_options.redirect)
{ /* "*" is specified or it is -recover or -rollback. We require gtmgbldir to be set in all these cases.
* The only exception is "-redirect" in which case the target database is obtained from -redirect
* instead of from the global directory.
*/
assert(NULL == gd_header);
gvinit(); /* read in current global directory */
assert(NULL != gd_header);
}
if (star_specified)
{
max_reg_total = gd_header->n_regions;
gld_db_files = read_db_files_from_gld(gd_header);
} else
gld_db_files = mur_db_files_from_jnllist(jnl_file_list, jnl_file_list_len, &max_reg_total);
if (NULL == gld_db_files)
return FALSE;
mur_ctl = (reg_ctl_list *)malloc(SIZEOF(reg_ctl_list) * max_reg_total);
memset(mur_ctl, 0, SIZEOF(reg_ctl_list) * max_reg_total);
curr = gld_db_files;
murgbl.max_extr_record_length = DEFAULT_EXTR_BUFSIZE;
murgbl.repl_standalone = FALSE;
if (mur_options.rollback)
{ /* Rundown the Jnlpool and Recvpool */
#if defined(UNIX)
if (!repl_inst_get_name((char *)replpool_id.instfilename, &full_len, SIZEOF(replpool_id.instfilename),
issue_gtm_putmsg))
{ /* appropriate gtm_putmsg would have already been issued by repl_inst_get_name */
return FALSE;
}
if (!mu_rndwn_repl_instance(&replpool_id, FALSE, TRUE))
return FALSE; /* mu_rndwn_repl_instance will have printed appropriate message in case of error */
assert(NULL == jnlpool.repl_inst_filehdr);
murgbl.repl_standalone = mu_replpool_grab_sem(FALSE);
assert(NULL != jnlpool.repl_inst_filehdr);
#elif defined(VMS)
gbldir_mstr.addr = GTM_GBLDIR;
gbldir_mstr.len = SIZEOF(GTM_GBLDIR) - 1;
tran_name = get_name(&gbldir_mstr);
memcpy(replpool_id.gtmgbldir, tran_name->addr, tran_name->len);
full_len = tran_name->len;
if (!get_full_path(replpool_id.gtmgbldir, tran_name->len,
replpool_id.gtmgbldir, &full_len, MAX_TRANS_NAME_LEN, &status))
{
gtm_putmsg(VARLSTCNT(4) ERR_FILENOTFND, 2, tran_name->len, tran_name->addr);
return FALSE;
}
else
{
tran_name->len = full_len; /* since on vax, mstr.len is a 'short' */
set_gdid_from_file((gd_id_ptr_t)&file_id, replpool_id.gtmgbldir, tran_name->len);
global_name("GT$P", &file_id, res_name); /* P - Stands for Journal Pool */
res_name[res_name[0] + 1] = '\0';
STRCPY(replpool_id.repl_pool_key, &res_name[1]);
replpool_id.pool_type = JNLPOOL_SEGMENT;
sgmnt_found = FALSE;
if (mu_rndwn_replpool(&replpool_id, FALSE, &sgmnt_found) && sgmnt_found)
gtm_putmsg(VARLSTCNT(6) ERR_MUJPOOLRNDWNSUC, 4, res_name[0], &res_name[1],
tran_name->len, replpool_id.gtmgbldir);
else if (sgmnt_found)
{
gtm_putmsg(VARLSTCNT(6) ERR_MUJPOOLRNDWNFL, 4, res_name[0], &res_name[1],
tran_name->len, replpool_id.gtmgbldir);
return FALSE;
}
global_name("GT$R", &file_id, res_name); /* R - Stands for Recv Pool */
res_name[res_name[0] + 1] = '\0';
STRCPY(replpool_id.repl_pool_key, &res_name[1]);
replpool_id.pool_type = RECVPOOL_SEGMENT;
sgmnt_found = FALSE;
if (mu_rndwn_replpool(&replpool_id, FALSE, &sgmnt_found) && sgmnt_found)
gtm_putmsg(VARLSTCNT(6) ERR_MURPOOLRNDWNSUC, 4, res_name[0], &res_name[1],
tran_name->len, replpool_id.gtmgbldir);
else if (sgmnt_found)
{
gtm_putmsg(VARLSTCNT(6) ERR_MURPOOLRNDWNFL, 4, res_name[0], &res_name[1],
tran_name->len, replpool_id.gtmgbldir);
return FALSE;
}
}
#endif
}
for (murgbl.reg_full_total = 0, rctl = mur_ctl, rctl_top = mur_ctl + max_reg_total;
rctl < rctl_top; rctl++, curr = curr->next)
{ /* Do region specific initialization */
rctl->initialized = FALSE;
rctl->gd = curr->gd; /* region structure is already set with proper values */
rctl->standalone = FALSE;
rctl->csa = NULL;
rctl->csd = NULL;
rctl->jctl = rctl->jctl_head = rctl->jctl_alt_head = rctl->jctl_turn_around = rctl->jctl_apply_pblk = NULL;
murgbl.reg_full_total++; /* mur_close_files() expects rctl->csa and rctl->jctl to be initialized.
* so consider this rctl only after those have been initialized. */
init_hashtab_mname(&rctl->gvntab, 0, HASHTAB_NO_COMPACT, HASHTAB_NO_SPARE_TABLE); /* for mur_forward() */
rctl->db_ctl = (file_control *)malloc(SIZEOF(file_control));
memset(rctl->db_ctl, 0, SIZEOF(file_control));
mur_rctl_desc_alloc(rctl); /* Allocate rctl->mur_desc associated buffers */
/* For redirect we just need to change the name of database. recovery will redirect to new database file */
if (mur_options.redirect)
{
for (rl_ptr = mur_options.redirect; rl_ptr != NULL; rl_ptr = rl_ptr->next)
{
if (curr->gd->dyn.addr->fname_len == rl_ptr->org_name_len &&
0 == memcmp(curr->gd->dyn.addr->fname, rl_ptr->org_name, rl_ptr->org_name_len))
{
curr->gd->dyn.addr->fname_len = rl_ptr->new_name_len;
memcpy(curr->gd->dyn.addr->fname, rl_ptr->new_name, curr->gd->dyn.addr->fname_len);
curr->gd->dyn.addr->fname[curr->gd->dyn.addr->fname_len] = 0;
break;
}
}
}
if (!mupfndfil(curr->gd, NULL))
{
if (mur_options.update || star_specified)
{
gtm_putmsg(VARLSTCNT(4) ERR_FILENOTFND, 2, DB_LEN_STR(curr->gd));
return FALSE;
}
/* else for 1) show 2) extract 3) verify action qualifier ,
* we do not need database to be present unless star (*) specified.
* For star we need to get journal file name from database file header,
* so database must be present in the system.
* NOTE: csa and csd fields are NULL, if database is not present */
} else /* database present */
{
if (mur_options.update)
{ /* recover and rollback qualifiers always require standalone access */
gv_cur_region = rctl->gd; /* mu_rndwn_file() assumes gv_cur_region is set in VMS */
if (!STANDALONE(rctl->gd)) /* STANDALONE macro calls mu_rndwn_file() */
{
gtm_putmsg(VARLSTCNT(4) ERR_MUSTANDALONE, 2, DB_LEN_STR(rctl->gd));
return FALSE;
}
have_standalone_access = TRUE;
rctl->standalone = TRUE;
}
if (mur_options.update || mur_options.extr[GOOD_TN])
{ /* NOTE: Only for collation info extract needs database access */
gvcst_init(rctl->gd);
DEFER_INTERRUPTS(INTRPT_IN_MUR_OPEN_FILES); /* temporarily disable MUPIP STOP/signal handling. */
csa = rctl->csa = &FILE_INFO(rctl->gd)->s_addrs;
csd = rctl->csd = rctl->csa->hdr;
if (mur_options.update)
{
assert(!csa->nl->donotflush_dbjnl);
csa->nl->donotflush_dbjnl = TRUE; /* indicate gds_rundown/mu_rndwn_file to not wcs_flu()
* this shared memory until recover/rlbk cleanly exits */
}
if (rctl->gd->read_only && mur_options.update)
{
gtm_putmsg(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(rctl->gd));
ENABLE_INTERRUPTS(INTRPT_IN_MUR_OPEN_FILES);
return FALSE;
}
assert(!JNL_ENABLED(csd) || 0 == csd->jnl_file_name[csd->jnl_file_len]);
rctl->db_ctl->file_type = rctl->gd->dyn.addr->file_cntl->file_type;
rctl->db_ctl->file_info = rctl->gd->dyn.addr->file_cntl->file_info;
rctl->recov_interrupted = csd->recov_interrupted;
if (mur_options.update && rctl->recov_interrupted)
{ /* interrupted recovery might have changed current csd's jnl_state/repl_state.
* restore the state of csd before the start of interrupted recovery.
*/
if (mur_options.forward)
{ /* error out. need fresh backup of database for forward recovery */
gtm_putmsg(VARLSTCNT(4) ERR_MUPJNLINTERRUPT, 2, DB_LEN_STR(rctl->gd));
ENABLE_INTERRUPTS(INTRPT_IN_MUR_OPEN_FILES);
return FALSE;
}
/* In case rollback with non-zero resync_seqno got interrupted, we would have
* written intrpt_recov_resync_seqno. If so, cannot use RECOVER now.
* In all other cases, intrpt_recov_resolve_time would have been written.
*/
if (!mur_options.rollback && csd->intrpt_recov_resync_seqno)
{
gtm_putmsg(VARLSTCNT(4) ERR_ROLLBKINTERRUPT, 2, DB_LEN_STR(rctl->gd));
ENABLE_INTERRUPTS(INTRPT_IN_MUR_OPEN_FILES);
return FALSE;
}
csd->jnl_state = csd->intrpt_recov_jnl_state;
csd->repl_state = csd->intrpt_recov_repl_state;
}
/* Save current states */
rctl->jnl_state = csd->jnl_state;
rctl->repl_state = csd->repl_state;
rctl->before_image = csd->jnl_before_image;
rctl->initialized = TRUE;
ENABLE_INTERRUPTS(INTRPT_IN_MUR_OPEN_FILES); /* reenable the interrupts */
if (mur_options.update)
{
if (!mur_options.rollback)
{
if (!mur_options.forward && !JNL_ENABLED(csd))
{
if (!star_specified)
{
gtm_putmsg(VARLSTCNT(4) ERR_JNLSTATEOFF, 2, DB_LEN_STR(rctl->gd));
return FALSE;
}
continue;
}
} else
{
if (!REPL_ALLOWED(csd))
{
if (JNL_ENABLED(csd))
{
gtm_putmsg(VARLSTCNT(4) ERR_REPLSTATEOFF, 2, DB_LEN_STR(rctl->gd));
return FALSE;
}
continue;
}
UNIX_ONLY(
else if (!rctl->before_image)
{ /* Replicated database with NOBEFORE_IMAGE journaling.
* ROLLBACK is allowed only if -FETCHRESYNC or -RESYNC is specified.
*/
if (!mur_options.fetchresync_port && !mur_options.resync_specified)
{
gtm_putmsg(VARLSTCNT(4) ERR_RLBKNOBIMG, 2, DB_LEN_STR(rctl->gd));
return FALSE;
}
mur_options.rollback_losttnonly = TRUE;
}
)
}
if (csd->freeze)
{ /* region_freeze should release freeze here */
reg_frz_status = region_freeze(curr->gd, FALSE, TRUE, FALSE);
assert (0 == rctl->csa->hdr->freeze);
assert(REG_FREEZE_SUCCESS == reg_frz_status);
if (REG_ALREADY_FROZEN == reg_frz_status)
{
gtm_putmsg(VARLSTCNT(4) ERR_DBFRZRESETFL, 2, DB_LEN_STR(curr->gd));
return FALSE;
}
gtm_putmsg(VARLSTCNT(4) ERR_DBFRZRESETSUC, 2, DB_LEN_STR(curr->gd));
}
/* save current jnl/repl state before changing in case recovery is interrupted */
csd->intrpt_recov_jnl_state = csd->jnl_state;
csd->intrpt_recov_repl_state = csd->repl_state;
csd->recov_interrupted = TRUE;
/* Temporarily change current state. mur_close_files() will restore them as appropriate */
if (mur_options.forward && JNL_ENABLED(csd))
csd->jnl_state = jnl_closed;
csd->repl_state = repl_closed;
csd->file_corrupt = TRUE;
/* flush the changed csd to disk */
fc = rctl->gd->dyn.addr->file_cntl;
fc->op = FC_WRITE;
fc->op_buff = (sm_uc_ptr_t)csd;
fc->op_len = (int)ROUND_UP(SIZEOF_FILE_HDR(csd), DISK_BLOCK_SIZE);
fc->op_pos = 1;
dbfilop(fc);
}
rctl->db_tn = csd->trans_hist.curr_tn;
/* Some routines use csa */
csa->jnl_state= csd->jnl_state;
csa->repl_state = csd->repl_state;
csa->jnl_before_image = csd->jnl_before_image;
} else
{ /* temporarily disable MUPIP STOP/signal handling. */
DEFER_INTERRUPTS(INTRPT_IN_MUR_OPEN_FILES);
/* NOTE: csa field is NULL, if we do not open database */
csd = rctl->csd = (sgmnt_data_ptr_t)malloc(SGMNT_HDR_LEN);
assert(0 == curr->gd->dyn.addr->fname[curr->gd->dyn.addr->fname_len]);
/* 1) show 2) extract 3) verify action does not need standalone access.
* In this case csa is NULL */
if (!file_head_read((char *)curr->gd->dyn.addr->fname, rctl->csd, SGMNT_HDR_LEN))
{
gtm_putmsg(VARLSTCNT(4) ERR_DBFILOPERR, 2, REG_LEN_STR(rctl->gd));
return FALSE;
}
rctl->jnl_state = csd->jnl_state;
rctl->repl_state = csd->repl_state;
rctl->before_image = csd->jnl_before_image;
rctl->initialized = TRUE;
ENABLE_INTERRUPTS(INTRPT_IN_MUR_OPEN_FILES); /* reenable the interrupts */
}
/* For star_specified we open journal files here.
* For star_specified we cannot do anything if journaling is disabled */
if (star_specified && JNL_ALLOWED(csd))
{
jctl = (jnl_ctl_list *)malloc(SIZEOF(jnl_ctl_list));
memset(jctl, 0, SIZEOF(jnl_ctl_list));
rctl->jctl_head = rctl->jctl = jctl;
jctl->jnl_fn_len = csd->jnl_file_len;
memcpy(jctl->jnl_fn, csd->jnl_file_name, csd->jnl_file_len);
jctl->jnl_fn[jctl->jnl_fn_len] = 0;
/* If system crashed during rename, following will fix it .
* Following function is directly related to cre_jnl_file_common */
cre_jnl_file_intrpt_rename(jctl->jnl_fn_len, jctl->jnl_fn);
if (!mur_fopen(jctl))
{
return FALSE;
}
if (SS_NORMAL != (jctl->status = mur_fread_eof(jctl, rctl)))
{
gtm_putmsg(VARLSTCNT(9) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn,
jctl->rec_offset, ERR_TEXT, 2, LEN_AND_LIT("mur_fread_eof failed"));
return FALSE;
}
if (!is_file_identical((char *)jctl->jfh->data_file_name, (char *)rctl->gd->dyn.addr->fname))
{
gtm_putmsg(VARLSTCNT(8) ERR_DBJNLNOTMATCH, 6, DB_LEN_STR(rctl->gd),
jctl->jnl_fn_len, jctl->jnl_fn,
jctl->jfh->data_file_name_length, jctl->jfh->data_file_name);
return FALSE;
}
}
} /* mupfndfil */
} /* End for */
/* At this point mur_ctl[] has been created from the current global directory database file names
* or from the journal file header's database names.
* For star_specified == TRUE implicitly only current generation journal files are specified and already opened
* For star_specified == FALSE user can specify multiple generations. We need to sort them */
if (!star_specified)
{
jnlno = 0;
cptr = jnl_file_list;
ctop = &jnl_file_list[jnl_file_list_len];
while (cptr < ctop)
{
jctl = (jnl_ctl_list *)malloc(SIZEOF(jnl_ctl_list));
memset(jctl, 0, SIZEOF(jnl_ctl_list));
cptr_last = cptr;
while (0 != *cptr && ',' != *cptr && '"' != *cptr && ' ' != *cptr)
++cptr;
if (!get_full_path(cptr_last, (unsigned int)(cptr - cptr_last),
(char *)jctl->jnl_fn, &jctl->jnl_fn_len, MAX_FN_LEN, &jctl->status2))
{
gtm_putmsg(VARLSTCNT(5) ERR_FILEPARSE, 2, cptr_last, cptr - cptr_last, jctl->status2);
return FALSE;
}
cptr++; /* skip separator */
/* Note cre_jnl_file_intrpt_rename was already called in mur_db_files_from_jnllist */
if (!mur_fopen(jctl)) /* dont know rctl yet */
{
return FALSE;
}
for (rctl = mur_ctl, rctl_top = mur_ctl + murgbl.reg_full_total; rctl < rctl_top; rctl++)
{
if (rctl->gd->dyn.addr->fname_len == jctl->jfh->data_file_name_length &&
(0 == memcmp(jctl->jfh->data_file_name, rctl->gd->dyn.addr->fname,
rctl->gd->dyn.addr->fname_len)))
break;
}
if (rctl == rctl_top)
{
for (rl_ptr = mur_options.redirect; (NULL != rl_ptr); rl_ptr = rl_ptr->next)
{
if ((jctl->jfh->data_file_name_length == rl_ptr->org_name_len)
&& (0 == memcmp(jctl->jfh->data_file_name,
rl_ptr->org_name, rl_ptr->org_name_len)))
break;
}
if (NULL != rl_ptr)
{
for (rctl = mur_ctl, rctl_top = mur_ctl + murgbl.reg_full_total; rctl < rctl_top; rctl++)
{
if (rctl->gd->dyn.addr->fname_len == rl_ptr->new_name_len &&
(0 == memcmp(rctl->gd->dyn.addr->fname, rl_ptr->new_name,
rl_ptr->new_name_len)))
break;
}
}
if (rctl == rctl_top)
GTMASSERT;/* db list was created from journal file header. So it is not possible */
}
/* Detect and report 1st case of any duplicated files in mupip forward recovery command. */
if (mur_options.forward)
{
VMS_ONLY(set_gdid_from_file(&jctl->fid, (char *)jctl->jnl_fn, jctl->jnl_fn_len);)
# if defined(UNIX)
if (filename_to_id(&jctl->fid, (char *)jctl->jnl_fn))
{
# endif
for (temp_jctl = rctl->jctl_head; temp_jctl; temp_jctl = temp_jctl->next_gen)
{
if (UNIX_ONLY(is_gdid_identical(&jctl->fid, &temp_jctl->fid))
VMS_ONLY(is_gdid_gdid_identical(&jctl->fid, &temp_jctl->fid)))
{
gtm_putmsg(VARLSTCNT(6) ERR_JNLFILEDUP, 4, jctl->jnl_fn_len,
jctl->jnl_fn, temp_jctl->jnl_fn_len, temp_jctl->jnl_fn);
return FALSE;
}
}
# if defined(UNIX)
}
else
{
gtm_putmsg(VARLSTCNT(11) ERR_JNLFILEOPNERR, 2, jctl->jnl_fn_len, jctl->jnl_fn,
ERR_SYSCALL, 5, LEN_AND_LIT("fstat"), CALLFROM, errno);
return FALSE;
}
# endif
}
if (SS_NORMAL != (jctl->status = mur_fread_eof(jctl, rctl)))
{
gtm_putmsg(VARLSTCNT(5) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn, jctl->rec_offset);
return FALSE;
}
/* Now, we have found the region for this jctl */
csd = rctl->csd;
if (!mur_options.forward)
{
rctl->jctl = rctl->jctl_head = jctl;
if (mur_options.update && !is_file_identical((char *)csd->jnl_file_name, (char *)jctl->jnl_fn))
{
gtm_putmsg(VARLSTCNT(8) ERR_JNLNMBKNOTPRCD, 6, jctl->jnl_fn_len, jctl->jnl_fn,
JNL_LEN_STR(csd), DB_LEN_STR(rctl->gd));
return FALSE;
}
} else
{ /* rctl->jctl_head will have the lowest bov_tn of the journals of the region
* Then next_gen items will be non-decreasing order of bov_tn */
if (NULL == rctl->jctl_head)
{
assert(NULL == rctl->jctl);
rctl->jctl = rctl->jctl_head = jctl;
} else
{
temp_jctl = jctl;
jctl = rctl->jctl_head;
if (temp_jctl->jfh->bov_tn < jctl->jfh->bov_tn ||
(temp_jctl->jfh->bov_tn == jctl->jfh->bov_tn &&
temp_jctl->jfh->eov_tn < jctl->jfh->eov_tn))
{
assert(NULL == jctl->prev_gen);
temp_jctl->prev_gen = NULL;
temp_jctl->next_gen = jctl;
jctl->prev_gen = temp_jctl;
rctl->jctl_head = temp_jctl;
} else
{
while (NULL != jctl->next_gen &&
((jctl->next_gen->jfh->bov_tn < temp_jctl->jfh->bov_tn) ||
(jctl->next_gen->jfh->bov_tn == temp_jctl->jfh->bov_tn &&
jctl->next_gen->jfh->eov_tn < temp_jctl->jfh->eov_tn)))
jctl = jctl->next_gen ;
temp_jctl->next_gen = jctl->next_gen;
temp_jctl->prev_gen = jctl;
if (NULL != jctl->next_gen)
jctl->next_gen->prev_gen = temp_jctl;
jctl->next_gen = temp_jctl;
}
}
} /* mur_options.forward */
} /* for jnlno */
}
/* If not all regions of a global directory are processed, we shrink mur_ctl array and conserve space.
* It is specially needed for later code */
murgbl.reg_total = murgbl.reg_full_total;
for (regno = 0; regno < murgbl.reg_total; regno++)
{
if (NULL == mur_ctl[regno].jctl)
{
for (--murgbl.reg_total; murgbl.reg_total > regno; murgbl.reg_total--)
{
rctl = &mur_ctl[murgbl.reg_total];
if (NULL != (jctl = rctl->jctl_head))
{
assert(jctl == rctl->jctl); /* rctl->jctl and rctl->jctl_head should be same now */
tmp_rctl = mur_ctl[regno];
mur_ctl[regno] = *rctl;
*rctl = tmp_rctl;
rctl = &mur_ctl[regno];
MUR_FIX_JCTL_BACK_POINTER_TO_RCTL(jctl, rctl, &mur_ctl[murgbl.reg_total], TRUE);
break;
}
}
}
}
assert(murgbl.reg_full_total == max_reg_total);
if (!mur_options.rollback && murgbl.reg_total < murgbl.reg_full_total)
gtm_putmsg(VARLSTCNT (1) ERR_NOTALLJNLEN);
else if (mur_options.rollback && murgbl.reg_total < murgbl.reg_full_total)
gtm_putmsg(VARLSTCNT (1) ERR_NOTALLREPLON);
if (0 == murgbl.reg_total)
return FALSE;
/* From this point consider only regions with journals to be processed (murgbl.reg_total)
* However mur_close_files will close all regions opened (murgbl.reg_full_total) */
for (rctl = mur_ctl, rctl_top = mur_ctl + murgbl.reg_total; rctl < rctl_top; rctl++)
{
jctl = rctl->jctl_head;
if (mur_options.update)
{
csd = rctl->csd;
if (mur_options.chain && mur_options.forward)
{ /* User might have not specified journal file starting tn matching database curr_tn.
* So try to open previous generation journal files and add to linked list */
rctl->jctl = jctl; /* asserted by mur_insert_prev */
while (jctl->jfh->bov_tn > csd->trans_hist.curr_tn)
{
if (0 == jctl->jfh->prev_jnl_file_name_length)
{
gtm_putmsg(VARLSTCNT(11) ERR_JNLDBTNNOMATCH, 9,jctl->jnl_fn_len, jctl->jnl_fn,
LEN_AND_LIT("beginning"), &jctl->jfh->bov_tn,
DB_LEN_STR(rctl->gd), &csd->trans_hist.curr_tn, &csd->jnl_eovtn);
gtm_putmsg(VARLSTCNT(4) ERR_NOPREVLINK, 2,
jctl->jnl_fn_len, jctl->jnl_fn);
return FALSE;
} else if (!mur_insert_prev(&jctl))
return FALSE;
}
}
if (mur_options.forward)
{
if (!mur_options.notncheck && (jctl->jfh->bov_tn != csd->trans_hist.curr_tn))
{
gtm_putmsg(VARLSTCNT(11) ERR_JNLDBTNNOMATCH, 9, jctl->jnl_fn_len, jctl->jnl_fn,
LEN_AND_LIT("beginning"), &jctl->jfh->bov_tn,
DB_LEN_STR(rctl->gd), &csd->trans_hist.curr_tn, &csd->jnl_eovtn);
return FALSE;
}
} else /*Backward Recovery*/
{
if (jctl->jfh->eov_tn != csd->trans_hist.curr_tn)
{ /* 'outofsync' variable identifies situations in which backward recovery
* proceeds if inequality (csd->jnl_eovtn <= jfh->eov_tn <= csd->curr_tn) is TRUE.
* So if,
* i) backward recovery is interrupted at any time except at turn around point just after
* database header is synched OR
*ii) database is crashed but journaling is behind database i.e.
* jfh->eov_tn < csd->trans_hist.curr_tn
* outofsync is set to TRUE.
* backward recovery does not proceed if,
* i) database is crashed and journaling is ahead of database
* ii) database is cleanly terminated and outofsync is FALSE
*iii) outofsync is TRUE but above mentioned inequality is FALSE and
* interruption or crash did not occur while processing turn around point
*/
outofsync = (rctl->recov_interrupted ||
(jctl->jfh->crash && (jctl->jfh->eov_tn < csd->trans_hist.curr_tn)));
if ((jctl->jfh->crash && (jctl->jfh->eov_tn > csd->trans_hist.curr_tn) &&
!rctl->recov_interrupted) || (!jctl->jfh->crash && !outofsync) ||
(outofsync && !csd->turn_around_point && (csd->jnl_eovtn != csd->trans_hist.curr_tn)
&& (csd->jnl_eovtn > jctl->jfh->eov_tn)))
{
gtm_putmsg(VARLSTCNT(11) ERR_JNLDBTNNOMATCH, 9, jctl->jnl_fn_len, jctl->jnl_fn,
LEN_AND_LIT("end"), &jctl->jfh->eov_tn, DB_LEN_STR(rctl->gd),
&csd->trans_hist.curr_tn, &csd->jnl_eovtn);
return FALSE;
}
}
}
} /* if mur_options.update */
while (NULL != jctl->next_gen) /* Check for continuity */
{
if (!mur_options.notncheck && (jctl->next_gen->jfh->bov_tn != jctl->jfh->eov_tn))
{
gtm_putmsg(VARLSTCNT(8) ERR_JNLTNOUTOFSEQ, 6,
&jctl->jfh->eov_tn, jctl->jnl_fn_len, jctl->jnl_fn,
&jctl->next_gen->jfh->bov_tn, jctl->next_gen->jnl_fn_len, jctl->next_gen->jnl_fn);
return FALSE;
}
jctl = jctl->next_gen;
}
rctl->jctl = jctl; /* latest in linked list */
} /* end for */
return TRUE;
}