/**************************************************************** * * * 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 "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "gdsblk.h" #include "gdsbml.h" #include "mupint.h" #include "gtmmsg.h" #ifdef GTM_CRYPT #include "gtmcrypt.h" #endif #ifdef GTM_SNAPSHOT #include "db_snapshot.h" #endif GBLDEF unsigned char *mu_int_locals; GBLDEF int4 mu_int_ovrhd; GBLREF gd_region *gv_cur_region; GBLREF sgmnt_data mu_int_data; GBLREF uint4 mu_int_errknt; GBLREF boolean_t tn_reset_specified; error_def(ERR_DBNOTDB); error_def(ERR_DBINCRVER); error_def(ERR_DBSVBNMIN); error_def(ERR_DBFLCORRP); error_def(ERR_DBCREINCOMP); error_def(ERR_DBBSIZZRO); error_def(ERR_DBSZGT64K); error_def(ERR_DBNOTMLTP); error_def(ERR_DBBPLMLT512); error_def(ERR_DBBPLMGT2K); error_def(ERR_DBBPLNOT512); error_def(ERR_DBTTLBLK0); error_def(ERR_DBTNNEQ); error_def(ERR_DBMAXKEYEXC); error_def(ERR_DBMXRSEXCMIN); error_def(ERR_DBMAXRSEXBL); error_def(ERR_DBUNDACCMT); error_def(ERR_DBHEADINV); error_def(ERR_DBFGTBC); error_def(ERR_DBFSTBC); error_def(ERR_DBTOTBLK); error_def(ERR_DBMISALIGN); error_def(ERR_KILLABANDONED); error_def(ERR_MUKILLIP); error_def(ERR_MUTNWARN); #ifdef GTM_SNAPSHOT # define GET_NATIVE_SIZE(native_size) \ { \ GBLREF util_snapshot_ptr_t util_ss_ptr; \ GBLREF boolean_t ointeg_this_reg; \ if (ointeg_this_reg) \ { \ assert(NULL != util_ss_ptr); \ native_size = util_ss_ptr->native_size; \ assert(0 != native_size); /* Ensure native_size is updated properly in ss_initiate */ \ } else \ native_size = gds_file_size(gv_cur_region->dyn.addr->file_cntl); \ } #else # define GET_NATIVE_SIZE(native_size) \ native_size = gds_file_size(gv_cur_region->dyn.addr->file_cntl); #endif boolean_t mu_int_fhead(void) { unsigned char *p1; unsigned int maps, native_size, size, block_factor; trans_num temp_tn, max_tn_warn; sgmnt_data_ptr_t mu_data; GTMCRYPT_ONLY(int crypt_status;) mu_data = &mu_int_data; if (MEMCMP_LIT(mu_data->label, GDS_LABEL)) { if (memcmp(mu_data->label, GDS_LABEL, SIZEOF(GDS_LABEL) - 2)) mu_int_err(ERR_DBNOTDB, 0, 0, 0, 0, 0, 0, 0); else mu_int_err(ERR_DBINCRVER, 0, 0, 0, 0, 0, 0, 0); return FALSE; } UNIX_ONLY(CHECK_DB_ENDIAN(mu_data, gv_cur_region->dyn.addr->fname_len, gv_cur_region->dyn.addr->fname)); /* bypass ok */ if (mu_data->start_vbn < DIVIDE_ROUND_UP(SIZEOF_FILE_HDR(mu_data), DISK_BLOCK_SIZE)) { mu_int_err(ERR_DBSVBNMIN, 0, 0, 0, 0, 0, 0, 0); return FALSE; } if (mu_data->file_corrupt) mu_int_err(ERR_DBFLCORRP, 0, 0, 0, 0, 0, 0, 0); if (mu_data->createinprogress) { mu_int_err(ERR_DBCREINCOMP, 0, 0, 0, 0, 0, 0, 0); return FALSE; } /* CHECK: 0 < blk_size <= 64K; blk_size is a multiple of DISK_BLOCK_SIZE */ if (0 == mu_data->blk_size) { mu_int_err(ERR_DBBSIZZRO, 0, 0, 0, 0, 0, 0, 0); return FALSE; } if (mu_data->blk_size > 1 << 16) { mu_int_err(ERR_DBSZGT64K, 0, 0, 0, 0, 0, 0, 0); return FALSE; } if (mu_data->blk_size % DISK_BLOCK_SIZE) { /* these messages should use rts_error and parameters */ assert(512 == DISK_BLOCK_SIZE); /* but in lieu of that, check that message is accurate */ mu_int_err(ERR_DBNOTMLTP, 0, 0, 0, 0, 0, 0, 0); return FALSE; } /* CHECK: BLKS_PER_LMAP <= bplmap <= 2K; bplmap is a multiple of BLKS_PER_LMAP */ if (mu_data->bplmap < BLKS_PER_LMAP) { mu_int_err(ERR_DBBPLMLT512, 0, 0, 0, 0, 0, 0, 0); return FALSE; } if (mu_data->bplmap > 1 << 11) { mu_int_err(ERR_DBBPLMGT2K, 0, 0, 0, 0, 0, 0, 0); return FALSE; } if (BLKS_PER_LMAP != mu_data->bplmap) { mu_int_err(ERR_DBBPLNOT512, 0, 0, 0, 0, 0, 0, 0); return FALSE; } /* CHECK: total_blks <> 0 */ if (0 == mu_data->trans_hist.total_blks) { mu_int_err(ERR_DBTTLBLK0, 0, 0, 0, 0, 0, 0, 0); return FALSE; } if (mu_data->trans_hist.curr_tn != mu_data->trans_hist.early_tn) mu_int_err(ERR_DBTNNEQ, 0, 0, 0, 0, 0, 0, 0); if (0 != mu_data->kill_in_prog) { gtm_putmsg(VARLSTCNT(6) ERR_MUKILLIP, 4, DB_LEN_STR(gv_cur_region), LEN_AND_LIT("MUPIP INTEG")); mu_int_errknt++; } if (0 != mu_data->abandoned_kills) { gtm_putmsg(VARLSTCNT(6) ERR_KILLABANDONED, 4, DB_LEN_STR(gv_cur_region), LEN_AND_LIT("database could have incorrectly marked busy integrity errors")); mu_int_errknt++; } if (MAX_KEY_SZ < mu_data->max_key_size) mu_int_err(ERR_DBMAXKEYEXC, 0, 0, 0, 0, 0, 0, 0); if (SIZEOF(rec_hdr) + SIZEOF(block_id) >= mu_data->max_rec_size) mu_int_err(ERR_DBMXRSEXCMIN, 0, 0, 0, 0, 0, 0, 0); if (mu_data->blk_size - SIZEOF(blk_hdr) < mu_data->max_rec_size) mu_int_err(ERR_DBMAXRSEXBL, 0, 0, 0, 0, 0, 0, 0); # ifdef GTM_CRYPT if (mu_data->is_encrypted) { /* Encryption init should have happened in db_init. */ ASSERT_ENCRYPTION_INITIALIZED; GTMCRYPT_HASH_CHK(mu_data->encryption_hash, crypt_status); if (0 != crypt_status) { GC_GTM_PUTMSG(crypt_status, (gv_cur_region->dyn.addr->fname)); return FALSE; } } # endif /* !tn_reset_this_reg should ideally be used here instead of (!tn_reset_specified || gv_cur_region->read_only). * But at this point, tn_reset_this_reg has not yet been set for this region and to avoid taking a risk in * changing the code flow, we redo the computation ot tn_reset_this_reg here. This is not as much a performance concern. */ if (!tn_reset_specified || gv_cur_region->read_only) { SET_TN_WARN(mu_data, max_tn_warn); if (max_tn_warn == mu_data->trans_hist.curr_tn) { /* implies there is not enough transactions to go before reaching MAX_TN (see SET_TN_WARN macro) */ temp_tn = mu_data->max_tn - mu_data->trans_hist.curr_tn; gtm_putmsg(VARLSTCNT(6) ERR_MUTNWARN, 4, DB_LEN_STR(gv_cur_region), &temp_tn, &mu_data->max_tn); mu_int_errknt++; } } /* Note - ovrhd is incremented once in order to achieve a zero-based * index of the GDS 'data' blocks (those other than the file header * and the block table). */ switch (mu_data->acc_meth) { default: mu_int_err(ERR_DBUNDACCMT, 0, 0, 0, 0, 0, 0, 0); /*** WARNING: Drop thru ***/ #ifdef VMS #ifdef GT_CX_DEF case dba_bg: /* necessary to do calculation in this manner to prevent double rounding causing an error */ if (mu_data->unbacked_cache) mu_int_ovrhd = DIVIDE_ROUND_UP(SIZEOF_FILE_HDR(mu_data) + mu_data->free_space + mu_data->lock_space_size, DISK_BLOCK_SIZE); else mu_int_ovrhd = DIVIDE_ROUND_UP(SIZEOF_FILE_HDR(mu_data) + BT_SIZE(mu_data) + mu_data->free_space + mu_data->lock_space_size, DISK_BLOCK_SIZE); break; case dba_mm: mu_int_ovrhd = DIVIDE_ROUND_UP(SIZEOF_FILE_HDR(mu_data) + mu_data->free_space, DISK_BLOCK_SIZE); break; #else case dba_bg: /*** WARNING: Drop thru ***/ case dba_mm: mu_int_ovrhd = DIVIDE_ROUND_UP(SIZEOF_FILE_HDR(mu_data) + mu_data->free_space, DISK_BLOCK_SIZE); break; #endif #elif defined(UNIX) case dba_bg: /*** WARNING: Drop thru ***/ case dba_mm: mu_int_ovrhd = (int4)DIVIDE_ROUND_UP(SIZEOF_FILE_HDR(mu_data) + mu_data->free_space, DISK_BLOCK_SIZE); #else #error unsupported platform #endif } assert(mu_data->blk_size == ROUND_UP(mu_data->blk_size, DISK_BLOCK_SIZE)); block_factor = mu_data->blk_size / DISK_BLOCK_SIZE; mu_int_ovrhd += 1; if (mu_int_ovrhd != mu_data->start_vbn) { mu_int_err(ERR_DBHEADINV, 0, 0, 0, 0, 0, 0, 0); return FALSE; } size = mu_int_ovrhd + block_factor * mu_data->trans_hist.total_blks; /* If ONLINE INTEG for this region is in progress, then native_size would have been calculated in ss_initiate. */ GET_NATIVE_SIZE(native_size); /* In the following tests, the EOF block should always be 1 greater * than the actual size of the file. This is due to the GDS being * allocated in even DISK_BLOCK_SIZE-byte blocks. */ if (native_size && (size != native_size)) { if (size < native_size) mu_int_err(ERR_DBFGTBC, 0, 0, 0, 0, 0, 0, 0); else mu_int_err(ERR_DBFSTBC, 0, 0, 0, 0, 0, 0, 0); if (native_size % 2) /* Native size should be (64K + n*1K + 512) / DISK_BLOCK_SIZE , so always an odd number. */ gtm_putmsg(VARLSTCNT(4) ERR_DBTOTBLK, 2, (native_size - mu_data->start_vbn) / block_factor, mu_data->trans_hist.total_blks); else /* Since native_size is even and the result will be rounded down, we need to add 1 before the division so we * extend by enough blocks (ie. if current nb. of blocks is 100, and the file size gives 102.5 blocks, we * need to extend by 3 blocks, not 2). */ gtm_putmsg(VARLSTCNT(6) ERR_DBMISALIGN, 4, DB_LEN_STR(gv_cur_region), (native_size - mu_data->start_vbn) / block_factor, ((native_size + 1 - mu_data->start_vbn) / block_factor) - mu_data->trans_hist.total_blks); } /* make working space for all local bitmaps */ maps = (mu_data->trans_hist.total_blks + mu_data->bplmap - 1) / mu_data->bplmap; size = (unsigned int)(BM_SIZE(mu_data->bplmap) - SIZEOF(blk_hdr)); size *= maps; mu_int_locals = (unsigned char *)malloc(size); memset(mu_int_locals, FOUR_BLKS_FREE, size); return TRUE; }