/**************************************************************** * * * 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_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 ) and mu_int_reg(mupip integ -reg ). */ 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_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= 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; mu_int_errknt++; mu_int_err(ERR_DBNOREGION, 0, 0, 0, 0, 0, 0, 0); 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_errknt++; 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:; blks: ]*/ } 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); mupip_exit(SS_NORMAL); }