fis-gtm/sr_port/mu_split.c

690 lines
27 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. *
* *
****************************************************************/
/***********************************************************************************
mu_split.c:
Split a block on the boundary of fill_factor.
Split ancestors's if necessary. Ancestor's split will also honor fill_factor
***********************************************************************************/
#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 "gdsblkops.h"
#include "gdskill.h"
#include "gdscc.h"
#include "jnl.h"
#include "copy.h"
#include "muextr.h"
#include "mu_reorg.h"
/* Include prototypes */
#include "t_qread.h"
#include "t_write.h"
#include "t_write_root.h"
#include "t_create.h"
#include "mupip_reorg.h"
GBLREF gv_namehead *gv_target;
GBLREF sgmnt_data_ptr_t cs_data;
GBLREF gd_region *gv_cur_region;
GBLREF char *update_array, *update_array_ptr;
GBLREF uint4 update_array_size; /* for the BLK_* macros */
GBLREF cw_set_element cw_set[];
GBLREF unsigned char cw_set_depth;
GBLREF unsigned int t_tries;
GBLREF gv_key *gv_currkey;
GBLREF gv_key *gv_currkey_next_reorg;
static int4 const zeroes = 0;
enum cdb_sc locate_block_split_point(sm_uc_ptr_t blk_base, int level, int cur_blk_size, int max_fill,
int *last_rec_size, unsigned char last_key[], int *last_keysz, int *top_off);
/***********************************************************************************************
Input Parameters:
cur_level: Working block's level
d_max_fill: Database fill factor
i_max_fill: Index fill factor
Output Parameters:
blks_created: how many new blocks are created
lvls_increased : How much level is increased
Input/Output Parameters:
gv_target: History of working block
Here it is assumed that i_max_fill or, d_max_fill is strictly less than block size.
Returns:
cdb_sc_normal: if successful
cdb_sc status otherwise
************************************************************************************************/
enum cdb_sc mu_split(int cur_level, int i_max_fill, int d_max_fill, int *blks_created, int *lvls_increased)
{
boolean_t first_copy, new_rtblk_star_only, create_root = FALSE, split_required, insert_in_left;
unsigned char curr_prev_key[MAX_KEY_SZ+1], new_blk1_last_key[MAX_KEY_SZ+1];
unsigned short temp_ushort;
int rec_size, new_ins_keycmpc, tkeycmpc, new_ances_currkeycmpc, old_ances_currkeycmpc;
int tmp_cmpc;
block_index left_index, right_index;
block_offset ins_off, ins_off2;
int level;
int new_ins_keysz, new_ances_currkeysz, new_blk1_last_keysz, newblk2_first_keysz, next_gv_currkeysz;
int old_ances_currkeylen, new_ins_keylen, new_ances_currkeylen, tkeylen, newblk2_first_keylen;
int old_blk1_last_rec_size, old_blk1_sz, save_blk_piece_len, old_right_piece_len;
int delta, max_fill;
enum cdb_sc status;
int blk_seg_cnt, blk_size, new_leftblk_top_off;
block_id allocation_clue;
sm_uc_ptr_t rPtr1, rPtr2, rec_base, key_base, next_gv_currkey,
bn_ptr1, bn_ptr2, save_blk_piece,
old_blk_after_currec, ances_currkey,
old_blk1_base,
new_blk1_top, new_blk2_top,
new_blk2_frec_base, new_blk2_rem,
newblk2_first_key, new_ins_key;
blk_segment *bs_ptr1, *bs_ptr2;
cw_set_element *cse;
rec_hdr_ptr_t star_rec_hdr, new_rec_hdr1a, new_rec_hdr1b, new_rec_hdr2, root_hdr;
blk_hdr_ptr_t blk_hdr_ptr;
blk_size = cs_data->blk_size;
CHECK_AND_RESET_UPDATE_ARRAY; /* reset update_array_ptr to update_array */
BLK_ADDR(star_rec_hdr, SIZEOF(rec_hdr), rec_hdr);
star_rec_hdr->rsiz = BSTAR_REC_SIZE;
SET_CMPC(star_rec_hdr, 0);
level = cur_level;
max_fill = (0 == level)? d_max_fill : i_max_fill;
/* -------------------
* Split working block.
* -------------------
* new_blk1_last_key = last key of the new working block after split
* new_blk1_last_keysz = size of new_blk1_last_key
* old_blk1_last_rec_size = last record size of the new working block after split (for old block)
* new_blk2_frec_base = base of first record of right block created after split
* newblk2_first_key = first key of new block created after split
* newblk2_first_keysz = size of newblk2_first_key
* new_blk2_rem = pointer to new block to be created after split exclude 1st record header + key
*/
blk_hdr_ptr = (blk_hdr_ptr_t)(gv_target->hist.h[level].buffaddr);
old_blk1_base = (sm_uc_ptr_t)blk_hdr_ptr;
old_blk1_sz = blk_hdr_ptr->bsiz;
new_blk2_top = old_blk1_base + old_blk1_sz;
if (cdb_sc_normal != (status = locate_block_split_point (old_blk1_base, level, old_blk1_sz, max_fill,
&old_blk1_last_rec_size, new_blk1_last_key, &new_blk1_last_keysz, &new_leftblk_top_off)))
{
assert(t_tries < CDB_STAGNATE);
return cdb_sc_blkmod;
}
if (new_leftblk_top_off + BSTAR_REC_SIZE >= old_blk1_sz)
/* Avoid split to create a small right sibling. Note this should not happen often when tolerance is high */
return cdb_sc_oprnotneeded;
old_right_piece_len = old_blk1_sz - new_leftblk_top_off;
new_blk2_frec_base = old_blk1_base + new_leftblk_top_off;
BLK_ADDR(newblk2_first_key, gv_cur_region->max_rec_size + 1, unsigned char);
READ_RECORD(level, new_blk2_frec_base, tkeycmpc, rec_size, newblk2_first_key, newblk2_first_keylen, status);
if (cdb_sc_normal != status) /* restart for cdb_sc_starrecord too, because we eliminated the possibility already */
{
assert(t_tries < CDB_STAGNATE);
return cdb_sc_blkmod;
}
memcpy(newblk2_first_key, &new_blk1_last_key[0], tkeycmpc); /* copy the compressed key piece */
new_blk2_rem = new_blk2_frec_base + SIZEOF(rec_hdr) + newblk2_first_keylen;
newblk2_first_keysz = newblk2_first_keylen + tkeycmpc;
/* gv_currkey_next_reorg will be saved for next iteration in mu_reorg */
next_gv_currkey = newblk2_first_key;
next_gv_currkeysz = newblk2_first_keysz;
BLK_ADDR(new_rec_hdr1b, SIZEOF(rec_hdr), rec_hdr);
new_rec_hdr1b->rsiz = rec_size + tkeycmpc;
SET_CMPC(new_rec_hdr1b, 0);
/* Create new split piece, we already know that this will not be *-rec only.
* Note that this has to be done BEFORE modifying working block as building this buffer relies on the
* working block to be pinned which is possible only if this cw-set-element is created ahead of that
* of the working block (since order in which blocks are built is the order in which cses are created).
*/
BLK_INIT(bs_ptr2, bs_ptr1);
BLK_SEG(bs_ptr2, (sm_uc_ptr_t)new_rec_hdr1b, SIZEOF(rec_hdr));
BLK_SEG(bs_ptr2, newblk2_first_key, newblk2_first_keysz);
BLK_SEG(bs_ptr2, new_blk2_rem, new_blk2_top - new_blk2_rem);
if (!BLK_FINI(bs_ptr2, bs_ptr1))
{
assert(t_tries < CDB_STAGNATE);
return cdb_sc_blkmod;
}
allocation_clue = ALLOCATION_CLUE(cs_data->trans_hist.total_blks);
right_index = t_create(allocation_clue++, (unsigned char *)bs_ptr1, 0, 0, level);
(*blks_created)++;
/* Modify working block removing split piece */
BLK_INIT(bs_ptr2, bs_ptr1);
if (0 == level)
{
BLK_SEG(bs_ptr2, old_blk1_base + SIZEOF(blk_hdr), new_leftblk_top_off - SIZEOF(blk_hdr));
}
else
{
BLK_SEG(bs_ptr2, old_blk1_base + SIZEOF(blk_hdr),
new_leftblk_top_off - SIZEOF(blk_hdr) - old_blk1_last_rec_size);
BLK_SEG(bs_ptr2, (sm_uc_ptr_t)star_rec_hdr, SIZEOF(rec_hdr) );
BLK_ADDR(bn_ptr1, SIZEOF(block_id), unsigned char);
memcpy(bn_ptr1, old_blk1_base + new_leftblk_top_off - SIZEOF(block_id), SIZEOF(block_id));
BLK_SEG(bs_ptr2, bn_ptr1, SIZEOF(block_id));
}
if ( !BLK_FINI(bs_ptr2, bs_ptr1))
{
assert(t_tries < CDB_STAGNATE);
return cdb_sc_blkmod;
}
t_write(&gv_target->hist.h[level], (unsigned char *)bs_ptr1, 0, 0, level, FALSE, TRUE, GDS_WRITE_KILLTN);
/*
----------------------------------------------------------------------------
Modify ancestor block for the split in current level.
new_ins_key = new key to be inserted in parent because of split in child
new_ins_key will be inserted after gv_target->hist.h[level].prev_rec and
before gv_target->hist.h[level].curr_rec
new_ins_keysz = size of new_ins_key
Note: A restriction of the algorithm is to have current key and new_ins_key
in the same block, either left or, new right block
----------------------------------------------------------------------------
*/
BLK_ADDR(new_ins_key, new_blk1_last_keysz, unsigned char);
memcpy(new_ins_key, &new_blk1_last_key[0], new_blk1_last_keysz);
new_ins_keysz = new_blk1_last_keysz;
for(;;) /* ========== loop through ancestors as necessary ======= */
{
level ++;
max_fill = i_max_fill;
/*
old_blk_after_currec = remaining of current block after currec
ances_currkey = old real value of currkey in ancestor block
*/
blk_hdr_ptr = (blk_hdr_ptr_t)(gv_target->hist.h[level].buffaddr);
old_blk1_base = (sm_uc_ptr_t)blk_hdr_ptr;
old_blk1_sz = blk_hdr_ptr->bsiz;
new_blk2_top = old_blk1_base + old_blk1_sz;
rec_base = old_blk1_base + gv_target->hist.h[level].curr_rec.offset;
GET_RSIZ(rec_size, rec_base);
old_blk_after_currec = rec_base + rec_size;
old_ances_currkeycmpc = EVAL_CMPC((rec_hdr_ptr_t)rec_base);
old_ances_currkeylen = rec_size - BSTAR_REC_SIZE;
if (INVALID_RECORD(level, rec_size, old_ances_currkeylen, old_ances_currkeycmpc))
{
assert(t_tries < CDB_STAGNATE);
return cdb_sc_blkmod;
}
if (0 == old_ances_currkeylen)
{
if (0 != old_ances_currkeycmpc)
{
assert(t_tries < CDB_STAGNATE);
return cdb_sc_blkmod;
}
new_ances_currkeycmpc = new_ances_currkeylen = 0;
}
else
{
BLK_ADDR(ances_currkey, gv_cur_region->max_rec_size + 1, unsigned char);
key_base = rec_base + SIZEOF(rec_hdr);
}
new_ances_currkeysz = old_ances_currkeycmpc + old_ances_currkeylen;
if (SIZEOF(blk_hdr) != gv_target->hist.h[level].curr_rec.offset) /* cur_rec is not first key */
{
if (cdb_sc_normal != (status = gvcst_expand_any_key(old_blk1_base,
old_blk1_base + gv_target->hist.h[level].curr_rec.offset,
&curr_prev_key[0], &rec_size, &tkeylen, &tkeycmpc, NULL)))
{
assert(t_tries < CDB_STAGNATE);
return cdb_sc_blkmod;
}
if (old_ances_currkeycmpc)
memcpy(ances_currkey, &curr_prev_key[0], old_ances_currkeycmpc);
}
if (old_ances_currkeylen)
{
memcpy(ances_currkey + old_ances_currkeycmpc, key_base, old_ances_currkeylen);
GET_CMPC(new_ances_currkeycmpc, new_ins_key, ances_currkey);
new_ances_currkeylen = new_ances_currkeysz - new_ances_currkeycmpc;
}
if (SIZEOF(blk_hdr) != gv_target->hist.h[level].curr_rec.offset)
{
/* new_ins_key will be inseted after curr_prev_key */
GET_CMPC(new_ins_keycmpc, &curr_prev_key[0], new_ins_key);
}
else
new_ins_keycmpc = 0; /* new_ins_key will be the 1st key */
new_ins_keylen = new_ins_keysz - new_ins_keycmpc ;
delta = BSTAR_REC_SIZE + new_ins_keylen - old_ances_currkeylen + new_ances_currkeylen;
if (old_blk1_sz + delta > blk_size - cs_data->reserved_bytes) /* split required */
{
split_required = TRUE;
if (level == gv_target->hist.depth)
{
create_root = TRUE;
if (MAX_BT_DEPTH - 1 <= level) /* maximum level reached */
return cdb_sc_maxlvl;
}
if (max_fill + BSTAR_REC_SIZE > old_blk1_sz)
{
if (SIZEOF(blk_hdr) + BSTAR_REC_SIZE == old_blk1_sz)
return cdb_sc_oprnotneeded; /* Improve code to avoid this */
max_fill = old_blk1_sz - BSTAR_REC_SIZE;
}
status = locate_block_split_point(old_blk1_base, level, old_blk1_sz, max_fill,
&old_blk1_last_rec_size, new_blk1_last_key, &new_blk1_last_keysz, &new_leftblk_top_off);
if (cdb_sc_normal != status || new_leftblk_top_off >= old_blk1_sz
|| 0 == new_blk1_last_keysz)
{
assert(t_tries < CDB_STAGNATE);
return cdb_sc_blkmod;
}
assert(BSTAR_REC_SIZE != old_blk1_last_rec_size);
old_right_piece_len = old_blk1_sz - new_leftblk_top_off;
new_blk2_frec_base = new_blk1_top = old_blk1_base + new_leftblk_top_off;
if (BSTAR_REC_SIZE == old_right_piece_len)
new_rtblk_star_only = TRUE;
else
new_rtblk_star_only = FALSE;
if (new_leftblk_top_off == gv_target->hist.h[level].curr_rec.offset)
{
/* inserted key will be the first record of new right block */
new_ins_keylen = new_ins_keysz;
new_ins_keycmpc = 0;
}
else
/* process 1st record of new right block */
{
BLK_ADDR(newblk2_first_key, gv_cur_region->max_rec_size + 1, unsigned char);
READ_RECORD(level, new_blk2_frec_base, tkeycmpc, rec_size,
newblk2_first_key, newblk2_first_keylen, status);
if (cdb_sc_normal == status)
{
memcpy(newblk2_first_key, &new_blk1_last_key[0], tkeycmpc); /* compressed piece */
new_blk2_rem = new_blk2_frec_base + SIZEOF(rec_hdr) + newblk2_first_keylen;
newblk2_first_keysz = newblk2_first_keylen + tkeycmpc;
BLK_ADDR(new_rec_hdr2, SIZEOF(rec_hdr), rec_hdr);
new_rec_hdr2->rsiz = newblk2_first_keysz + BSTAR_REC_SIZE;
SET_CMPC(new_rec_hdr2, 0);
}
else if (cdb_sc_starrecord != status || !new_rtblk_star_only)
{
assert(t_tries < CDB_STAGNATE);
return cdb_sc_blkmod;
}
}
/* else gv_target->hist.h[level].curr_rec will be newblk2_first_key */
if (new_leftblk_top_off > gv_target->hist.h[level].curr_rec.offset +
old_ances_currkeylen + BSTAR_REC_SIZE)
{
/* in this case prev_rec (if exists), new key and curr_rec should go into left block */
if (new_leftblk_top_off + delta - old_blk1_last_rec_size + BSTAR_REC_SIZE
<= blk_size - cs_data->reserved_bytes)
insert_in_left = TRUE;
else
{
/* cannot handle it now */
return cdb_sc_oprnotneeded;
}
}
else if (new_leftblk_top_off < gv_target->hist.h[level].curr_rec.offset +
old_ances_currkeylen + BSTAR_REC_SIZE)
{
/* if gv_target->hist.h[level].curr_rec is the first key in old_blk1
then in new right block,
new_ins_key will be the 1st record key and
curr_rec will be 2nd record and
there will be no prev_rec in right block.
Else (if curr_rec is not first key)
there will be some records before new_ins_key, at least prev_rec */
delta = (int)(BSTAR_REC_SIZE + new_ins_keylen
- old_ances_currkeylen + new_ances_currkeylen
+ ((0 == new_ins_keycmpc) ? 0 : (EVAL_CMPC((rec_hdr_ptr_t)new_blk2_frec_base))));
if (SIZEOF(blk_hdr) + old_right_piece_len + delta <= blk_size - cs_data->reserved_bytes)
{
insert_in_left = FALSE;
if (new_leftblk_top_off + BSTAR_REC_SIZE >= old_blk1_sz)
{
/* cannot handle it now */
return cdb_sc_oprnotneeded;
}
}
else
{
/* cannot handle it now */
return cdb_sc_oprnotneeded;
}
}
else
{
/* in this case prev_rec (if exists), new key and curr_rec should go into left block
and curr_rec will be the last record (*-key) of left new block */
delta = BSTAR_REC_SIZE + new_ins_keylen;
if (new_leftblk_top_off + delta <= blk_size - cs_data->reserved_bytes)
insert_in_left = TRUE;
else
{
/* cannot handle it now */
return cdb_sc_oprnotneeded;
}
}
} /* end if split required */
else
split_required = FALSE;
BLK_ADDR(new_rec_hdr1a, SIZEOF(rec_hdr), rec_hdr);
new_rec_hdr1a->rsiz = BSTAR_REC_SIZE + new_ins_keylen;
SET_CMPC(new_rec_hdr1a, new_ins_keycmpc);
BLK_ADDR(new_rec_hdr1b, SIZEOF(rec_hdr), rec_hdr);
new_rec_hdr1b->rsiz = BSTAR_REC_SIZE + new_ances_currkeylen;
SET_CMPC(new_rec_hdr1b, new_ances_currkeycmpc);
BLK_ADDR(bn_ptr1, SIZEOF(block_id), unsigned char);
/* child pointer of ances_currkey */
memcpy(bn_ptr1, old_blk1_base + gv_target->hist.h[level].curr_rec.offset +
SIZEOF(rec_hdr) + old_ances_currkeylen, SIZEOF(block_id));
if (!split_required)
{
/* LEFT part of old BLOCK */
BLK_INIT(bs_ptr2, bs_ptr1);
if (SIZEOF(blk_hdr) < gv_target->hist.h[level].curr_rec.offset)
{
BLK_SEG(bs_ptr2, old_blk1_base + SIZEOF(blk_hdr),
gv_target->hist.h[level].curr_rec.offset - SIZEOF(blk_hdr));
first_copy = FALSE;
} else
first_copy = TRUE;
BLK_SEG(bs_ptr2, (sm_uc_ptr_t)new_rec_hdr1a, SIZEOF(rec_hdr));
BLK_SEG(bs_ptr2, new_ins_key + new_ins_keycmpc, new_ins_keylen);
BLK_SEG(bs_ptr2, bn_ptr1, SIZEOF(block_id));
BLK_SEG(bs_ptr2, (sm_uc_ptr_t)new_rec_hdr1b, SIZEOF(rec_hdr));
if (0 < new_ances_currkeylen)
BLK_SEG(bs_ptr2, ances_currkey + new_ances_currkeycmpc, new_ances_currkeylen);
ins_off = blk_seg_cnt;
BLK_SEG(bs_ptr2, (unsigned char *)&zeroes, SIZEOF(block_id));
if (0 < old_blk1_base + old_blk1_sz - old_blk_after_currec)
BLK_SEG(bs_ptr2, old_blk_after_currec, old_blk1_base + old_blk1_sz - old_blk_after_currec);
if (!BLK_FINI(bs_ptr2, bs_ptr1))
{
assert(t_tries < CDB_STAGNATE);
return cdb_sc_blkmod;
}
t_write(&gv_target->hist.h[level], (unsigned char *)bs_ptr1, ins_off, right_index,
level, first_copy, FALSE, GDS_WRITE_KILLTN);
break;
}
/* if SPLIT REQUIRED */
if (insert_in_left) /* new_ins_key will go to left block */
{
/* LEFT BLOCK */
BLK_INIT(bs_ptr2, bs_ptr1);
if (SIZEOF(blk_hdr) < gv_target->hist.h[level].curr_rec.offset)
{
BLK_SEG(bs_ptr2, old_blk1_base + SIZEOF(blk_hdr),
gv_target->hist.h[level].curr_rec.offset - SIZEOF(blk_hdr));
first_copy = FALSE;
} else
first_copy = TRUE;
BLK_SEG(bs_ptr2, (sm_uc_ptr_t)new_rec_hdr1a, SIZEOF(rec_hdr));
BLK_SEG(bs_ptr2, new_ins_key + new_ins_keycmpc, new_ins_keylen);
BLK_SEG(bs_ptr2, bn_ptr1, SIZEOF(block_id));
if (old_blk_after_currec < new_blk1_top) /* curr_rec is not the last record of new left block */
{
BLK_SEG(bs_ptr2, (sm_uc_ptr_t)new_rec_hdr1b, SIZEOF(rec_hdr));
BLK_SEG(bs_ptr2, ances_currkey + new_ances_currkeycmpc, new_ances_currkeylen);
ins_off = blk_seg_cnt;
BLK_SEG(bs_ptr2, (unsigned char *)&zeroes, SIZEOF(block_id));
save_blk_piece_len = (int)(new_blk1_top - old_blk1_last_rec_size - old_blk_after_currec);
if (0 < save_blk_piece_len )
{
if (old_blk_after_currec + save_blk_piece_len >= new_blk2_top)
{
assert(t_tries < CDB_STAGNATE);
return cdb_sc_blkmod;
}
BLK_ADDR(save_blk_piece, save_blk_piece_len, unsigned char);
memcpy(save_blk_piece, old_blk_after_currec, save_blk_piece_len);
BLK_SEG(bs_ptr2, save_blk_piece, save_blk_piece_len);
}
BLK_SEG(bs_ptr2, (sm_uc_ptr_t)star_rec_hdr, SIZEOF(rec_hdr) );
BLK_ADDR(bn_ptr2, SIZEOF(block_id), unsigned char);
memcpy(bn_ptr2, new_blk1_top - SIZEOF(block_id), SIZEOF(block_id));
BLK_SEG(bs_ptr2, bn_ptr2, SIZEOF(block_id));
} else
{
assert (old_blk_after_currec == new_blk1_top);
BLK_SEG(bs_ptr2, (sm_uc_ptr_t)star_rec_hdr, SIZEOF(rec_hdr) );
ins_off = blk_seg_cnt;
BLK_SEG(bs_ptr2, (unsigned char *)&zeroes, SIZEOF(block_id));
}
if (!BLK_FINI(bs_ptr2, bs_ptr1))
{
assert(t_tries < CDB_STAGNATE);
return cdb_sc_blkmod;
}
if (create_root)
left_index = t_create(allocation_clue++, (unsigned char *)bs_ptr1, ins_off, right_index, level);
else
t_write(&gv_target->hist.h[level], (unsigned char *)bs_ptr1, ins_off, right_index,
level, first_copy, FALSE, GDS_WRITE_KILLTN);
/* RIGHT BLOCK */
BLK_INIT(bs_ptr2, bs_ptr1);
if (new_rtblk_star_only)
{
BLK_SEG(bs_ptr2, (sm_uc_ptr_t)star_rec_hdr, SIZEOF(rec_hdr) );
BLK_ADDR(bn_ptr2, SIZEOF(block_id), unsigned char);
memcpy(bn_ptr2, new_blk2_top - SIZEOF(block_id), SIZEOF(block_id));
BLK_SEG(bs_ptr2, bn_ptr2, SIZEOF(block_id));
} else
{
BLK_SEG(bs_ptr2, (sm_uc_ptr_t)new_rec_hdr2, SIZEOF(rec_hdr));
BLK_SEG(bs_ptr2, newblk2_first_key, newblk2_first_keysz);
save_blk_piece_len = (int)(new_blk2_top - new_blk2_rem);
if (0 > save_blk_piece_len)
{
assert(t_tries < CDB_STAGNATE);
return cdb_sc_blkmod;
}
BLK_ADDR(save_blk_piece, save_blk_piece_len, unsigned char);
memcpy(save_blk_piece, new_blk2_rem, save_blk_piece_len);
BLK_SEG(bs_ptr2, save_blk_piece, new_blk2_top - new_blk2_rem );
}
if (!BLK_FINI(bs_ptr2, bs_ptr1))
{
assert(t_tries < CDB_STAGNATE);
return cdb_sc_blkmod;
}
right_index = t_create(allocation_clue++, (unsigned char *)bs_ptr1, 0, 0, level);
(*blks_created)++;
} /* end if insert_in_left */
else
{ /* new_ins_key to be inserted in right block */
/* LEFT BLOCK */
BLK_INIT(bs_ptr2, bs_ptr1);
save_blk_piece_len = (int)(new_leftblk_top_off - SIZEOF(blk_hdr) - old_blk1_last_rec_size);
if ((old_blk1_base + SIZEOF(blk_hdr) + save_blk_piece_len >= new_blk2_top) || (0 > save_blk_piece_len))
{
assert(t_tries < CDB_STAGNATE);
return cdb_sc_blkmod;
}
BLK_ADDR(save_blk_piece, save_blk_piece_len, unsigned char);
memcpy(save_blk_piece, old_blk1_base + SIZEOF(blk_hdr), save_blk_piece_len);
BLK_SEG(bs_ptr2, save_blk_piece, save_blk_piece_len);
BLK_SEG(bs_ptr2, (sm_uc_ptr_t)star_rec_hdr, SIZEOF(rec_hdr) );
BLK_ADDR(bn_ptr2, SIZEOF(block_id), unsigned char);
memcpy(bn_ptr2, old_blk1_base + new_leftblk_top_off - SIZEOF(block_id), SIZEOF(block_id));
BLK_SEG(bs_ptr2, bn_ptr2, SIZEOF(block_id));
if ( !BLK_FINI(bs_ptr2, bs_ptr1))
{
assert(t_tries < CDB_STAGNATE);
return cdb_sc_blkmod;
}
if (create_root)
left_index = t_create(allocation_clue++, (unsigned char *)bs_ptr1, 0, 0, level);
else
t_write(&gv_target->hist.h[level], (unsigned char *)bs_ptr1, 0, 0,
level, TRUE, TRUE, GDS_WRITE_KILLTN);
/* RIGHT BLOCK */
BLK_INIT(bs_ptr2, bs_ptr1);
if (new_leftblk_top_off < gv_target->hist.h[level].curr_rec.offset)
{ /* anything before curr_rec */
BLK_SEG(bs_ptr2, (sm_uc_ptr_t)new_rec_hdr2, SIZEOF(rec_hdr));
BLK_SEG(bs_ptr2, newblk2_first_key, newblk2_first_keysz);
save_blk_piece_len = (int)(gv_target->hist.h[level].curr_rec.offset -
new_leftblk_top_off - (new_blk2_rem - new_blk2_frec_base));
if ((new_blk2_rem + save_blk_piece_len >= new_blk2_top) || (0 > save_blk_piece_len))
{
assert(t_tries < CDB_STAGNATE);
return cdb_sc_blkmod;
}
BLK_ADDR(save_blk_piece, save_blk_piece_len, unsigned char);
memcpy(save_blk_piece, new_blk2_rem, save_blk_piece_len);
BLK_SEG(bs_ptr2, save_blk_piece, save_blk_piece_len);
}
/* Following else if may not be necessary. But I wanted it to be safe:Layek:10/3/2000 */
else if (new_leftblk_top_off > gv_target->hist.h[level].curr_rec.offset)
{
assert(t_tries < CDB_STAGNATE);
return cdb_sc_blkmod;
}
BLK_SEG(bs_ptr2, (sm_uc_ptr_t)new_rec_hdr1a, SIZEOF(rec_hdr));
BLK_SEG(bs_ptr2, new_ins_key + new_ins_keycmpc, new_ins_keylen);
BLK_SEG(bs_ptr2, bn_ptr1, SIZEOF(block_id));
BLK_SEG(bs_ptr2, (sm_uc_ptr_t)new_rec_hdr1b, SIZEOF(rec_hdr));
BLK_SEG(bs_ptr2, ances_currkey + new_ances_currkeycmpc, new_ances_currkeylen);
ins_off = blk_seg_cnt;
BLK_SEG(bs_ptr2, (unsigned char *)&zeroes, SIZEOF(block_id));
save_blk_piece_len = (int)(new_blk2_top - old_blk_after_currec);
if (0 < save_blk_piece_len)
{
BLK_ADDR(save_blk_piece, save_blk_piece_len, unsigned char);
memcpy(save_blk_piece, old_blk_after_currec, save_blk_piece_len);
BLK_SEG(bs_ptr2, save_blk_piece, save_blk_piece_len);
}
if (!BLK_FINI(bs_ptr2, bs_ptr1))
{
assert(t_tries < CDB_STAGNATE);
return cdb_sc_blkmod;
}
right_index = t_create(allocation_clue++, (unsigned char *)bs_ptr1, ins_off, right_index, level);
(*blks_created)++;
} /* endif new_ins_key insered in right block */
BLK_ADDR(new_ins_key, new_blk1_last_keysz, unsigned char);
memcpy(new_ins_key, &new_blk1_last_key[0], new_blk1_last_keysz);
new_ins_keysz = new_blk1_last_keysz;
if (create_root)
{
BLK_ADDR(root_hdr, SIZEOF(rec_hdr), rec_hdr);
root_hdr->rsiz = BSTAR_REC_SIZE + new_ins_keysz;
SET_CMPC(root_hdr, 0);
BLK_INIT(bs_ptr2, bs_ptr1);
BLK_SEG(bs_ptr2, (sm_uc_ptr_t)root_hdr, SIZEOF(rec_hdr));
BLK_SEG(bs_ptr2, new_ins_key, new_ins_keysz);
ins_off = blk_seg_cnt;
BLK_SEG(bs_ptr2, (unsigned char *)&zeroes, SIZEOF(block_id));
BLK_SEG(bs_ptr2, (sm_uc_ptr_t)star_rec_hdr, SIZEOF(rec_hdr) );
ins_off2 = blk_seg_cnt;
BLK_SEG(bs_ptr2, (unsigned char *)&zeroes, SIZEOF(block_id));
if (!BLK_FINI(bs_ptr2, bs_ptr1))
{
assert(t_tries < CDB_STAGNATE);
return cdb_sc_blkmod;
}
cse = t_write(&gv_target->hist.h[level], (unsigned char *)bs_ptr1, ins_off, left_index,
level + 1, TRUE, FALSE, GDS_WRITE_KILLTN);
t_write_root(ins_off2, right_index); /* create a sibling cw-set-element to store ins_off2/right_index */
(*lvls_increased)++;
break;
}
} /* ========== End loop through ancestors as necessary ======= */
/* gv_currkey_next_reorg for next iteration in mu_reorg */
memcpy(&gv_currkey_next_reorg->base[0], next_gv_currkey, next_gv_currkeysz);
gv_currkey_next_reorg->end = next_gv_currkeysz - 1;
return cdb_sc_normal;
}
/* end mu_split() */
/*
-------------------------------------------------------------------------
locate_block_split_point ():
This will split a block at a point given by fill factor
Input Parameter:
blk_base = base of the block
level = level of the block
cur_blk_size = size of the block
max_fill = maximum fill allowed for the block (max_fill < cur_blk_size)
Output Parameter:
last_rec_size = last record size of first piece
last_key = actual value of last key of the first block
last_keysz = size of actual value of last key of the first block
top_off = offset of left piece's top
Return :
cdb_sc_blkmod : If block is already modified
cdb_sc_normal : Otherwise (not necessary block is fine)
Note: After split
*top_off >= max_fill,
max_fill <= cur_blk_size
max_fill > SIZEOF(blk_hdr)
At least one record will be in left block after split
-------------------------------------------------------------------------
*/
enum cdb_sc locate_block_split_point(sm_uc_ptr_t blk_base, int level, int cur_blk_size, int max_fill,
int *last_rec_size, unsigned char last_key[], int *last_keysz, int *top_off)
{
unsigned short temp_ushort;
int tkeycmpc;
int rec_size;
enum cdb_sc status;
sm_uc_ptr_t rPtr1, rPtr2, rec_base;
*last_keysz = 0;
*top_off = SIZEOF(blk_hdr);
*last_rec_size = 0;
rec_base = blk_base + SIZEOF(blk_hdr);
while (*top_off < max_fill)
{
READ_RECORD(level, rec_base, tkeycmpc, rec_size, &last_key[0], *last_keysz, status);
*top_off += rec_size;
*last_keysz += tkeycmpc;
rec_base += rec_size;
*last_rec_size = rec_size;
if (cdb_sc_starrecord == status && *top_off == cur_blk_size)
return cdb_sc_normal;
else if (cdb_sc_normal != status)
{
assert(t_tries < CDB_STAGNATE);
return cdb_sc_blkmod; /* block became invalid */
}
}/* end of "while" loop */
if (*top_off > cur_blk_size || ((blk_hdr_ptr_t)blk_base)->levl != level ||
((blk_hdr_ptr_t)blk_base)->bsiz != cur_blk_size)
{
assert(t_tries < CDB_STAGNATE);
return cdb_sc_blkmod; /* block became invalid */
}
return cdb_sc_normal;
}