185 lines
5.7 KiB
C
185 lines
5.7 KiB
C
|
/****************************************************************
|
||
|
* *
|
||
|
* Copyright 2013 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 "cdb_sc.h"
|
||
|
#include "gdsroot.h"
|
||
|
#include "gdsblk.h"
|
||
|
#include "gtm_facility.h"
|
||
|
#include "fileinfo.h"
|
||
|
#include "gdsbt.h"
|
||
|
#include "gdsfhead.h"
|
||
|
#include "filestruct.h"
|
||
|
#include "jnl.h"
|
||
|
#include "gdsblkops.h"
|
||
|
#include "gdskill.h"
|
||
|
#include "gdscc.h"
|
||
|
#include "copy.h"
|
||
|
#include "mu_reorg.h"
|
||
|
#include "util.h"
|
||
|
#include "min_max.h"
|
||
|
|
||
|
GBLREF sgmnt_data_ptr_t cs_data;
|
||
|
GBLREF unsigned int t_tries;
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
# define DBG_VERIFY_ACCESS(PTR) \
|
||
|
{ /* Ensure accessible pointer (no SIG-11) */ \
|
||
|
unsigned char c; \
|
||
|
\
|
||
|
c = *(unsigned char *)(PTR); \
|
||
|
}
|
||
|
#else
|
||
|
# define DBG_VERIFY_ACCESS(PTR)
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* Get length of the global variable name contained in the key starting at KEY_BASE.
|
||
|
* NOTE: If keys reside outside a GDS block (e.g. in cs_data), allocated buffer should have capacity at least MAX_KEY_SZ.
|
||
|
* Input:
|
||
|
* BLK_BASE := if non-NULL, base of current block
|
||
|
* if NULL, it means we're dealing with a key that is not within a database block
|
||
|
* KEY_BASE := starting address of key
|
||
|
* Output:
|
||
|
* GBLNAME_LEN := length of global variable name
|
||
|
*/
|
||
|
int get_gblname_len(sm_uc_ptr_t blk_base, sm_uc_ptr_t key_base)
|
||
|
{
|
||
|
sm_uc_ptr_t rPtr1, blk_end;
|
||
|
|
||
|
blk_end = (NULL != blk_base) ? (blk_base + cs_data->blk_size) : (key_base + MAX_KEY_SZ);
|
||
|
DBG_VERIFY_ACCESS(blk_end - 1);
|
||
|
for (rPtr1 = key_base; ; )
|
||
|
{
|
||
|
if (blk_end <= rPtr1)
|
||
|
break;
|
||
|
if (KEY_DELIMITER == *rPtr1++)
|
||
|
break;
|
||
|
}
|
||
|
return (int)(rPtr1 - key_base);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Get length of the key starting at KEY_BASE.
|
||
|
* NOTE: If keys reside outside a GDS block (e.g. in cs_data), allocated buffer should have capacity at least MAX_KEY_SZ.
|
||
|
* Currently, all get_key_len() calls take a key in shared memory; the only "allocated buffer" is csd->reorg_restart_key.
|
||
|
* Input:
|
||
|
* BLK_BASE := if non-NULL, base of current block
|
||
|
* if NULL, it means we're dealing with a key that is not within a database block
|
||
|
* KEY_BASE := starting address of key
|
||
|
* Output:
|
||
|
* KEY_LEN := length of key, including 2 null bytes at the end
|
||
|
*/
|
||
|
int get_key_len(sm_uc_ptr_t blk_base, sm_uc_ptr_t key_base)
|
||
|
{
|
||
|
sm_uc_ptr_t rPtr1, blk_end;
|
||
|
|
||
|
blk_end = (NULL != blk_base) ? (blk_base + cs_data->blk_size) : (key_base + MAX_KEY_SZ);
|
||
|
DBG_VERIFY_ACCESS(blk_end - 1);
|
||
|
for (rPtr1 = key_base; ; )
|
||
|
{
|
||
|
if (blk_end <= rPtr1 + 1)
|
||
|
break;
|
||
|
if ((KEY_DELIMITER == *rPtr1++) && (KEY_DELIMITER == *rPtr1))
|
||
|
break;
|
||
|
}
|
||
|
return (int)(rPtr1 + 1 - key_base);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Get compression count of SECOND_KEY with respect to FIRST_KEY.
|
||
|
* NOTE: Each key should reside in a private buffer with capacity at least MAX_KEY_SZ.
|
||
|
*/
|
||
|
int get_cmpc(sm_uc_ptr_t first_key, sm_uc_ptr_t second_key)
|
||
|
{
|
||
|
sm_uc_ptr_t rPtr1, rPtr2;
|
||
|
int cmpc;
|
||
|
|
||
|
DBG_VERIFY_ACCESS(first_key + MAX_KEY_SZ - 1);
|
||
|
DBG_VERIFY_ACCESS(second_key + MAX_KEY_SZ - 1);
|
||
|
/* We don't expect the inputs to be equal, hence the assert. It shouldn't matter, though. If the keys' contents are equal,
|
||
|
* we return an indeterminate value between the key length and MAX_KEY_SZ. The value depends on the garbage bytes past the
|
||
|
* terminating null bytes. But we don't care because we don't compress a key off an identical key in the final retry.
|
||
|
*/
|
||
|
assert(first_key != second_key);
|
||
|
for (rPtr1 = first_key, rPtr2 = second_key, cmpc = 0; cmpc < MAX_KEY_SZ; cmpc++)
|
||
|
{
|
||
|
if (*rPtr1++ != *rPtr2++)
|
||
|
break;
|
||
|
}
|
||
|
return cmpc;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Copy record info (record size and key) out of a block.
|
||
|
* Input:
|
||
|
* LEVEL := level of current block
|
||
|
* BLK_BASE := base of current block
|
||
|
* REC_BASE := starting address of record in current block
|
||
|
* KEY := previous key; first KEY_CMPC bytes are retained in output KEY
|
||
|
* Output:
|
||
|
* STATUS := status of read
|
||
|
* REC_SIZE := record size
|
||
|
* KEY_CMPC := key compression count
|
||
|
* KEY_LEN := key length
|
||
|
* KEY := local copy of key copied out of record
|
||
|
*/
|
||
|
enum cdb_sc read_record(int *rec_size_ptr, int *key_cmpc_ptr, int *key_len_ptr, sm_uc_ptr_t key,
|
||
|
int level, sm_uc_ptr_t blk_base, sm_uc_ptr_t rec_base)
|
||
|
{
|
||
|
sm_uc_ptr_t rPtr1, rPtr2, blk_end, rPtr1_end, rPtr2_end;
|
||
|
unsigned short temp_ushort;
|
||
|
int key_cmpc, rec_size, key_len;
|
||
|
boolean_t invalid;
|
||
|
|
||
|
blk_end = blk_base + cs_data->blk_size;
|
||
|
DBG_VERIFY_ACCESS(blk_end - 1);
|
||
|
if (blk_end <= (rec_base + SIZEOF(rec_hdr)))
|
||
|
{
|
||
|
assert(CDB_STAGNATE > t_tries);
|
||
|
return cdb_sc_blkmod;
|
||
|
}
|
||
|
GET_USHORT(temp_ushort, &(((rec_hdr_ptr_t)rec_base)->rsiz));
|
||
|
rec_size = temp_ushort;
|
||
|
key_cmpc = EVAL_CMPC((rec_hdr_ptr_t)rec_base);
|
||
|
if ((0 != level) && (BSTAR_REC_SIZE == rec_size))
|
||
|
{
|
||
|
key_len = 0;
|
||
|
*key_cmpc_ptr = key_cmpc;
|
||
|
*rec_size_ptr = rec_size;
|
||
|
*key_len_ptr = key_len;
|
||
|
return cdb_sc_starrecord;
|
||
|
}
|
||
|
rPtr1_end = key + MAX_KEY_SZ - 1;
|
||
|
DBG_VERIFY_ACCESS(rPtr1_end);
|
||
|
rPtr2_end = MIN(blk_end - 1, rec_base + SIZEOF(rec_hdr) + MAX_KEY_SZ - 1);
|
||
|
for (rPtr1 = key + key_cmpc, rPtr2 = rec_base + SIZEOF(rec_hdr); (rPtr1 < rPtr1_end) && (rPtr2 < rPtr2_end); )
|
||
|
{
|
||
|
if ((KEY_DELIMITER == (*rPtr1++ = *rPtr2++)) && (KEY_DELIMITER == *rPtr2)) /* note assignment */
|
||
|
break;
|
||
|
}
|
||
|
*rPtr1++ = *rPtr2++;
|
||
|
key_len = (int)(rPtr2 - rec_base - SIZEOF(rec_hdr));
|
||
|
invalid = INVALID_RECORD(level, rec_size, key_len, key_cmpc);
|
||
|
if (invalid || ((KEY_DELIMITER != *(rPtr1 - 1)) || (KEY_DELIMITER != *(rPtr1 - 2))))
|
||
|
{
|
||
|
assert(CDB_STAGNATE > t_tries);
|
||
|
return cdb_sc_blkmod;
|
||
|
}
|
||
|
*key_cmpc_ptr = key_cmpc;
|
||
|
*rec_size_ptr = rec_size;
|
||
|
*key_len_ptr = key_len;
|
||
|
return cdb_sc_normal;
|
||
|
}
|