822 lines
28 KiB
C
822 lines
28 KiB
C
/****************************************************************
|
|
* *
|
|
* 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 "gtm_string.h"
|
|
#include "stp_parms.h"
|
|
#include "gdsroot.h"
|
|
#include "gtm_facility.h"
|
|
#include "fileinfo.h"
|
|
#include "gdsbt.h"
|
|
#include "gdsfhead.h"
|
|
#include "error.h"
|
|
#include "cli.h"
|
|
#include "iosp.h"
|
|
#include "gdscc.h"
|
|
#include "gdskill.h"
|
|
#include "filestruct.h"
|
|
#include "jnl.h"
|
|
#include "buddy_list.h" /* needed for tp.h */
|
|
#include "hashtab_int4.h" /* needed for tp.h */
|
|
#include "tp.h"
|
|
#include "mu_int_maps.h"
|
|
#include "util.h"
|
|
#include "mupipbckup.h"
|
|
#include "dbfilop.h"
|
|
#include "targ_alloc.h"
|
|
#include "mupip_exit.h"
|
|
#ifdef UNIX
|
|
#include "ipcrmid.h"
|
|
#include "db_ipcs_reset.h"
|
|
#endif
|
|
#include "mu_getlst.h"
|
|
#include "mu_outofband_setup.h"
|
|
#include "mupip_integ.h"
|
|
#include "gtmmsg.h"
|
|
#include "collseq.h"
|
|
#ifdef GTM_SNAPSHOT
|
|
#include "db_snapshot.h"
|
|
#endif
|
|
#include "mupint.h"
|
|
#include "mu_gv_cur_reg_init.h"
|
|
|
|
#define DUMMY_GLOBAL_VARIABLE "%D%DUMMY_VARIABLE"
|
|
#define DUMMY_GLOBAL_VARIABLE_LEN SIZEOF(DUMMY_GLOBAL_VARIABLE)
|
|
#define MAX_UTIL_LEN 80
|
|
#define APPROX_ALL_ERRORS 1000000
|
|
#define DEFAULT_ERR_LIMIT 10
|
|
#define DEFAULT_ADJACENCY 10
|
|
#define PERCENT_FACTOR 100
|
|
#define PERCENT_DECIMAL_SCALE 100000
|
|
#define PERCENT_SCALE_FACTOR 1000
|
|
#define LEAVE_BLOCKS_ALONE 0x0FFFFFFFFUL
|
|
|
|
#define TEXT1 " is incorrect, should be "
|
|
#define TEXT2 "!/Largest transaction number found in database was "
|
|
#define TEXT3 "Current transaction number is "
|
|
#define MSG1 "!/!/WARNING: Transaction number reset complete on all active blocks. Please do a DATABASE BACKUP before proceeding"
|
|
/* The QWPERCENTCALC calculates the percent used compatibly with the code fragment below.
|
|
* The size is no longer int_size but is now a qw_num, so the QW macros are now used to
|
|
* do the calculation.
|
|
*
|
|
* leftpt = (int_size * PERCENT_FACTOR) / (int_blks * blk_size);
|
|
* rightpt = (int_size * PERCENT_DECIMAL_SCALE) / (int_blks * blk_size) - (leftpt * PERCENT_SCALE_FACTOR);
|
|
*/
|
|
|
|
#define QWPERCENTCALC(lpt, rpt, qwint_size, int_blks, blk_size) \
|
|
{ \
|
|
qw_num tmp; \
|
|
size_t rem; \
|
|
\
|
|
if (int_blks) \
|
|
{ \
|
|
QWMULBYDW(tmp, (qwint_size), PERCENT_DECIMAL_SCALE); \
|
|
QWDIVIDEBYDW(tmp, (int_blks), tmp, rem); \
|
|
QWDIVIDEBYDW(tmp, (blk_size), tmp, rem); \
|
|
QWDIVIDEBYDW(tmp, PERCENT_SCALE_FACTOR, tmp, rpt); \
|
|
DWASSIGNQW((lpt), tmp); \
|
|
} else \
|
|
{ \
|
|
(lpt) = 0; \
|
|
(rpt) = 0; \
|
|
} \
|
|
}
|
|
|
|
GBLDEF unsigned char mu_int_root_level;
|
|
GBLDEF int4 mu_int_adj[MAX_BT_DEPTH + 1];
|
|
GBLDEF uint4 mu_int_errknt;
|
|
GBLDEF uint4 mu_int_skipreg_cnt=0;
|
|
GBLDEF uint4 mu_int_blks[MAX_BT_DEPTH + 1];
|
|
GBLDEF uint4 mu_int_offset[MAX_BT_DEPTH + 1];
|
|
GBLDEF uint4 mu_int_recs[MAX_BT_DEPTH + 1];
|
|
GBLDEF qw_num mu_int_size[MAX_BT_DEPTH + 1];
|
|
GBLDEF int disp_map_errors;
|
|
GBLDEF int disp_maxkey_errors;
|
|
GBLDEF int disp_trans_errors;
|
|
GBLDEF int maxkey_errors = 0;
|
|
GBLDEF int muint_adj;
|
|
GBLDEF int mu_int_plen;
|
|
GBLDEF int mu_map_errs;
|
|
GBLDEF int trans_errors = 0;
|
|
GBLDEF boolean_t block = FALSE;
|
|
GBLDEF boolean_t muint_fast = FALSE;
|
|
GBLDEF boolean_t master_dir;
|
|
GBLDEF boolean_t muint_key = FALSE;
|
|
GBLDEF boolean_t muint_subsc = FALSE;
|
|
GBLDEF boolean_t mu_int_err_ranges;
|
|
GBLDEF boolean_t tn_reset_specified; /* use this to avoid recomputing cli_present("TN_RESET") in the loop */
|
|
GBLDEF boolean_t tn_reset_this_reg;
|
|
GBLDEF block_id mu_int_adj_prev[MAX_BT_DEPTH + 1];
|
|
GBLDEF block_id mu_int_path[MAX_BT_DEPTH + 1];
|
|
GBLDEF global_list *trees_tail;
|
|
GBLDEF global_list *trees;
|
|
GBLDEF sgmnt_data mu_int_data;
|
|
GBLDEF unsigned char *mu_int_master;
|
|
GBLDEF trans_num largest_tn;
|
|
GBLDEF int4 mu_int_blks_to_upgrd;
|
|
GBLDEF span_node_integ *sndata;
|
|
/* The following global variable is used to store the encryption information for the current database. The
|
|
* variable is initialized in mu_int_init(mupip integ -file <file.dat>) and mu_int_reg(mupip integ -reg <reg_name>). */
|
|
GTMCRYPT_ONLY(
|
|
GBLDEF gtmcrypt_key_t mu_int_encrypt_key_handle;
|
|
)
|
|
GBLREF bool mu_ctrly_occurred;
|
|
GBLREF bool mu_ctrlc_occurred;
|
|
GBLREF bool error_mupip;
|
|
GBLREF short crash_count;
|
|
GBLREF gd_region *gv_cur_region;
|
|
GBLREF gv_namehead *gv_target;
|
|
GBLREF gv_key *gv_altkey;
|
|
GBLREF gv_key *gv_currkey;
|
|
GBLREF sgmnt_addrs *cs_addrs;
|
|
GBLREF tp_region *grlist;
|
|
GBLREF bool region;
|
|
GBLREF boolean_t debug_mupip;
|
|
GBLDEF boolean_t ointeg_this_reg;
|
|
GTM_SNAPSHOT_ONLY(
|
|
GBLDEF util_snapshot_ptr_t util_ss_ptr;
|
|
GBLDEF boolean_t preserve_snapshot;
|
|
GBLDEF boolean_t online_specified;
|
|
)
|
|
|
|
error_def(ERR_CTRLC);
|
|
error_def(ERR_CTRLY);
|
|
error_def(ERR_DBBTUFIXED);
|
|
error_def(ERR_DBBTUWRNG);
|
|
error_def(ERR_DBNOREGION);
|
|
error_def(ERR_DBRBNLBMN);
|
|
error_def(ERR_DBRBNNEG);
|
|
error_def(ERR_DBRBNTOOLRG);
|
|
error_def(ERR_DBRDONLY);
|
|
error_def(ERR_DBTNLTCTN);
|
|
error_def(ERR_DBTNRESETINC);
|
|
error_def(ERR_DBTNRESET);
|
|
error_def(ERR_INTEGERRS);
|
|
error_def(ERR_MUNOACTION);
|
|
error_def(ERR_MUNOFINISH);
|
|
error_def(ERR_MUNOTALLINTEG);
|
|
error_def(ERR_MUPCLIERR);
|
|
error_def(ERR_DBSPANGLOINCMP);
|
|
error_def(ERR_DBSPANCHUNKORD);
|
|
|
|
void mupip_integ(void)
|
|
{
|
|
boolean_t full, muint_all_index_blocks;
|
|
boolean_t update_filehdr, update_header_tn;
|
|
char *temp, util_buff[MAX_UTIL_LEN];
|
|
unsigned char dummy;
|
|
unsigned char key_buff[2048];
|
|
short iosb[4];
|
|
unsigned short keylen;
|
|
unsigned int blocks_free = LEAVE_BLOCKS_ALONE;
|
|
int idx, leftpt, rightpt, total_errors, util_len;
|
|
uint4 cli_status;
|
|
block_id dir_root, mu_index_adj, mu_data_adj, muint_block;
|
|
uint4 prev_errknt, mu_dir_blks, mu_dir_recs, mu_data_blks, mu_data_recs, mu_index_blks, mu_index_recs;
|
|
qw_num mu_dir_size, mu_index_size, mu_data_size;
|
|
tp_region *rptr;
|
|
file_control *fc;
|
|
boolean_t retvalue_mu_int_reg, online_integ = FALSE, region_was_frozen;
|
|
GTM_SNAPSHOT_ONLY(
|
|
char ss_filename[GTM_PATH_MAX];
|
|
unsigned short ss_file_len = GTM_PATH_MAX;
|
|
)
|
|
sgmnt_data_ptr_t csd;
|
|
span_node_integ span_node_data;
|
|
|
|
sndata = &span_node_data;
|
|
sndata->sn_cnt = 0;
|
|
sndata->sn_blk_cnt = 0;
|
|
sndata->sn_type = SN_NOT;
|
|
error_mupip = FALSE;
|
|
if (NULL == gv_target)
|
|
gv_target = (gv_namehead *)targ_alloc(DUMMY_GLOBAL_VARIABLE_LEN, NULL, NULL);
|
|
if (CLI_PRESENT == (cli_status = cli_present("MAXKEYSIZE")))
|
|
{
|
|
assert(SIZEOF(disp_maxkey_errors) == SIZEOF(int4));
|
|
if (0 == cli_get_int("MAXKEYSIZE", (int4 *)&disp_maxkey_errors))
|
|
mupip_exit(ERR_MUPCLIERR);
|
|
if (disp_maxkey_errors < 1)
|
|
disp_maxkey_errors = 1;
|
|
} else if (CLI_NEGATED == cli_status)
|
|
disp_maxkey_errors = APPROX_ALL_ERRORS;
|
|
else
|
|
disp_maxkey_errors = DEFAULT_ERR_LIMIT;
|
|
if (CLI_PRESENT == (cli_status = cli_present("TRANSACTION")))
|
|
{
|
|
assert(SIZEOF(disp_trans_errors) == SIZEOF(int4));
|
|
if (0 == cli_get_int("TRANSACTION", (int4 *)&disp_trans_errors))
|
|
mupip_exit(ERR_MUPCLIERR);
|
|
if (disp_trans_errors < 1)
|
|
disp_trans_errors = 1;
|
|
} else if (CLI_NEGATED == cli_status)
|
|
disp_trans_errors = APPROX_ALL_ERRORS;
|
|
else
|
|
disp_trans_errors = DEFAULT_ERR_LIMIT;
|
|
if (CLI_PRESENT == (cli_status = cli_present("MAP")))
|
|
{
|
|
assert(SIZEOF(disp_map_errors) == SIZEOF(int4));
|
|
if (0 == cli_get_int("MAP", (int4 *)&disp_map_errors))
|
|
mupip_exit(ERR_MUPCLIERR);
|
|
if (disp_map_errors < 1)
|
|
disp_map_errors = 1;
|
|
} else if (CLI_NEGATED == cli_status)
|
|
disp_map_errors = APPROX_ALL_ERRORS;
|
|
else
|
|
disp_map_errors = DEFAULT_ERR_LIMIT;
|
|
if (CLI_PRESENT == cli_present("ADJACENCY"))
|
|
{
|
|
assert(SIZEOF(muint_adj) == SIZEOF(int4));
|
|
if (0 == cli_get_int("ADJACENCY", (int4 *)&muint_adj))
|
|
mupip_exit(ERR_MUPCLIERR);
|
|
} else
|
|
muint_adj = DEFAULT_ADJACENCY;
|
|
if (CLI_PRESENT == cli_present("BRIEF"))
|
|
full = FALSE;
|
|
else if (CLI_PRESENT == cli_present("FULL"))
|
|
full = TRUE;
|
|
else
|
|
full = FALSE;
|
|
if (CLI_PRESENT == cli_present("FAST"))
|
|
muint_fast = TRUE;
|
|
else
|
|
muint_fast = FALSE;
|
|
|
|
/* DBG qualifier prints extra debug messages while waiting for KIP in region freeze */
|
|
debug_mupip = (CLI_PRESENT == cli_present("DBG"));
|
|
GTM_SNAPSHOT_ONLY(online_specified = (CLI_PRESENT == cli_present("ONLINE"));)
|
|
# ifdef GTM_SNAPSHOT
|
|
if (online_specified)
|
|
{ /* if MUPIP INTEG -ONLINE -ANALYZE=<filename> is given then display details about the snapshot file
|
|
* and do early return
|
|
*/
|
|
if (cli_get_str("ANALYZE", ss_filename, &ss_file_len))
|
|
{
|
|
ss_anal_shdw_file(ss_filename, ss_file_len);
|
|
return;
|
|
}
|
|
}
|
|
# endif
|
|
if ((CLI_PRESENT == cli_present("REGION")) GTM_SNAPSHOT_ONLY(|| online_specified))
|
|
{
|
|
gvinit(); /* side effect: initializes gv_altkey (used by code below) & gv_currkey (not used by below code) */
|
|
region = TRUE;
|
|
mu_getlst("WHAT", SIZEOF(tp_region));
|
|
if (!grlist)
|
|
{
|
|
error_mupip = TRUE;
|
|
gtm_putmsg(VARLSTCNT(1) ERR_DBNOREGION);
|
|
mupip_exit(ERR_MUNOACTION);
|
|
}
|
|
rptr = grlist;
|
|
} else
|
|
GVKEY_INIT(gv_altkey, DBKEYSIZE(MAX_KEY_SZ)); /* used by code below */
|
|
GTM_SNAPSHOT_ONLY(online_integ = ((TRUE != cli_negated("ONLINE")) && region)); /* Default option for INTEG is -ONLINE */
|
|
GTM_SNAPSHOT_ONLY(preserve_snapshot = (CLI_PRESENT == cli_present("PRESERVE"))); /* Should snapshot file be preserved ? */
|
|
GTM_SNAPSHOT_ONLY(assert(!online_integ || (region && !tn_reset_specified)));
|
|
if (CLI_PRESENT == cli_present("SUBSCRIPT"))
|
|
{
|
|
keylen = SIZEOF(key_buff);
|
|
if (0 == cli_get_str("SUBSCRIPT", (char *)key_buff, &keylen))
|
|
mupip_exit(ERR_MUPCLIERR);
|
|
if (FALSE == mu_int_getkey(key_buff, keylen))
|
|
mupip_exit(ERR_MUPCLIERR);
|
|
assert(muint_key); /* or else "mu_int_getkey" call above would have returned FALSE */
|
|
disp_map_errors = 0;
|
|
}
|
|
if (CLI_PRESENT == cli_present("BLOCK"))
|
|
{
|
|
if (0 == cli_get_hex("BLOCK", (uint4 *)&muint_block))
|
|
mupip_exit(SS_NORMAL);
|
|
block = TRUE;
|
|
disp_map_errors = 0;
|
|
master_dir = FALSE;
|
|
}
|
|
muint_all_index_blocks = !(block || muint_key);
|
|
mu_int_master = malloc(MASTER_MAP_SIZE_MAX);
|
|
tn_reset_specified = (CLI_PRESENT == cli_present("TN_RESET"));
|
|
mu_outofband_setup();
|
|
UNIX_ONLY(ESTABLISH(mu_int_ch);)
|
|
if (region)
|
|
{
|
|
if (online_integ)
|
|
{
|
|
# ifdef GTM_SNAPSHOT
|
|
/* The below structure members will be assigned in ss_initiate done in mu_int_reg.
|
|
* No free required as will be gone when process dies
|
|
*/
|
|
util_ss_ptr = malloc(SIZEOF(util_snapshot_t));
|
|
util_ss_ptr->header = &mu_int_data;
|
|
util_ss_ptr->master_map = mu_int_master;
|
|
util_ss_ptr->native_size = 0;
|
|
# endif
|
|
}
|
|
else /* Establish the condition handler ONLY if ONLINE INTEG was not requested */
|
|
ESTABLISH(mu_freeze_ch);
|
|
}
|
|
for (total_errors = mu_int_errknt = 0; ; total_errors += mu_int_errknt, mu_int_errknt = 0)
|
|
{
|
|
if (mu_ctrly_occurred || mu_ctrlc_occurred)
|
|
break;
|
|
if (region)
|
|
{
|
|
assert(NULL != rptr);
|
|
if (!mupfndfil(rptr->reg, NULL))
|
|
{
|
|
mu_int_skipreg_cnt++;
|
|
rptr = rptr->fPtr;
|
|
if (NULL == rptr)
|
|
break;
|
|
continue;
|
|
}
|
|
}
|
|
QWASSIGNDW(mu_dir_size, 0);
|
|
QWASSIGNDW(mu_index_size, 0);
|
|
QWASSIGNDW(mu_data_size, 0);
|
|
mu_index_adj = mu_data_adj = 0;
|
|
mu_dir_blks = mu_dir_recs = 0;
|
|
mu_data_blks = mu_data_recs = 0;
|
|
mu_index_blks = mu_index_recs = 0;
|
|
mu_int_err_ranges = (CLI_NEGATED != cli_present("KEYRANGES"));
|
|
mu_int_root_level = (unsigned char)-1;
|
|
mu_map_errs = 0, prev_errknt = 0, largest_tn = 0;
|
|
mu_int_blks_to_upgrd = 0;
|
|
for (idx = 0; idx <= MAX_BT_DEPTH; idx++)
|
|
{
|
|
QWASSIGNDW(mu_int_size[idx], 0);
|
|
mu_int_blks[idx] = mu_int_recs[idx] = 0;
|
|
}
|
|
mu_int_path[0] = 0;
|
|
mu_int_offset[0] = 0;
|
|
mu_int_plen = 1;
|
|
memset(mu_int_adj, 0, SIZEOF(mu_int_adj));
|
|
if (region)
|
|
{
|
|
util_out_print("!/!/Integ of region !AD", TRUE, REG_LEN_STR(rptr->reg));
|
|
ointeg_this_reg = online_integ;
|
|
mu_int_reg(rptr->reg, &retvalue_mu_int_reg);
|
|
region_was_frozen = !ointeg_this_reg;
|
|
if (TRUE != retvalue_mu_int_reg)
|
|
{
|
|
rptr = rptr->fPtr;
|
|
if (NULL == rptr)
|
|
break;
|
|
continue;
|
|
}
|
|
/* If the region was frozen (INTEG -REG -NOONLINE) then use cs_addrs->hdr for verification of
|
|
* blks_to_upgrd, free blocks calculation. Otherwise (ONLINE INTEG) then use mu_int_data for
|
|
* the verification.
|
|
*/
|
|
if (region_was_frozen)
|
|
csd = cs_addrs->hdr;
|
|
else
|
|
csd = &mu_int_data;
|
|
} else
|
|
{
|
|
region_was_frozen = FALSE; /* For INTEG -FILE, region is not frozen as we would have standalone access */
|
|
if (FALSE == mu_int_init())
|
|
mupip_exit(ERR_INTEGERRS);
|
|
/* Since we have standalone access, there is no need for cs_addrs->hdr. So, use mu_int_data for
|
|
* verifications
|
|
*/
|
|
csd = &mu_int_data;
|
|
}
|
|
trees_tail = trees = (global_list *)malloc(SIZEOF(global_list));
|
|
memset(trees, 0, SIZEOF(global_list));
|
|
trees->root = dir_root = get_dir_root();
|
|
master_dir = TRUE;
|
|
trees_tail->nct = 0;
|
|
trees_tail->act = 0;
|
|
trees_tail->ver = 0;
|
|
tn_reset_this_reg = update_header_tn = FALSE;
|
|
if (tn_reset_specified)
|
|
{
|
|
if (gv_cur_region->read_only)
|
|
{
|
|
gtm_putmsg(VARLSTCNT(4) ERR_DBRDONLY, 2, gv_cur_region->dyn.addr->fname_len,
|
|
gv_cur_region->dyn.addr->fname);
|
|
mu_int_errknt++;
|
|
mu_int_err(ERR_DBTNRESET, 0, 0, 0, 0, 0, 0, 0);
|
|
mu_int_errknt-=2;
|
|
/* is this error supposed to update error count, or leave it ( then mu_int_errknt-- instead)*/
|
|
mu_int_plen++; /* continuing, so compensate for mu_int_err decrement */
|
|
} else
|
|
tn_reset_this_reg = update_header_tn = TRUE;
|
|
}
|
|
if (block)
|
|
{
|
|
master_dir = FALSE;
|
|
trees->root = muint_block;
|
|
}
|
|
for (trees->link = 0; ; master_dir = FALSE, temp = (char*)trees, trees = trees->link, free(temp))
|
|
{
|
|
if (mu_ctrly_occurred || mu_ctrlc_occurred)
|
|
{
|
|
if (region_was_frozen)
|
|
{
|
|
region_freeze(rptr->reg, FALSE, FALSE, FALSE);
|
|
if (!rptr->reg->read_only)
|
|
{
|
|
fc = gv_cur_region->dyn.addr->file_cntl;
|
|
fc->op = FC_WRITE;
|
|
fc->op_buff = (unsigned char *)FILE_INFO(rptr->reg)->s_addrs.hdr;
|
|
fc->op_len = ROUND_UP(SIZEOF(sgmnt_data), DISK_BLOCK_SIZE);
|
|
fc->op_pos = 1;
|
|
dbfilop(fc);
|
|
}
|
|
}
|
|
gtm_putmsg(VARLSTCNT(1) mu_ctrly_occurred ? ERR_CTRLY : ERR_CTRLC);
|
|
mupip_exit(ERR_MUNOFINISH);
|
|
}
|
|
if (!trees)
|
|
break;
|
|
mu_int_path[0] = trees->root;
|
|
if (trees->root < 0)
|
|
{
|
|
mu_int_err(ERR_DBRBNNEG, 0, 0, 0, 0, 0, 0, mu_int_root_level);
|
|
continue;
|
|
}
|
|
if (trees->root >= mu_int_data.trans_hist.total_blks)
|
|
{
|
|
mu_int_err(ERR_DBRBNTOOLRG, 0, 0, 0, 0, 0, 0,
|
|
mu_int_root_level);
|
|
continue;
|
|
}
|
|
if (0 == (trees->root % mu_int_data.bplmap))
|
|
{
|
|
mu_int_err(ERR_DBRBNLBMN, 0, 0, 0, 0, 0, 0, mu_int_root_level);
|
|
continue;
|
|
}
|
|
mu_int_plen = 0;
|
|
memset(mu_int_adj_prev, 0, SIZEOF(mu_int_adj_prev));
|
|
gv_target->nct = trees->nct;
|
|
gv_target->act = trees->act;
|
|
gv_target->ver = trees->ver;
|
|
gv_altkey->prev = 0;
|
|
assert(trees->keysize == strlen(trees->key));
|
|
gv_altkey->end = trees->keysize;
|
|
assert(gv_altkey->end + 2 <= gv_altkey->top);
|
|
memcpy(gv_altkey->base, trees->key, gv_altkey->end);
|
|
gv_altkey->base[gv_altkey->end++] = '\0';
|
|
gv_altkey->base[gv_altkey->end] = '\0';
|
|
if (gv_target->act)
|
|
act_in_gvt();
|
|
if (mu_int_blk(trees->root, MAX_BT_DEPTH, TRUE, gv_altkey->base, gv_altkey->end, &dummy, 0, 0))
|
|
{
|
|
/* We are done with the INTEG CHECK for the current GVT, but if the spanning node INTEG
|
|
* check is not finished, either of the following two are occurred.
|
|
*/
|
|
if (SPAN_NODE == sndata->sn_type)
|
|
{ /* ERROR 1: There is discontinuity in the spanning node blocks;
|
|
* adjacent spanning block is missing.
|
|
*/
|
|
mu_int_plen = mu_int_root_level + 1;
|
|
mu_int_err(ERR_DBSPANGLOINCMP, TRUE, FALSE, sndata->span_node_buf, sndata->key_len,
|
|
&dummy, 0, 0);
|
|
sndata->sn_blk_cnt += sndata->span_blk_cnt;
|
|
mu_int_plen = 0;
|
|
sndata->sn_type = SN_NOT;
|
|
}
|
|
if (2 == sndata->sn_type)
|
|
{ /* ERROR 2: Spanning-node-block occurred in the middle of non-spanning block */
|
|
mu_int_plen = mu_int_root_level + 1;
|
|
mu_int_err(ERR_DBSPANCHUNKORD, TRUE, FALSE, sndata->span_node_buf, sndata->key_len,
|
|
&dummy, 0, 0);
|
|
sndata->sn_blk_cnt += sndata->span_blk_cnt;
|
|
mu_int_plen = 0;
|
|
mu_int_plen = 0;
|
|
sndata->sn_type = SN_NOT;
|
|
}
|
|
if (full)
|
|
{
|
|
if (trees->root == dir_root)
|
|
util_out_print("!/Directory tree", TRUE);
|
|
else
|
|
util_out_print("!/Global variable ^!AD", TRUE, LEN_AND_STR(trees->key));
|
|
if (mu_int_errknt > prev_errknt)
|
|
{
|
|
if (trees->root == dir_root)
|
|
util_out_print("Total error count for directory tree: !UL",
|
|
TRUE, mu_int_errknt - prev_errknt);
|
|
else
|
|
util_out_print("Total error count for global !AD: !UL.",
|
|
TRUE, LEN_AND_STR(trees->key), mu_int_errknt - prev_errknt);
|
|
prev_errknt = mu_int_errknt;
|
|
}
|
|
util_out_print("Level Blocks Records % Used Adjacent", TRUE);
|
|
for (idx = mu_int_root_level; idx >= 0; idx--)
|
|
{
|
|
if ((0 == idx) && muint_fast && (trees->root != dir_root))
|
|
util_out_print("!5UL !12UL NA NA NA", TRUE,
|
|
idx, mu_int_blks[idx]);
|
|
else
|
|
{
|
|
QWPERCENTCALC(leftpt, rightpt, mu_int_size[idx], mu_int_blks[idx],
|
|
mu_int_data.blk_size);
|
|
if (trees->root != dir_root)
|
|
{
|
|
util_out_print("!5UL !12UL !12UL !8UL.!3ZL !12UL",
|
|
TRUE, idx, mu_int_blks[idx], mu_int_recs[idx],
|
|
leftpt, rightpt, mu_int_adj[idx]);
|
|
} else
|
|
util_out_print("!5UL !12UL !12UL !8UL.!3ZL NA",
|
|
TRUE, idx, mu_int_blks[idx], mu_int_recs[idx],
|
|
leftpt, rightpt);
|
|
}
|
|
}
|
|
}
|
|
if (dir_root == trees->root)
|
|
{
|
|
for (idx = mu_int_root_level; idx >= 0; idx--)
|
|
{
|
|
mu_dir_blks += mu_int_blks[idx];
|
|
QWINCRBY(mu_dir_size, mu_int_size[idx]);
|
|
mu_dir_recs += mu_int_recs[idx];
|
|
QWASSIGNDW(mu_int_size[idx], 0);
|
|
mu_int_adj[0] = mu_int_blks[idx] = mu_int_recs[idx] = 0;
|
|
}
|
|
} else
|
|
{
|
|
for (idx = mu_int_root_level; idx > 0; idx--)
|
|
{
|
|
mu_index_blks += mu_int_blks[idx];
|
|
QWINCRBY(mu_index_size, mu_int_size[idx]);
|
|
mu_index_recs += mu_int_recs[idx];
|
|
mu_index_adj += mu_int_adj[idx];
|
|
QWASSIGNDW(mu_int_size[idx], 0);
|
|
mu_int_adj[idx] = mu_int_blks[idx] = mu_int_recs[idx] = 0;
|
|
}
|
|
mu_data_blks += mu_int_blks[0];
|
|
mu_data_adj += mu_int_adj[0];
|
|
QWINCRBY(mu_data_size, mu_int_size[0]);
|
|
mu_data_recs += mu_int_recs[0];
|
|
QWASSIGNDW(mu_int_size[0], 0);
|
|
mu_int_adj[0] = mu_int_blks[0] = mu_int_recs[0] = 0;
|
|
}
|
|
} else if (update_header_tn)
|
|
{
|
|
update_header_tn = FALSE;
|
|
mu_int_err(ERR_DBTNRESETINC, 0, 0, 0, 0, 0, 0, 0);
|
|
mu_int_plen++; /* continuing, so compensate for mu_int_err decrement */
|
|
mu_int_errknt--; /* if this error is not supposed to increment the error count */
|
|
}
|
|
}
|
|
if (muint_all_index_blocks)
|
|
{
|
|
mu_int_maps();
|
|
if (! mu_int_errknt)
|
|
{
|
|
blocks_free = mu_int_data.trans_hist.total_blks -
|
|
(mu_int_data.trans_hist.total_blks + mu_int_data.bplmap - 1) / mu_int_data.bplmap -
|
|
mu_data_blks - mu_index_blks - mu_dir_blks;
|
|
/* If ONLINE INTEG, then cs_addrs->hdr->trans_hist.free_blocks can no longer be expected to remain
|
|
* the same as it was during the time INTEG started as updates are allowed when ONLINE INTEG is
|
|
* in progress and hence use mu_int_data.trans_hist.free_blocks as it is the copy of the file header
|
|
* right when ONLINE INTEG starts.
|
|
*/
|
|
if (csd->trans_hist.free_blocks != blocks_free)
|
|
{
|
|
if (gv_cur_region->read_only)
|
|
mu_int_errknt++;
|
|
util_len = SIZEOF("!/Free blocks counter in file header: ") - 1;
|
|
memcpy(util_buff, "!/Free blocks counter in file header: ", util_len);
|
|
util_len += i2hex_nofill(csd->trans_hist.free_blocks, (uchar_ptr_t)&util_buff[util_len], 8);
|
|
MEMCPY_LIT(&util_buff[util_len], TEXT1);
|
|
util_len += SIZEOF(TEXT1) - 1;
|
|
util_len += i2hex_nofill(blocks_free, (uchar_ptr_t)&util_buff[util_len], 8);
|
|
util_buff[util_len] = 0;
|
|
util_out_print(util_buff, TRUE);
|
|
} else
|
|
blocks_free = LEAVE_BLOCKS_ALONE;
|
|
}
|
|
if (!muint_fast && (mu_int_blks_to_upgrd != csd->blks_to_upgrd))
|
|
{
|
|
gtm_putmsg(VARLSTCNT(4) ERR_DBBTUWRNG, 2, mu_int_blks_to_upgrd, csd->blks_to_upgrd);
|
|
if (gv_cur_region->read_only || mu_int_errknt)
|
|
mu_int_errknt++;
|
|
else
|
|
gtm_putmsg(VARLSTCNT(1) ERR_DBBTUFIXED);
|
|
}
|
|
if (((0 != mu_int_data.kill_in_prog) || (0 != mu_int_data.abandoned_kills)) && (!mu_map_errs) && !region
|
|
&& !gv_cur_region->read_only)
|
|
{
|
|
assert(mu_int_errknt > 0);
|
|
mu_int_errknt--;
|
|
}
|
|
}
|
|
if (muint_fast)
|
|
{
|
|
if (mu_int_errknt)
|
|
util_out_print("!/Total error count from fast integ: !UL.", TRUE, mu_int_errknt);
|
|
else
|
|
util_out_print("!/No errors detected by fast integ.", TRUE);
|
|
} else
|
|
{
|
|
if (mu_int_errknt)
|
|
util_out_print("!/Total error count from integ: !UL.", TRUE, mu_int_errknt);
|
|
else
|
|
util_out_print("!/No errors detected by integ.", TRUE);
|
|
}
|
|
util_out_print("!/Type Blocks Records % Used Adjacent!/", TRUE);
|
|
QWPERCENTCALC(leftpt, rightpt, mu_dir_size, mu_dir_blks, mu_int_data.blk_size);
|
|
util_out_print("Directory !8UL !12UL !8UL.!3ZL NA", TRUE, mu_dir_blks, mu_dir_recs,
|
|
leftpt, rightpt);
|
|
QWPERCENTCALC(leftpt, rightpt, mu_index_size, mu_index_blks, mu_int_data.blk_size);
|
|
util_out_print("Index !12UL !12UL !8UL.!3ZL !12UL", TRUE, mu_index_blks, mu_index_recs, leftpt, rightpt,
|
|
mu_index_adj);
|
|
if (muint_fast)
|
|
util_out_print("Data !12UL NA NA NA", TRUE, mu_data_blks);
|
|
else
|
|
{
|
|
QWPERCENTCALC(leftpt, rightpt, mu_data_size, mu_data_blks, mu_int_data.blk_size);
|
|
util_out_print("Data !12UL !12UL !8UL.!3ZL !12UL", TRUE, mu_data_blks, mu_data_recs,
|
|
leftpt, rightpt, mu_data_adj);
|
|
}
|
|
if ((FALSE == block) && (FALSE == muint_key))
|
|
util_out_print("Free !12UL NA NA NA", TRUE,
|
|
mu_int_data.trans_hist.total_blks -
|
|
(mu_int_data.trans_hist.total_blks + mu_int_data.bplmap - 1) / mu_int_data.bplmap -
|
|
mu_data_blks - mu_index_blks - mu_dir_blks);
|
|
if (muint_fast)
|
|
{
|
|
util_out_print("Total !12UL NA NA !12UL", TRUE,
|
|
mu_int_data.trans_hist.total_blks -
|
|
(mu_int_data.trans_hist.total_blks + mu_int_data.bplmap - 1) / mu_int_data.bplmap,
|
|
mu_data_adj + mu_index_adj);
|
|
} else
|
|
{
|
|
util_out_print("Total !12UL !12UL NA !12UL", TRUE,
|
|
mu_int_data.trans_hist.total_blks -
|
|
(mu_int_data.trans_hist.total_blks + mu_int_data.bplmap - 1) / mu_int_data.bplmap,
|
|
mu_dir_recs + mu_index_recs + mu_data_recs, mu_data_adj + mu_index_adj);
|
|
}
|
|
if(sndata->sn_cnt)
|
|
{
|
|
util_out_print("[Spanning Nodes:!UL ; Blocks:!UL]", TRUE, sndata->sn_cnt, sndata->sn_blk_cnt);
|
|
/*[span_node:<no of span-node in DB>; blks: <total number of spanning blocks used by all span-node>]*/
|
|
}
|
|
if (largest_tn)
|
|
{
|
|
mu_int_err(ERR_DBTNLTCTN, 0, 0, 0, 0, 0, 0, 0);
|
|
mu_int_plen--;
|
|
mu_int_errknt--;
|
|
if (trans_errors > disp_trans_errors)
|
|
{
|
|
util_out_print("Maximum number of transaction number errors to display: !UL, was exceeded",
|
|
TRUE, disp_trans_errors);
|
|
util_out_print("!UL transaction number errors encountered.", TRUE, trans_errors);
|
|
}
|
|
MEMCPY_LIT(util_buff, TEXT2);
|
|
util_len = SIZEOF(TEXT2) - 1;
|
|
util_len += i2hexl_nofill(largest_tn, (uchar_ptr_t)&util_buff[util_len], 16);
|
|
util_buff[util_len] = 0;
|
|
util_out_print(util_buff, TRUE);
|
|
MEMCPY_LIT(util_buff, TEXT3);
|
|
util_len = SIZEOF(TEXT3) - 1;
|
|
util_len += i2hexl_nofill(mu_int_data.trans_hist.curr_tn, (uchar_ptr_t)&util_buff[util_len], 16);
|
|
util_buff[util_len] = 0;
|
|
util_out_print(util_buff, TRUE);
|
|
}
|
|
if (maxkey_errors > disp_maxkey_errors)
|
|
{
|
|
util_out_print("Maximum number of keys too large errors to display: !UL, was exceeded",
|
|
TRUE, disp_maxkey_errors);
|
|
util_out_print("!UL keys too large errors encountered.", TRUE, maxkey_errors);
|
|
}
|
|
if (region)
|
|
{
|
|
/* Below logic updates the database file header in the shared memory with values calculated
|
|
* by INTEG during it's course of tree traversal and writes it to disk. If ONLINE INTEG is
|
|
* in progress, then these values could legally be out-of-date and hence avoid writing the header if
|
|
* ONLINE INTEG is in progress.
|
|
*/
|
|
if (!gv_cur_region->read_only && !ointeg_this_reg)
|
|
{
|
|
if (LEAVE_BLOCKS_ALONE != blocks_free)
|
|
csd->trans_hist.free_blocks = blocks_free;
|
|
if (!mu_int_errknt && muint_all_index_blocks && !muint_fast)
|
|
{
|
|
if (mu_int_blks_to_upgrd != csd->blks_to_upgrd)
|
|
csd->blks_to_upgrd = mu_int_blks_to_upgrd;
|
|
}
|
|
csd->span_node_absent = (sndata->sn_cnt) ? FALSE : TRUE;
|
|
csd->maxkeysz_assured = (maxkey_errors) ? FALSE : TRUE;
|
|
region_freeze(gv_cur_region, FALSE, FALSE, FALSE);
|
|
fc = gv_cur_region->dyn.addr->file_cntl;
|
|
fc->op = FC_WRITE;
|
|
fc->op_buff = (unsigned char *)FILE_INFO(gv_cur_region)->s_addrs.hdr;
|
|
fc->op_len = ROUND_UP(SIZEOF(sgmnt_data), DISK_BLOCK_SIZE);
|
|
fc->op_pos = 1;
|
|
dbfilop(fc);
|
|
}
|
|
else if (region_was_frozen)
|
|
{
|
|
/* If online_integ, then database is not frozen, so no need to unfreeze. */
|
|
region_freeze(gv_cur_region, FALSE, FALSE, FALSE);
|
|
}
|
|
# ifdef GTM_SNAPSHOT
|
|
else
|
|
{
|
|
assert(SNAPSHOTS_IN_PROG(cs_addrs));
|
|
assert(NULL != cs_addrs->ss_ctx);
|
|
ss_release(&cs_addrs->ss_ctx);
|
|
CLEAR_SNAPSHOTS_IN_PROG(cs_addrs);
|
|
}
|
|
# endif
|
|
rptr = rptr->fPtr;
|
|
if (NULL == rptr)
|
|
break;
|
|
} else if (!gv_cur_region->read_only)
|
|
{
|
|
assert(!online_integ);
|
|
update_filehdr = FALSE;
|
|
if (muint_all_index_blocks)
|
|
{
|
|
if ((0 == mu_map_errs) && ((0 != mu_int_data.kill_in_prog) || (0 != mu_int_data.abandoned_kills)))
|
|
{
|
|
mu_int_data.abandoned_kills = 0;
|
|
mu_int_data.kill_in_prog = 0;
|
|
update_filehdr = TRUE;
|
|
}
|
|
if ((LEAVE_BLOCKS_ALONE != blocks_free) && (mu_int_data.trans_hist.free_blocks != blocks_free))
|
|
{
|
|
mu_int_data.trans_hist.free_blocks = blocks_free;
|
|
update_filehdr = TRUE;
|
|
}
|
|
if (!mu_int_errknt && !muint_fast)
|
|
{
|
|
if (mu_int_blks_to_upgrd != mu_int_data.blks_to_upgrd)
|
|
{
|
|
mu_int_data.blks_to_upgrd = mu_int_blks_to_upgrd;
|
|
update_filehdr = TRUE;
|
|
}
|
|
}
|
|
}
|
|
if (update_header_tn)
|
|
{
|
|
mu_int_data.trans_hist.early_tn = 2;
|
|
mu_int_data.trans_hist.curr_tn = 1;
|
|
/* curr_tn = 1 + 1 is done (instead of = 2) so as to use INCREMENT_CURR_TN macro.
|
|
* this way all places that update db curr_tn are easily obtained by searching for the macro.
|
|
* Reason for setting the transaction number to 2 (instead of 1) is so as to let a BACKUP in
|
|
* all forms to proceed, which earlier used to error out on seeing the database transaction
|
|
* number as 1.
|
|
*/
|
|
INCREMENT_CURR_TN(&mu_int_data);
|
|
/* Reset all last backup transaction numbers to 1. */
|
|
mu_int_data.last_inc_backup = 1;
|
|
mu_int_data.last_com_backup = 1;
|
|
mu_int_data.last_rec_backup = 1;
|
|
mu_int_data.last_inc_bkup_last_blk = 0;
|
|
mu_int_data.last_com_bkup_last_blk = 0;
|
|
mu_int_data.last_rec_bkup_last_blk = 0;
|
|
update_filehdr = TRUE;
|
|
util_out_print(MSG1, TRUE);
|
|
}
|
|
if (FALSE != update_filehdr)
|
|
{
|
|
fc = gv_cur_region->dyn.addr->file_cntl;
|
|
fc->op = FC_WRITE;
|
|
fc->op_buff = (unsigned char *)&mu_int_data;
|
|
fc->op_len = ROUND_UP(SIZEOF(sgmnt_data), DISK_BLOCK_SIZE);
|
|
fc->op_pos = 1;
|
|
dbfilop(fc);
|
|
fc->op = FC_CLOSE;
|
|
dbfilop(fc);
|
|
}
|
|
break;
|
|
} else
|
|
break;
|
|
}
|
|
# ifdef UNIX
|
|
if (!region)
|
|
{
|
|
db_ipcs_reset(gv_cur_region);
|
|
mu_gv_cur_reg_free(); /* mu_gv_cur_reg_init done in mu_int_init() */
|
|
REVERT;
|
|
}
|
|
# endif
|
|
total_errors += mu_int_errknt;
|
|
if (error_mupip)
|
|
total_errors++;
|
|
if (mu_ctrly_occurred || mu_ctrlc_occurred)
|
|
{
|
|
gtm_putmsg(VARLSTCNT(1) mu_ctrly_occurred ? ERR_CTRLY : ERR_CTRLC);
|
|
mupip_exit(ERR_MUNOFINISH);
|
|
}
|
|
if (0 != total_errors)
|
|
mupip_exit(ERR_INTEGERRS);
|
|
if (0 != mu_int_skipreg_cnt)
|
|
mupip_exit(ERR_MUNOTALLINTEG);
|
|
mupip_exit(SS_NORMAL);
|
|
}
|