921 lines
30 KiB
C
921 lines
30 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 "gtm_ctype.h"
|
|
|
|
#include "gdsroot.h"
|
|
#include "gtm_facility.h"
|
|
#include "fileinfo.h"
|
|
#include "gdsbt.h"
|
|
#include "gdsfhead.h"
|
|
#include "gdsdbver.h"
|
|
#include "gdsblk.h"
|
|
#include "copy.h"
|
|
#include "mupint.h"
|
|
#include "subscript.h"
|
|
#include "spec_type.h"
|
|
#include "mmemory.h"
|
|
#include "util.h"
|
|
#include "gdsbml.h"
|
|
#include "gtmmsg.h"
|
|
#include "get_spec.h"
|
|
#ifdef GTM_TRIGGER
|
|
#include <rtnhdr.h> /* for rtn_tabent in gv_trigger.h */
|
|
#include "gv_trigger.h"
|
|
#endif
|
|
|
|
#define NEG_SUB 127
|
|
#define NO_SUBSCRIPTS -1
|
|
#define MAX_UTIL_SIZE 32
|
|
#define MIN_DATA (3 * SIZEOF(char)) /* a non-empty data block rec must have at least one character of key and two of terminator */
|
|
#define TEXT2 "Block "
|
|
#define TEXT3 " doubly allocated"
|
|
#define SPAN_SUBS_LENGTH 5
|
|
#define SPAN_START_BYTE 0x02
|
|
#define SPAN_BYTE_MAX 255
|
|
#define SPAN_BYTE_MIN 1
|
|
#define SPAN_SUBS_OFF 48
|
|
|
|
GBLDEF unsigned char muint_temp_buff[MAX_MIDENT_LEN + 1];
|
|
GBLREF unsigned char *mu_int_locals;
|
|
GBLREF unsigned char mu_int_root_level;
|
|
GBLREF bool mu_ctrly_occurred, mu_ctrlc_occurred;
|
|
GBLREF boolean_t block;
|
|
GBLREF boolean_t master_dir;
|
|
GBLREF boolean_t muint_fast;
|
|
GBLREF boolean_t muint_key;
|
|
GBLREF boolean_t muint_subsc;
|
|
GBLREF boolean_t tn_reset_this_reg;
|
|
GBLREF int disp_maxkey_errors;
|
|
GBLREF int disp_trans_errors;
|
|
GBLREF int maxkey_errors;
|
|
GBLREF int muint_adj;
|
|
GBLREF int muint_end_keyend;
|
|
GBLREF int muint_start_keyend;
|
|
GBLREF int mu_int_plen;
|
|
GBLREF int trans_errors;
|
|
GBLREF int4 mu_int_adj[];
|
|
GBLREF uint4 mu_int_blks[];
|
|
GBLREF uint4 mu_int_offset[];
|
|
GBLREF uint4 mu_int_recs[];
|
|
GBLREF qw_num mu_int_size[];
|
|
GBLREF uint4 mu_int_errknt;
|
|
GBLREF block_id mu_int_adj_prev[];
|
|
GBLREF block_id mu_int_path[];
|
|
GBLREF int4 mu_int_blks_to_upgrd;
|
|
GBLREF global_list *trees;
|
|
GBLREF global_list *trees_tail;
|
|
GBLREF gv_key *muint_end_key;
|
|
GBLREF gv_key *muint_start_key;
|
|
GBLREF sgmnt_data mu_int_data;
|
|
GBLREF trans_num largest_tn;
|
|
GBLREF span_node_integ *sndata;
|
|
|
|
error_def(ERR_DBBADKYNM);
|
|
error_def(ERR_DBBADNSUB);
|
|
error_def(ERR_DBBADPNTR);
|
|
error_def(ERR_DBBDBALLOC);
|
|
error_def(ERR_DBBNPNTR);
|
|
error_def(ERR_DBBSIZMN);
|
|
error_def(ERR_DBBSIZMX);
|
|
error_def(ERR_DBCMPBAD);
|
|
error_def(ERR_DBCMPNZRO);
|
|
error_def(ERR_DBCOMPTOOLRG);
|
|
error_def(ERR_DBGTDBMAX);
|
|
error_def(ERR_DBINCLVL);
|
|
error_def(ERR_DBINVGBL);
|
|
error_def(ERR_DBKEYGTIND);
|
|
error_def(ERR_DBKEYMN);
|
|
error_def(ERR_DBKEYMX);
|
|
error_def(ERR_DBKEYORD);
|
|
error_def(ERR_DBKGTALLW);
|
|
error_def(ERR_DBLRCINVSZ);
|
|
error_def(ERR_DBLTSIBL);
|
|
error_def(ERR_DBMAXNRSUBS); /* same error as ERR_MAXNRSUBSCRIPTS, but has a string output as well */
|
|
error_def(ERR_DBPTRMX);
|
|
error_def(ERR_DBPTRNOTPOS);
|
|
error_def(ERR_DBRLEVTOOHI);
|
|
error_def(ERR_DBRLEVLTONE);
|
|
error_def(ERR_DBSTARCMP);
|
|
error_def(ERR_DBRSIZMN);
|
|
error_def(ERR_DBRSIZMX);
|
|
error_def(ERR_DBDATAMX);
|
|
error_def(ERR_DBTN);
|
|
error_def(ERR_DBTNTOOLG);
|
|
error_def(ERR_DBSPANGLOINCMP);
|
|
error_def(ERR_DBSPANCHUNKORD);
|
|
|
|
LITDEF boolean_t mu_int_possub[16][16] = {
|
|
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
|
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0},
|
|
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0},
|
|
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0},
|
|
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0},
|
|
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0},
|
|
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0},
|
|
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0},
|
|
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0},
|
|
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0},
|
|
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0},
|
|
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
|
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
|
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
|
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
|
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
|
};
|
|
|
|
LITDEF boolean_t mu_int_negsub[16][16] = {
|
|
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
|
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
|
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
|
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
|
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
|
{0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
|
{0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
|
{0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
|
{0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
|
{0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
|
{0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
|
{0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
|
{0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
|
{0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
|
{0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
|
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
|
};
|
|
|
|
LITDEF boolean_t mu_int_exponent[256] = {
|
|
0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0};
|
|
|
|
|
|
boolean_t mu_int_blk(
|
|
block_id blk,
|
|
char level,
|
|
boolean_t is_root,
|
|
unsigned char *bot_key,
|
|
int bot_len,
|
|
unsigned char *top_key,
|
|
int top_len,
|
|
boolean_t eb_ok) /* boolean indicating whether an empty block here is ok. This is true when
|
|
the parent is a root with only a star key */
|
|
{
|
|
typedef struct
|
|
{
|
|
boolean_t numeric;
|
|
int index;
|
|
} sub_list;
|
|
|
|
unsigned char buff[MAX_KEY_SZ + 1], old_buff[MAX_KEY_SZ + 1], temp_buff[MAX_MIDENT_LEN + 1], util_buff[MAX_UTIL_SIZE];
|
|
unsigned char blk_levl, *c1, ch, *ctrlbytes;
|
|
unsigned short cc, rec_cmpc;
|
|
uchar_ptr_t c0, c2, c_base, blk_base, blk_top, key_base, ptr, rec_base, rec_top, span_key;
|
|
unsigned short temp_ushort;
|
|
boolean_t first_key, is_top, pstar, valid_gbl, hasht_global;
|
|
boolean_t muint_range_done = FALSE;
|
|
int blk_size, buff_length, b_index, cmcc, comp_length, key_size, len, name_len,
|
|
num_len, rec_size, s_index, start_index, hdr_len, idx;
|
|
int tmp_cmpc, tmp_numsubs, max_allowed_key_size;
|
|
block_id child, root_pointer;
|
|
sub_list mu_sub_list[MAX_GVSUBSCRIPTS + 1];
|
|
sub_num check_vals;
|
|
trans_num blk_tn;
|
|
uchar_ptr_t subrec_ptr;
|
|
enum db_ver ondsk_blkver;
|
|
uint4 cnt, span_curr_blk, rval_len, gblsize;
|
|
unsigned short numsubs;
|
|
|
|
mu_int_offset[mu_int_plen] = 0;
|
|
mu_int_path[mu_int_plen++] = blk;
|
|
mu_int_path[mu_int_plen] = 0;
|
|
if (!bml_busy(blk, mu_int_locals)) /* block already marked busy */
|
|
{
|
|
mu_int_err(ERR_DBBDBALLOC, TRUE, TRUE, bot_key, bot_len, top_key, top_len, (unsigned int)(level));
|
|
return FALSE;
|
|
}
|
|
blk_base = mu_int_read(blk, &ondsk_blkver); /* ondsk_blkver set to GDSV4 or GDSV6 (GDSVCURR) */
|
|
if (!blk_base)
|
|
return FALSE;
|
|
blk_size = (int)((blk_hdr_ptr_t)blk_base)->bsiz;
|
|
if (!muint_fast)
|
|
{
|
|
if (tn_reset_this_reg)
|
|
{
|
|
((blk_hdr_ptr_t)blk_base)->tn = 1;
|
|
mu_int_write(blk, blk_base);
|
|
if (GDSVCURR != mu_int_data.desired_db_format)
|
|
mu_int_blks_to_upgrd++;
|
|
} else if (GDSVCURR != ondsk_blkver)
|
|
mu_int_blks_to_upgrd++;
|
|
}
|
|
/* pstar indicates that the current block is a (root block with only a star key) or not.
|
|
This is passed into mu_int_blk() as eb_ok */
|
|
pstar = (is_root && (SIZEOF(blk_hdr) + SIZEOF(rec_hdr) + SIZEOF(block_id) == blk_size));
|
|
if (blk_size < (SIZEOF(blk_hdr) + (eb_ok ? 0 : (SIZEOF(rec_hdr) + (level ? SIZEOF(block_id) : MIN_DATA)))))
|
|
{
|
|
mu_int_err(ERR_DBBSIZMN, TRUE, TRUE, bot_key, bot_len, top_key, top_len,
|
|
(unsigned int)((blk_hdr_ptr_t)blk_base)->levl);
|
|
free(blk_base);
|
|
return FALSE;
|
|
}
|
|
if (blk_size > mu_int_data.blk_size)
|
|
{
|
|
mu_int_err(ERR_DBBSIZMX, TRUE, TRUE, bot_key, bot_len, top_key, top_len,
|
|
(unsigned int)((blk_hdr_ptr_t)blk_base)->levl);
|
|
free(blk_base);
|
|
return FALSE;
|
|
}
|
|
blk_top = blk_base + blk_size;
|
|
blk_levl = ((blk_hdr_ptr_t)blk_base)->levl;
|
|
if (block)
|
|
mu_int_root_level = level = blk_levl;
|
|
else if (is_root)
|
|
{
|
|
if (blk_levl >= MAX_BT_DEPTH)
|
|
{
|
|
mu_int_err(ERR_DBRLEVTOOHI, 0, 0, 0, 0, 0, 0, (unsigned int)blk_levl);
|
|
free(blk_base);
|
|
return FALSE;
|
|
}
|
|
if (blk_levl < 1)
|
|
{
|
|
mu_int_err(ERR_DBRLEVLTONE, 0, 0, 0, 0, 0, 0, (unsigned int)blk_levl);
|
|
free(blk_base);
|
|
return FALSE;
|
|
}
|
|
mu_int_root_level = level = blk_levl;
|
|
} else if (blk_levl != level)
|
|
{
|
|
mu_int_err(ERR_DBINCLVL, TRUE, TRUE, bot_key, bot_len, top_key, top_len, (unsigned int)blk_levl);
|
|
free(blk_base);
|
|
return FALSE;
|
|
}
|
|
if (!master_dir)
|
|
{
|
|
if (mu_int_adj_prev[level] <= blk + muint_adj && mu_int_adj_prev[level] >= blk - muint_adj)
|
|
mu_int_adj[level] += 1;
|
|
mu_int_adj_prev[level] = blk;
|
|
}
|
|
blk_tn = ((blk_hdr_ptr_t)blk_base)->tn;
|
|
if (blk_tn >= mu_int_data.trans_hist.curr_tn)
|
|
{
|
|
if (trans_errors < disp_trans_errors)
|
|
{
|
|
mu_int_err(ERR_DBTNTOOLG, TRUE, TRUE, bot_key, bot_len, top_key, top_len,
|
|
(unsigned int)blk_levl);
|
|
mu_int_plen++; /* continuing, so compensate for mu_int_err decrement */
|
|
gtm_putmsg(VARLSTCNT(3) ERR_DBTN, 1, &blk_tn);
|
|
trans_errors++;
|
|
} else
|
|
{
|
|
mu_int_errknt++;
|
|
trans_errors++;
|
|
}
|
|
/* Stop searching the sub-tree when TN in block is larger than integ_start_tn for fast_integ. The reason being,
|
|
* fast_integ skips writing free blocks and level-0 block in GV tree to snapshot file. However, some blocks can be
|
|
* mistakenly marked free or its level is messed-up as 0. After updating these blocks, thse blocks will have TN
|
|
* larger than integ_start_tn. In this case, the child tree pointed to by one such updated block may result in
|
|
* arbitrary error report. Since we already capture the core reason for the integ error, we should not proceed
|
|
* searching its child tree; otherwise, we will have meaningless report content
|
|
*/
|
|
if (muint_fast)
|
|
return FALSE;
|
|
if (blk_tn > largest_tn)
|
|
largest_tn = blk_tn;
|
|
}
|
|
mu_int_blks[level]++;
|
|
QWINCRBYDW(mu_int_size[level], blk_size);
|
|
first_key = TRUE;
|
|
buff_length = 0;
|
|
comp_length = bot_len;
|
|
is_top = FALSE;
|
|
memcpy(buff, bot_key, bot_len);
|
|
mu_sub_list[0].index = NO_SUBSCRIPTS;
|
|
for (rec_base = blk_base + SIZEOF(blk_hdr); (rec_base < blk_top) && (FALSE == muint_range_done);
|
|
rec_base = rec_top, comp_length = buff_length)
|
|
{
|
|
if (mu_ctrly_occurred || mu_ctrlc_occurred)
|
|
return FALSE;
|
|
mu_int_recs[level]++;
|
|
GET_USHORT(temp_ushort, &(((rec_hdr_ptr_t)rec_base)->rsiz));
|
|
rec_size = temp_ushort;
|
|
mu_int_offset[mu_int_plen - 1] = (uint4)(rec_base - blk_base);
|
|
if (rec_size <= SIZEOF(rec_hdr))
|
|
{
|
|
mu_int_err(ERR_DBRSIZMN, TRUE, TRUE, buff, comp_length, top_key, top_len, (unsigned int)blk_levl);
|
|
free(blk_base);
|
|
return FALSE;
|
|
}
|
|
if ((rec_size > blk_top - rec_base))
|
|
{
|
|
mu_int_err(ERR_DBRSIZMX, TRUE, TRUE, buff, comp_length, top_key, top_len, (unsigned int)blk_levl);
|
|
free(blk_base);
|
|
return FALSE;
|
|
}
|
|
rec_top = rec_base + rec_size;
|
|
rec_cmpc = EVAL_CMPC((rec_hdr_ptr_t)rec_base);
|
|
if (level && (rec_top == blk_top))
|
|
{
|
|
is_top = TRUE;
|
|
if (SIZEOF(rec_hdr) + SIZEOF(block_id) != rec_size)
|
|
{
|
|
mu_int_err(ERR_DBLRCINVSZ, TRUE, TRUE, buff, comp_length, top_key, top_len, (unsigned int)blk_levl);
|
|
free(blk_base);
|
|
return FALSE;
|
|
}
|
|
if (rec_cmpc)
|
|
{
|
|
mu_int_err(ERR_DBSTARCMP, TRUE, TRUE, buff, comp_length, top_key, top_len, (unsigned int)blk_levl);
|
|
free(blk_base);
|
|
return FALSE;
|
|
}
|
|
ptr = rec_base + SIZEOF(rec_hdr);
|
|
} else
|
|
{
|
|
if (first_key)
|
|
{
|
|
if (rec_cmpc)
|
|
{
|
|
mu_int_err(ERR_DBCMPNZRO, TRUE, TRUE, buff,
|
|
comp_length, top_key, top_len, (unsigned int)blk_levl);
|
|
free(blk_base);
|
|
return FALSE;
|
|
}
|
|
} else if ((rec_cmpc < name_len) && (FALSE == master_dir))
|
|
{
|
|
mu_int_err(ERR_DBINVGBL, TRUE, TRUE, buff, comp_length, top_key, top_len,
|
|
(unsigned int)blk_levl);
|
|
if (!level)
|
|
{ /* since global names are mixed, the numeric subscript check done later below
|
|
* (using mu_sub_list) needs to not use the optimization which relies on the assumption
|
|
* that all keys within a block have the same global name prefix.
|
|
* reset mu_sub_list[0].index here to ensure the same.
|
|
*/
|
|
mu_sub_list[0].index = NO_SUBSCRIPTS;
|
|
}
|
|
mu_int_plen++; /* continuing, so compensate for mu_int_err decrement */
|
|
}
|
|
if (rec_cmpc && (short int)rec_cmpc >= buff_length)
|
|
{
|
|
mu_int_err(ERR_DBCOMPTOOLRG, TRUE, TRUE, buff, comp_length, top_key,
|
|
top_len, (unsigned int)blk_levl);
|
|
free(blk_base);
|
|
return FALSE;
|
|
}
|
|
key_base = rec_base + SIZEOF(rec_hdr);
|
|
for (ptr = key_base; ;)
|
|
{
|
|
if (ptr >= rec_top)
|
|
{
|
|
mu_int_err(ERR_DBKEYMX, TRUE, TRUE, buff, comp_length, top_key, top_len,
|
|
(unsigned int)blk_levl);
|
|
free(blk_base);
|
|
return FALSE;
|
|
}
|
|
if (KEY_DELIMITER == *ptr++)
|
|
{
|
|
if (first_key)
|
|
{
|
|
first_key = FALSE;
|
|
name_len = (int)(ptr - key_base);
|
|
if (!master_dir)
|
|
{ /* If NOT directory tree and this is the first key in the block,
|
|
* make sure the global name part of the key matches the name
|
|
* corresponding to the current global variable tree.
|
|
*/
|
|
assert(strlen(trees->key) == trees->keysize);
|
|
if (0 != memcmp(trees->key, key_base, trees->keysize + 1))
|
|
{
|
|
mu_int_err(ERR_DBINVGBL, TRUE, TRUE, bot_key, bot_len,
|
|
top_key, top_len, (unsigned int)blk_levl);
|
|
free(blk_base);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
if (KEY_DELIMITER == *ptr++)
|
|
break;
|
|
}
|
|
}
|
|
key_size = (int)(ptr - key_base);
|
|
if (level && (rec_size - SIZEOF(block_id) - SIZEOF(rec_hdr) != key_size))
|
|
{
|
|
mu_int_err(ERR_DBKEYMN, TRUE, TRUE, buff, comp_length, top_key, top_len,
|
|
(unsigned int)blk_levl);
|
|
free(blk_base);
|
|
return FALSE;
|
|
}
|
|
if (key_size + rec_cmpc > MAX_KEY_SZ)
|
|
{ /* We'll allow index keys to be whatever length, so long as they don't exceed MAX_KEY_SZ */
|
|
mu_int_err(ERR_DBKGTALLW, TRUE, TRUE, buff, comp_length, top_key,
|
|
top_len, (unsigned int)blk_levl);
|
|
free(blk_base);
|
|
return FALSE;
|
|
}
|
|
if ((short int)rec_cmpc < buff_length && buff[rec_cmpc] == *key_base)
|
|
{
|
|
mu_int_err(ERR_DBCMPBAD, TRUE, TRUE, buff, comp_length, top_key, top_len,
|
|
(unsigned int)blk_levl);
|
|
free(blk_base);
|
|
return FALSE;
|
|
}
|
|
if (memvcmp(buff + rec_cmpc, comp_length - rec_cmpc, key_base, key_size) >= 0)
|
|
{
|
|
if (3 == mu_int_offset[mu_int_plen - 1])
|
|
{
|
|
mu_int_err(ERR_DBLTSIBL,
|
|
TRUE, TRUE, buff, comp_length, top_key, top_len, (unsigned int)blk_levl);
|
|
mu_int_plen++; /* continuing, so compensate for mu_int_err decrement */
|
|
} else
|
|
{
|
|
mu_int_err(ERR_DBKEYORD, TRUE, TRUE, buff, comp_length, top_key, top_len,
|
|
(unsigned int)blk_levl);
|
|
free(blk_base);
|
|
return FALSE;
|
|
}
|
|
}
|
|
memcpy(old_buff, buff, comp_length);
|
|
memcpy(buff + rec_cmpc, key_base, key_size);
|
|
buff_length = rec_cmpc + key_size;
|
|
/* Now that we have the uncompressed global variable name, check for global name validity.
|
|
* Note that it is enough to check the validity on the leaf level directory tree and not
|
|
* for every block. Invalid global names in non-directory tree blocks will encounter
|
|
* either DBKEYORD error or DBINVGBL. Below are the rules for validating.
|
|
* a) The first character should be ALPHA or '%' or '#'
|
|
* b) If first character is '#' then the following character should be 't' followed by 2 KEY_DELIMITERS
|
|
* c) If first character is '%' then the following characters should be ALPHANUMERIC and 2 KEY_DELIMITERS
|
|
*/
|
|
if (master_dir && !level)
|
|
{
|
|
hasht_global = FALSE;
|
|
ch = buff[0];
|
|
switch (ch)
|
|
{
|
|
# ifdef GTM_TRIGGER
|
|
case HASHT_GBL_CHAR1:
|
|
hasht_global = valid_gbl = (HASHT_GBL_CHAR2 == buff[1]);
|
|
idx = 2;
|
|
break;
|
|
# endif
|
|
case '%':
|
|
default:
|
|
valid_gbl = VALFIRSTCHAR(ch);
|
|
idx = 1;
|
|
break;
|
|
}
|
|
if (!hasht_global)
|
|
{
|
|
for (; valid_gbl && (idx <= buff_length - 3); idx++)
|
|
valid_gbl = (valid_gbl && VALKEY(buff[idx]));
|
|
}
|
|
valid_gbl = (valid_gbl && (KEY_DELIMITER == buff[idx]) && (KEY_DELIMITER == buff[idx + 1]));
|
|
if (!valid_gbl)
|
|
{
|
|
mu_int_err(ERR_DBBADKYNM, TRUE, TRUE, buff, buff_length, top_key, top_len,
|
|
(unsigned int)blk_levl);
|
|
mu_int_plen++; /* continuing, so compensate for mu_int_err decrement */
|
|
}
|
|
}
|
|
if (!master_dir)
|
|
{ /* master_directory has no subscripts; block splits don't preserve numeric integrity in index */
|
|
if (muint_subsc)
|
|
{
|
|
if (muint_end_key)
|
|
{
|
|
if (memcmp(buff, muint_end_key->base, muint_end_key->end + 1) > 0)
|
|
{
|
|
if (level)
|
|
muint_range_done = TRUE;
|
|
else
|
|
{
|
|
mu_int_recs[level]--;
|
|
mu_int_plen--;
|
|
free(blk_base);
|
|
return TRUE;
|
|
}
|
|
}
|
|
if (memcmp(buff, muint_start_key->base, muint_start_key->end + 1) < 0)
|
|
{
|
|
mu_int_recs[level]--;
|
|
continue;
|
|
}
|
|
} else
|
|
{
|
|
if (memcmp(buff, muint_start_key->base, muint_start_key->end + 1) > 0)
|
|
{
|
|
if (level)
|
|
muint_range_done = TRUE;
|
|
else
|
|
{
|
|
mu_int_recs[level]--;
|
|
mu_int_plen--;
|
|
free(blk_base);
|
|
return TRUE;
|
|
}
|
|
}
|
|
if (memcmp(buff, muint_start_key->base, muint_start_key->end + 1) < 0)
|
|
{
|
|
mu_int_recs[level]--;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
if (!level)
|
|
{
|
|
s_index = 0;
|
|
if (NO_SUBSCRIPTS != mu_sub_list[0].index)
|
|
{
|
|
for (; (mu_sub_list[s_index].index < (short int)rec_cmpc - 1) &&
|
|
mu_sub_list[s_index].index > 0;)
|
|
if (MAX_GVSUBSCRIPTS <= s_index++)
|
|
break;
|
|
if (s_index)
|
|
s_index--;
|
|
} else /* scan off key */
|
|
{
|
|
for (b_index = 0; buff[b_index]; b_index++)
|
|
;
|
|
b_index++;
|
|
mu_sub_list[0].index = b_index;
|
|
}
|
|
b_index = mu_sub_list[s_index].index;
|
|
start_index = s_index;
|
|
while (buff[b_index])
|
|
{
|
|
if (mu_int_exponent[buff[b_index]])
|
|
mu_sub_list[s_index].numeric = TRUE;
|
|
else
|
|
mu_sub_list[s_index].numeric = FALSE;
|
|
mu_sub_list[s_index].index = b_index;
|
|
for (; buff[b_index]; b_index++)
|
|
;
|
|
b_index++;
|
|
if (MAX_GVSUBSCRIPTS <= s_index++)
|
|
break;
|
|
}
|
|
if (MAX_GVSUBSCRIPTS < s_index)
|
|
{
|
|
mu_int_err(ERR_DBMAXNRSUBS, TRUE, TRUE, buff,
|
|
comp_length, top_key, top_len, (unsigned int)blk_levl);
|
|
mu_int_plen++; /* continuing, so compensate for mu_int_err decrement */
|
|
break;
|
|
}
|
|
mu_sub_list[s_index].index = 0;
|
|
for (; (start_index != s_index) && (0 != mu_sub_list[start_index].index); start_index++)
|
|
{
|
|
if (mu_sub_list[start_index].numeric)
|
|
{
|
|
b_index = mu_sub_list[start_index].index;
|
|
if (buff[b_index] > NEG_SUB)
|
|
{
|
|
b_index++;
|
|
while (buff[b_index])
|
|
{
|
|
memcpy(&check_vals, &buff[b_index], 1);
|
|
if (!mu_int_possub[check_vals.one][check_vals.two])
|
|
{
|
|
mu_int_err(ERR_DBBADNSUB, TRUE, TRUE,
|
|
buff, comp_length, top_key, top_len,
|
|
(unsigned int)blk_levl);
|
|
free(blk_base);
|
|
return FALSE;
|
|
}
|
|
b_index++;
|
|
}
|
|
} else
|
|
{
|
|
b_index++;
|
|
while ((STR_SUB_PREFIX != buff[b_index]) && (0 != buff[b_index]))
|
|
{
|
|
memcpy(&check_vals, &buff[b_index], 1);
|
|
if (!mu_int_negsub[check_vals.one][check_vals.two])
|
|
{
|
|
mu_int_err(ERR_DBBADNSUB, TRUE, TRUE,
|
|
buff, comp_length, top_key, top_len,
|
|
(unsigned int)blk_levl);
|
|
free(blk_base);
|
|
return FALSE;
|
|
}
|
|
b_index++;
|
|
}
|
|
if (STR_SUB_PREFIX != buff[b_index++] || (buff[b_index]))
|
|
{
|
|
mu_int_err(ERR_DBBADNSUB, TRUE, TRUE, buff, comp_length,
|
|
top_key, top_len, (unsigned int)blk_levl);
|
|
free(blk_base);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!level && !master_dir)
|
|
{
|
|
rval_len = rec_size - SIZEOF(rec_hdr) - key_size;
|
|
if (mu_int_data.max_rec_size < rval_len)
|
|
{
|
|
mu_int_err(ERR_DBDATAMX, TRUE, TRUE, buff, comp_length,
|
|
top_key, top_len, (unsigned int)blk_levl);
|
|
free(blk_base);
|
|
return FALSE;
|
|
}
|
|
span_key = buff + buff_length - SPAN_SUBS_LENGTH - 1;
|
|
max_allowed_key_size = mu_int_data.max_key_size;
|
|
if ((SPAN_SUBS_LENGTH < key_size + rec_cmpc) && (KEY_DELIMITER == *span_key++)
|
|
&& (SPAN_START_BYTE == *span_key))
|
|
{ /* Hidden subscript detected */
|
|
max_allowed_key_size += 4;
|
|
if (0 == (span_curr_blk = SPAN_GVSUBS2INT((span_subs *)span_key)))
|
|
{ /* First record of spanning node. Get the number blocks. */
|
|
ctrlbytes = key_base + key_size;
|
|
if (rec_top - ctrlbytes == 6)
|
|
{
|
|
GET_NSBCTRL(ctrlbytes, numsubs, gblsize);
|
|
} else
|
|
{
|
|
SSCANF((char *)ctrlbytes, "%d,%d", &tmp_numsubs, &gblsize);
|
|
numsubs = tmp_numsubs;
|
|
}
|
|
sndata->span_tot_blks = numsubs + 1;
|
|
sndata->span_node_sz = gblsize;
|
|
sndata->val_len = 0;
|
|
sndata->sn_type = SPAN_NODE;
|
|
sndata->span_prev_blk = 0;
|
|
sndata->span_blk_cnt = 1;
|
|
sndata->key_len = buff_length;
|
|
sndata->sn_cnt += 1;
|
|
memcpy(sndata->span_node_buf, buff, buff_length);
|
|
} else
|
|
{
|
|
switch (sndata->sn_type)
|
|
{
|
|
case SN_NOT: /*First block of the node-fragment*/
|
|
sndata->sn_type = SN_CHUNK;
|
|
sndata->span_prev_blk = span_curr_blk;
|
|
sndata->span_blk_cnt = 1;
|
|
sndata->span_frag_off = span_curr_blk;
|
|
sndata->key_len = buff_length;
|
|
/*Spanning node can never have 0 rval*/
|
|
sndata->span_node_sz = 0;
|
|
sndata->val_len = 0;
|
|
sndata->sn_cnt += 1;
|
|
memcpy(sndata->span_node_buf, buff, buff_length);
|
|
break;
|
|
case SPAN_NODE: /* Already in the spanning node */
|
|
if((sndata->span_prev_blk + 1) == span_curr_blk)
|
|
{ /*Logical continuity of block is present*/
|
|
sndata->span_prev_blk = span_curr_blk;
|
|
sndata->span_blk_cnt = sndata->span_blk_cnt + 1;
|
|
sndata->val_len += rval_len;
|
|
if(sndata->span_blk_cnt == sndata->span_tot_blks)
|
|
{ /* All the blocks of the spanning node are seen */
|
|
sndata->sn_type = SN_NOT;
|
|
sndata->sn_blk_cnt += sndata->span_blk_cnt;
|
|
}
|
|
if (sndata->val_len > sndata->span_node_sz)
|
|
{
|
|
mu_int_err(ERR_DBDATAMX, TRUE, TRUE,
|
|
sndata->span_node_buf,
|
|
sndata->key_len, top_key,
|
|
top_len,
|
|
(unsigned int)blk_levl);
|
|
free(blk_base);
|
|
return FALSE;
|
|
}
|
|
}
|
|
else { /* ERROR 1: There is discontinuity in the spanning node
|
|
* blocks; adjacent spanning block is missing
|
|
*/
|
|
mu_int_err(ERR_DBSPANGLOINCMP, TRUE, FALSE,
|
|
sndata->span_node_buf,
|
|
sndata->key_len, top_key,
|
|
top_len, (unsigned int)blk_levl);
|
|
sndata->sn_type = SN_NOT;
|
|
sndata->sn_blk_cnt += sndata->span_blk_cnt;
|
|
/* continuing, so compensate for mu_int_err decrement */
|
|
mu_int_plen++;
|
|
maxkey_errors++;
|
|
}
|
|
break;
|
|
case SN_CHUNK: /* Already in the spanning node fragment */
|
|
if((sndata->span_prev_blk + 1) == span_curr_blk)
|
|
{ /*Logical continuity of block is present*/
|
|
sndata->span_prev_blk = span_curr_blk;
|
|
sndata->span_blk_cnt = sndata->span_blk_cnt + 1;
|
|
}
|
|
else { /* ERROR 2: Unexpected spanning-node-block occurred in
|
|
* the middle of spanning-node fragment
|
|
*/
|
|
mu_int_err(ERR_DBSPANCHUNKORD, TRUE, FALSE,
|
|
sndata->span_node_buf,
|
|
sndata->key_len, top_key,
|
|
top_len, (unsigned int)blk_levl);
|
|
sndata->sn_type = SN_CHUNK;
|
|
sndata->span_prev_blk = span_curr_blk;
|
|
sndata->span_blk_cnt = 1;
|
|
sndata->span_frag_off = span_curr_blk;
|
|
sndata->key_len = buff_length;
|
|
memcpy(sndata->span_node_buf, buff, buff_length);
|
|
sndata->sn_blk_cnt += sndata->span_blk_cnt;
|
|
/* continuing, so compensate for mu_int_err decrement */
|
|
mu_int_plen++;
|
|
maxkey_errors++;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
} else if (sndata->sn_type)
|
|
{
|
|
if (SPAN_NODE == sndata->sn_type) /*INCOMPLETE SPANNING NODE*/
|
|
{ /* ERROR 1: There is discontinuity in the spanning node blocks;
|
|
* adjacent spanning block is missing
|
|
*/
|
|
mu_int_err(ERR_DBSPANGLOINCMP, TRUE, FALSE,
|
|
sndata->span_node_buf, sndata->key_len, top_key,
|
|
top_len, (unsigned int)blk_levl);
|
|
} else /*INCOMPLETE SPANNING NODE FRAGMENT*/
|
|
{ /* ERROR 2: Spanning-node-block occurred in the middle
|
|
* of non-spanning block
|
|
*/
|
|
mu_int_err(ERR_DBSPANCHUNKORD, TRUE, FALSE,
|
|
sndata->span_node_buf, sndata->key_len, top_key,
|
|
top_len, (unsigned int)blk_levl);
|
|
}
|
|
sndata->sn_blk_cnt += sndata->span_blk_cnt;
|
|
/* continuing, so compensate for mu_int_err decrement */
|
|
mu_int_plen++;
|
|
maxkey_errors++;
|
|
sndata->sn_type = SN_NOT;
|
|
}
|
|
if (key_size + rec_cmpc > max_allowed_key_size)
|
|
{
|
|
if (maxkey_errors < disp_maxkey_errors)
|
|
{
|
|
mu_int_err(ERR_DBGTDBMAX, TRUE, FALSE, buff, comp_length, top_key,
|
|
top_len, (unsigned int)blk_levl);
|
|
mu_int_plen++; /* continuing, so compensate for mu_int_err decrement */
|
|
maxkey_errors++;
|
|
} else
|
|
{
|
|
mu_int_errknt++;
|
|
maxkey_errors++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (level)
|
|
{
|
|
GET_LONG(child, ptr);
|
|
if (child < 0)
|
|
{
|
|
mu_int_err(ERR_DBPTRNOTPOS, TRUE, TRUE, buff, comp_length, top_key, top_len,
|
|
(unsigned int)blk_levl);
|
|
free(blk_base);
|
|
return FALSE;
|
|
}
|
|
if (child > mu_int_data.trans_hist.total_blks)
|
|
{
|
|
mu_int_err(ERR_DBPTRMX, TRUE, TRUE, buff, comp_length, top_key,
|
|
top_len, (unsigned int)blk_levl);
|
|
free(blk_base);
|
|
return FALSE;
|
|
}
|
|
if (!(child % mu_int_data.bplmap))
|
|
{
|
|
mu_int_err(ERR_DBBNPNTR, TRUE, TRUE, buff, comp_length, top_key, top_len,
|
|
(unsigned int)blk_levl);
|
|
free(blk_base);
|
|
return FALSE;
|
|
}
|
|
if (!muint_fast || (level > 1) || master_dir)
|
|
{
|
|
if (is_top)
|
|
mu_int_blk(child, level - 1, FALSE, buff, comp_length, top_key, top_len, pstar);
|
|
else
|
|
mu_int_blk(child, level - 1, FALSE, old_buff, comp_length, buff, buff_length, pstar);
|
|
} else
|
|
{
|
|
if (!bml_busy(child, mu_int_locals))
|
|
{
|
|
mu_int_offset[mu_int_plen]=0;
|
|
mu_int_path[mu_int_plen++]=child;
|
|
mu_int_err(ERR_DBBDBALLOC, TRUE, TRUE, old_buff, comp_length, buff, buff_length,
|
|
(unsigned int)((blk_hdr_ptr_t)ptr)->levl);
|
|
mu_int_plen--;
|
|
free(blk_base);
|
|
return FALSE;
|
|
}
|
|
mu_int_blks[0]++;
|
|
}
|
|
} else
|
|
{
|
|
if (master_dir)
|
|
{
|
|
for (c0 = c_base = (uchar_ptr_t)rec_base + SIZEOF(rec_hdr); *c0; c0++);
|
|
GET_LONG(root_pointer, ((block_id *)(c0 + 2)));
|
|
if (root_pointer > mu_int_data.trans_hist.total_blks || root_pointer < 2)
|
|
{ /* 0=master map, 1=dir root*/
|
|
mu_int_err(ERR_DBBADPNTR, TRUE, TRUE, buff, comp_length, top_key,
|
|
top_len, (unsigned int)blk_levl);
|
|
mu_int_plen++; /* continuing, so compensate for mu_int_err decrement */
|
|
}
|
|
c1 = temp_buff;
|
|
if (rec_cmpc)
|
|
for (c2 = muint_temp_buff, cc = 0; *c2 && (cc < rec_cmpc); cc++)
|
|
*c1++ = *c2++;
|
|
for (; c_base < c0;)
|
|
*c1++ = *c_base++;
|
|
*c1 = 0;
|
|
assert(SIZEOF(muint_temp_buff) == SIZEOF(temp_buff));
|
|
memcpy(muint_temp_buff, temp_buff, SIZEOF(temp_buff));
|
|
if (muint_key)
|
|
{
|
|
if (muint_end_key) /* range */
|
|
{
|
|
len = (int)(c1 - temp_buff + 1);
|
|
if ((0 < memcmp(muint_start_key->base, temp_buff, len < muint_start_keyend ?
|
|
len : muint_start_keyend))
|
|
|| (0 > memcmp(muint_end_key->base, temp_buff, len < muint_end_keyend ?
|
|
len : muint_end_keyend)))
|
|
continue;
|
|
} else
|
|
{
|
|
if (((muint_start_keyend - 1) != (c1 - temp_buff))
|
|
|| (memcmp(muint_start_key->base, temp_buff, muint_start_keyend)))
|
|
continue;
|
|
}
|
|
}
|
|
trees_tail->link = (global_list *)malloc(SIZEOF(global_list));
|
|
trees_tail = trees_tail->link;
|
|
trees_tail->link = 0;
|
|
trees_tail->root = root_pointer;
|
|
|
|
memcpy(trees_tail->path, mu_int_path, SIZEOF(block_id) * (MAX_BT_DEPTH + 1));
|
|
memcpy(trees_tail->offset, mu_int_offset, SIZEOF(uint4) * (MAX_BT_DEPTH + 1));
|
|
assert(SIZEOF(trees_tail->key) == SIZEOF(muint_temp_buff));
|
|
memcpy(trees_tail->key, muint_temp_buff, SIZEOF(muint_temp_buff));
|
|
trees_tail->keysize = STRLEN((char *)muint_temp_buff);
|
|
hdr_len = SIZEOF(rec_hdr) + STRLEN(trees_tail->key) + 2 - rec_cmpc; /* We cannot use
|
|
mid_len() which expects mident_fixed structure */
|
|
/* +2 in the above hdr_len calculation is to take into account
|
|
two \0's after the end of the key
|
|
*/
|
|
if (rec_size > hdr_len + SIZEOF(block_id))
|
|
{
|
|
subrec_ptr = get_spec((sm_uc_ptr_t)rec_base + hdr_len + SIZEOF(block_id),
|
|
(int)(rec_size - (hdr_len + SIZEOF(block_id))), COLL_SPEC);
|
|
if (subrec_ptr)
|
|
{
|
|
trees_tail->nct = *(subrec_ptr + COLL_NCT_OFFSET);
|
|
trees_tail->act = *(subrec_ptr + COLL_ACT_OFFSET);
|
|
trees_tail->ver = *(subrec_ptr + COLL_VER_OFFSET);
|
|
} else
|
|
{
|
|
trees_tail->nct = 0;
|
|
trees_tail->act = 0;
|
|
trees_tail->ver = 0;
|
|
}
|
|
} else
|
|
{
|
|
trees_tail->nct = 0;
|
|
trees_tail->act = mu_int_data.def_coll;
|
|
trees_tail->ver = mu_int_data.def_coll_ver;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (top_len)
|
|
{
|
|
if ((cmcc = memvcmp(buff, comp_length, top_key, top_len)) >= 0)
|
|
{
|
|
if ((0 != cmcc) || level)
|
|
{
|
|
mu_int_err(ERR_DBKEYGTIND, TRUE, TRUE, buff, comp_length, top_key, top_len,
|
|
(unsigned int)blk_levl);
|
|
free(blk_base);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
mu_int_plen--;
|
|
free(blk_base);
|
|
return TRUE;
|
|
}
|