/************************************************************************************************* Input Parameters: gv_target: working block's history level : Level of working block and its right sibling d_blk_fill_size : Maximum fill allowed in a data block i_blk_fill_size : Maximum fill allowed in an index block Output Parameters: kill_set_ptr : List of blocks to be freed from LBM (already killed in mu_clsce) remove_rtsib : if right sibling was completely merged with working Returns: cdb_sc_normal on success Other wise error status *************************************************************************************************/ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_set_ptr, boolean_t *remove_rtsib) { boolean_t complete_merge = FALSE, old_ref_star_only = FALSE, new_rtsib_star_only = FALSE, star_only_merge = FALSE, blk2_ances_star_only = FALSE, delete_all_blk2_ances = TRUE, levelp_next_is_star, forward_process; unsigned char oldblk1_prev_key[MAX_KEY_SZ+1], old_levelp_cur_prev_key[MAX_KEY_SZ+1], old_levelp_cur_key[MAX_KEY_SZ+1]; /* keys in private memory */ unsigned short temp_ushort; int new_levelp_cur_cmpc, new_levelp_cur_next_cmpc, tkeycmpc, oldblk1_last_cmpc, newblk1_mid_cmpc, newblk1_last_cmpc; int levelp, level2; int old_blk1_sz, old_blk2_sz; int old_levelp_cur_prev_keysz, old_levelp_cur_keysz, old_levelp_cur_next_keysz, newblk1_last_keysz, newblk2_first_keysz, new_blk2_ances_first_keysz; int old_levelp_cur_keylen, new_levelp_cur_keylen, old_levelp_cur_next_keylen, new_levelp_cur_next_keylen, oldblk1_last_keylen, newblk1_last_keylen, newblk2_first_keylen; int rec_size, piece_len, tkeylen, old_levelp_rec_offset; int blk_seg_cnt, blk_size; uint4 save_t_err; enum cdb_sc status; sm_uc_ptr_t oldblk1_last_key, old_levelp_cur_next_key, newblk1_last_key, newblk2_first_key, new_blk2_ances_first_key; /* shared memory keys */ sm_uc_ptr_t rec_base, old_levelp_blk_base, bn_ptr1, bn_ptr2, blk2_ances_remain, old_blk1_base, old_blk2_base, new_blk1_top, new_blk2_first_rec_base, new_blk2_remain; /* shared memory pointers */ sm_uc_ptr_t rPtr1, rPtr2; rec_hdr_ptr_t star_rec_hdr, old_last_rec_hdr1, new_rec_hdr1, new_rec_hdr2, blk2_ances_hdr, new_levelp_cur_hdr, new_levelp_cur_next_hdr; blk_segment *bs_ptr1, *bs_ptr2; srch_hist *blk1ptr, *blk2ptr; /* blk2ptr is for right sibling's hist from a minimum sub-tree containing both blocks */ error_def(ERR_GVKILLFAIL); blk_size = cs_data->blk_size; assert(update_array != NULL); update_array_ptr = update_array; blk1ptr = &(gv_target->hist); blk2ptr = gv_target->alt_hist; old_blk1_base = blk1ptr->h[level].buffaddr; old_blk2_base = blk2ptr->h[level].buffaddr; old_blk1_sz = ((blk_hdr_ptr_t)old_blk1_base)->bsiz; old_blk2_sz = ((blk_hdr_ptr_t)old_blk2_base)->bsiz; if (0 != level && sizeof(blk_hdr) + BSTAR_REC_SIZE == old_blk1_sz) old_ref_star_only = TRUE; /* Search an ancestor block at levelp >= level+1, which has a real key value corresponding to the working block. This key value will be changed after coalesce. */ levelp = level; do { if (++levelp > blk1ptr->depth || levelp > blk2ptr->depth) { assert(t_tries < CDB_STAGNATE); return cdb_sc_blkmod; } old_levelp_blk_base = blk1ptr->h[levelp].buffaddr; old_levelp_rec_offset = blk1ptr->h[levelp].curr_rec.offset; rec_base = old_levelp_blk_base + old_levelp_rec_offset; GET_RSIZ(rec_size, rec_base); } while (BSTAR_REC_SIZE == rec_size); /* search ancestors to get a real value */ /* old_levelp_cur_prev_key = real value of the key before the curr_key at levelp old_levelp_cur_prev_keysz = uncompressed size of the key Note: we may not have a previous key (old_levelp_cur_prev_keysz = 0) */ if (sizeof(blk_hdr) == old_levelp_rec_offset) old_levelp_cur_prev_keysz = 0; else { if (cdb_sc_normal != (status = gvcst_expand_any_key (old_levelp_blk_base, rec_base, &old_levelp_cur_prev_key[0], &rec_size, &tkeylen, &tkeycmpc, NULL))) { assert(t_tries < CDB_STAGNATE); return cdb_sc_blkmod; } old_levelp_cur_prev_keysz = tkeylen + tkeycmpc; } /* old_levelp_cur_key = real value of the curr_key at levelp old_levelp_cur_keysz = uncompressed size of the key old_levelp_cur_keylen = compressed size of the key */ READ_RECORD(levelp, rec_base, tkeycmpc, rec_size, &old_levelp_cur_key[0], old_levelp_cur_keylen, status); if (cdb_sc_normal != status) { assert(t_tries < CDB_STAGNATE); return cdb_sc_blkmod; } if (old_levelp_cur_prev_keysz) memcpy(&old_levelp_cur_key[0], &old_levelp_cur_prev_key[0], tkeycmpc); rec_base += rec_size; old_levelp_cur_keysz = old_levelp_cur_keylen + tkeycmpc; /* old_levelp_cur_next_key = uncompressed value of the next right key of old_levelp_cur_key old_levelp_cur_next_keysz = uncomressed size of the key old_levelp_cur_next_keylen = comressed size of the key Note: we may not have a next key (old_levelp_cur_next_keysz = 0) */ BLK_ADDR(old_levelp_cur_next_key, gv_cur_region->max_key_size + 1, unsigned char); READ_RECORD(levelp, rec_base, tkeycmpc, rec_size, old_levelp_cur_next_key, old_levelp_cur_next_keylen, status); if (cdb_sc_starrecord == status) levelp_next_is_star = TRUE; else if (cdb_sc_normal != status) { assert(t_tries < CDB_STAGNATE); return cdb_sc_blkmod; } else { memcpy(old_levelp_cur_next_key, &old_levelp_cur_key[0], tkeycmpc); old_levelp_cur_next_keysz = old_levelp_cur_next_keylen + tkeycmpc; levelp_next_is_star = FALSE; } /* Now process the actual working block at current level oldblk1_last_key = real value of last key of the working block For index block decompress *-key oldblk1_last_keylen = compressed size of the last key oldblk1_last_cmpc = compression count of last key of working block old_last_rec_hdr1 = New working index block's last record header */ BLK_ADDR(oldblk1_last_key, gv_cur_region->max_key_size + 1, unsigned char); if (0 == level) /* data block */ { if (cdb_sc_normal != (status = gvcst_expand_any_key (old_blk1_base, old_blk1_base + old_blk1_sz, oldblk1_last_key, &rec_size, &oldblk1_last_keylen, &oldblk1_last_cmpc, NULL))) { assert(t_tries < CDB_STAGNATE); return cdb_sc_blkmod; } rec_base = old_blk1_base + old_blk1_sz; } else /* Index blocks */ { /* Since we will join this working block with the right sibling, we need to remove the *-key at the end of working block and replace with actual key value (with required compression). We will get the real value of *-rec from its ancestor at levelp */ memcpy (oldblk1_last_key, &old_levelp_cur_key[0], old_levelp_cur_keysz); if (!old_ref_star_only) /* if the index block is not a *-key only block) */ { if (cdb_sc_normal != (status = gvcst_expand_any_key (old_blk1_base, old_blk1_base + old_blk1_sz - BSTAR_REC_SIZE, &oldblk1_prev_key[0], &rec_size, &tkeylen, &tkeycmpc, NULL))) { assert(t_tries < CDB_STAGNATE); return cdb_sc_blkmod; } GET_CMPC(oldblk1_last_cmpc, &oldblk1_prev_key[0], &old_levelp_cur_key[0]); oldblk1_last_keylen = old_levelp_cur_keysz - oldblk1_last_cmpc; } else /* working block has a *-key record only */ { /* get key value from ancestor blocks key */ oldblk1_last_keylen = old_levelp_cur_keysz; oldblk1_last_cmpc = 0; } BLK_ADDR(old_last_rec_hdr1, sizeof(rec_hdr), rec_hdr); old_last_rec_hdr1->rsiz = BSTAR_REC_SIZE + oldblk1_last_keylen; old_last_rec_hdr1->cmpc = oldblk1_last_cmpc; } /* newblk1_last_key = new working blocks final appended key newblk1_mid_cmpc = new working blocks firstly appended key's cmpc newblk1_last_keysz = new working blocks lastly appended key's size star_only_merge = TRUE, we can append only a *-key record into the working block (decompressing current *-key) complete_merge = TRUE, rtsib can be completely merged with working block piece_len = Size of data from old rtsibling to be merged into working block (includes rec_hdr size) */ BLK_ADDR(newblk1_last_key, gv_cur_region->max_key_size + 1, unsigned char); rec_base = old_blk2_base + sizeof(blk_hdr); READ_RECORD(level, rec_base, newblk1_last_cmpc, rec_size, newblk1_last_key, newblk1_last_keylen, status); if (cdb_sc_starrecord == status) /* rtsib index block has *-record only */ { if (old_blk1_sz + oldblk1_last_keylen + BSTAR_REC_SIZE > i_max_fill ) /* cannot fit even one record */ return cdb_sc_oprnotneeded; star_only_merge = TRUE; complete_merge = TRUE; rec_base = old_blk2_base + sizeof(blk_hdr) + BSTAR_REC_SIZE; } else if (cdb_sc_normal != status) { assert(t_tries < CDB_STAGNATE);; return cdb_sc_blkmod; } else /* for both data and non-* index block */ { newblk1_last_keysz = newblk1_last_keylen; /* first key has uncompressed real value */ GET_CMPC(newblk1_mid_cmpc, oldblk1_last_key, newblk1_last_key); piece_len = rec_size - newblk1_mid_cmpc; if (level == 0) /* data block */ { if (old_blk1_sz + piece_len > d_max_fill ) /* cannot fit even one record */ return cdb_sc_oprnotneeded; } else /* else an index block */ { if (old_blk1_sz + oldblk1_last_keylen + BSTAR_REC_SIZE > i_max_fill ) /* cannot fit even one record */ return cdb_sc_oprnotneeded; if (old_blk1_sz + oldblk1_last_keylen + piece_len + BSTAR_REC_SIZE > i_max_fill ) star_only_merge = TRUE; /* can fit only a *-record */ } rec_base += rec_size; } /* new_blk2_first_rec_base and new_blk1_top is set with final value for star_only_merge for index block */ new_blk2_first_rec_base = new_blk1_top = rec_base; if (!star_only_merge) { BLK_ADDR(new_rec_hdr1, sizeof(rec_hdr), rec_hdr); new_rec_hdr1->rsiz = piece_len; new_rec_hdr1->cmpc = newblk1_mid_cmpc; } /* else only new_blk1_last_key will be appeneded in working block */ /* find a piece of the right sibling to be copied into the working block. Note: rec_base points to 2nd record of old rtsib */ if (0 == level) /* if data block */ { complete_merge = TRUE; while (rec_base < old_blk2_base + old_blk2_sz) { GET_RSIZ(rec_size, rec_base); if (old_blk1_sz + piece_len + rec_size > d_max_fill ) { complete_merge = FALSE; break; } READ_RECORD(level, rec_base, newblk1_last_cmpc, rec_size, newblk1_last_key, newblk1_last_keylen, status); if (cdb_sc_normal != status) { assert(t_tries < CDB_STAGNATE);; return cdb_sc_blkmod; } newblk1_last_keysz = newblk1_last_keylen + newblk1_last_cmpc; rec_base += rec_size; piece_len += rec_size; }/* end of "while" loop */ new_blk1_top = new_blk2_first_rec_base = rec_base; } else /* index block */ { if (!star_only_merge) { /* we know we can fit more record in working block and rtsibling has more records */ complete_merge = TRUE; while (rec_base < old_blk2_base + old_blk2_sz) { GET_RSIZ(rec_size, rec_base); if (BSTAR_REC_SIZE == rec_size) { rec_base += rec_size; piece_len += rec_size; break; /* already we know we can fit this *-record in working block */ } READ_RECORD(level, rec_base, newblk1_last_cmpc, rec_size, newblk1_last_key, newblk1_last_keylen, status); if (cdb_sc_normal != status) { assert(t_tries < CDB_STAGNATE);; return cdb_sc_blkmod; } newblk1_last_keysz = newblk1_last_keylen + newblk1_last_cmpc; rec_base += rec_size; piece_len += rec_size; if (old_blk1_sz + oldblk1_last_keylen + piece_len + BSTAR_REC_SIZE > i_max_fill ) { complete_merge = FALSE; break; } }/* end of "while" loop */ new_blk1_top = new_blk2_first_rec_base = rec_base; } /* end else *-only merge */ } /* end else index block */ if (!complete_merge) { /* Adjust new right sibling's buffer if new_rtsib_star_only == TRUE then new right sibling will have a *-key record only else new_blk2_remain = base pointer of buffer including 1st record but exclude rec_header and key new_blk2_first_keysz = size of new rtsib block's first key */ BLK_ADDR(newblk2_first_key, gv_cur_region->max_key_size + 1, unsigned char); READ_RECORD(level, new_blk2_first_rec_base, tkeycmpc, rec_size, newblk2_first_key, newblk2_first_keylen, status); if (cdb_sc_starrecord == status) /* new rtsib will have a *-record only */ new_rtsib_star_only = TRUE; else if (cdb_sc_normal != status) { assert(t_tries < CDB_STAGNATE);; return cdb_sc_blkmod; } else { memcpy(newblk2_first_key, newblk1_last_key, tkeycmpc); /* copy the compressed piece */ newblk2_first_keysz = newblk2_first_keylen + tkeycmpc; new_blk2_remain = new_blk2_first_rec_base + sizeof(rec_hdr) + newblk2_first_keylen; BLK_ADDR(new_rec_hdr2, sizeof(rec_hdr), rec_hdr); new_rec_hdr2->rsiz = rec_size + tkeycmpc; new_rec_hdr2->cmpc = 0; } }
/*********************************************************************************************** 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
/******************************************************************************************* Input Parameter: blk_base = Block's base which has the key rec_top = record top of the record which will be expanded Output Parameter: expanded_key = expanded key rec_size = last record size whic has the key keylen = key size keycmpc = key compression cound hist_ptr = history of blocks read, while expanding a *-key History excludes the working block from which key is expanded and includes the blocks read below the current block to expand a *-key NOTE: hist_ptr.depth will be unchanged Return: cdb_sc_normal on success failure code on concurrency failure *******************************************************************************************/ enum cdb_sc gvcst_expand_any_key (sm_uc_ptr_t blk_base, sm_uc_ptr_t rec_top, sm_uc_ptr_t expanded_key, int *rec_size, int *keylen, int *keycmpc, srch_hist *hist_ptr) { enum cdb_sc status; unsigned char expanded_star_key[MAX_KEY_SZ]; unsigned short temp_ushort; int cur_level; int star_keycmpc; int star_keylen; int star_rec_size; int tblk_size; block_id tblk_num; sm_uc_ptr_t rPtr1, rPtr2, curptr; cur_level = ((blk_hdr_ptr_t)blk_base)->levl; curptr = blk_base + sizeof(blk_hdr); *rec_size = *keycmpc = *keylen = 0; while (curptr < rec_top) { GET_RSIZ(*rec_size, curptr); if (0 == cur_level || BSTAR_REC_SIZE != *rec_size) { READ_RECORD(cur_level, curptr, *keycmpc, *rec_size, expanded_key, *keylen, status); if (cdb_sc_normal != status) { assert(t_tries < CDB_STAGNATE); return status; } else { curptr += *rec_size; if (curptr >= rec_top) break; } } else /* a star record in index block */ { if (curptr + *rec_size != rec_top || NULL == hist_ptr) { assert(t_tries < CDB_STAGNATE); return cdb_sc_rmisalign; } while (0 != cur_level) { tblk_size = ((blk_hdr_ptr_t)blk_base)->bsiz; GET_LONG(tblk_num, blk_base + tblk_size - sizeof(block_id)); if (0 == tblk_num || cs_data->trans_hist.total_blks - 1 < tblk_num) { assert(t_tries < CDB_STAGNATE); return cdb_sc_badlvl; } cur_level--; hist_ptr->h[cur_level].tn = cs_addrs->ti->curr_tn; if (!(blk_base = t_qread(tblk_num, (sm_int_ptr_t)(&(hist_ptr->h[cur_level].cycle)), &(hist_ptr->h[cur_level].cr) ))) { assert(t_tries < CDB_STAGNATE); return rdfail_detail; } if (((blk_hdr_ptr_t)blk_base)->levl != cur_level) { assert(t_tries < CDB_STAGNATE); return cdb_sc_badlvl; } hist_ptr->h[cur_level].buffaddr = blk_base; hist_ptr->h[cur_level].blk_num = tblk_num; hist_ptr->h[cur_level].prev_rec.match = 0; hist_ptr->h[cur_level].prev_rec.offset = 0; hist_ptr->h[cur_level].curr_rec.match = 0; hist_ptr->h[cur_level].curr_rec.offset = 0; } tblk_size = ((blk_hdr_ptr_t)blk_base)->bsiz; /* expand *-key from right most leaf level block of the sub-tree, of which, the original block is root */ if (cdb_sc_normal != (status = (gvcst_expand_any_key(blk_base, blk_base + tblk_size, expanded_star_key, &star_rec_size, &star_keylen, &star_keycmpc, hist_ptr)))) return status; if (*keylen + *keycmpc) /* Previous key exists */ { GET_CMPC(*keycmpc, expanded_key, &expanded_star_key[0]); } memcpy(expanded_key, expanded_star_key, star_keylen + star_keycmpc); *keylen = star_keylen + star_keycmpc - *keycmpc; *rec_size = *keylen + *keycmpc + BSTAR_REC_SIZE; return cdb_sc_normal; } /* end else if *-record */ }/* end of "while" loop */ if (curptr == rec_top) { return cdb_sc_normal; } else { assert(t_tries < CDB_STAGNATE); return cdb_sc_rmisalign; } }