276 lines
9.3 KiB
C
276 lines
9.3 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 "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;
|
|
}
|