fis-gtm/sr_port/gvcst_expand_free_subtree.c

180 lines
6.6 KiB
C

/****************************************************************
* *
* Copyright 2001, 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" /* atleast for cdb_sc_* codes */
#include "copy.h" /* atleast for the GET_USHORT macros */
#include "gdsroot.h" /* atleast for gds_file_id used by sgmnt_data in gdsfhead.h */
#include "gdskill.h" /* atleast for the kill_set and blk_ident structures */
#include "gdsblk.h" /* atleast for the blk_hdr and rec_hdr structures */
#include "gtm_facility.h" /* atleast for gdsfhead.h */
#include "fileinfo.h" /* atleast for gdsfhead.h */
#include "gdsbt.h" /* atleast for gdsfhead.h */
#include "gdsfhead.h" /* atleast for cs_addrs, cs_data etc. */
#include "filestruct.h" /* atleast for the FILE_INFO macro */
#include "gdscc.h" /* atleast for cw_set_element in tp.h */
#include "jnl.h" /* atleast for tp.h */
#include "buddy_list.h" /* atleast for tp.h */
#include "hashtab_int4.h" /* needed for tp.h */
#include "tp.h" /* atleast for off_chain */
#include "t_qread.h"
#include "gvcst_bmp_mark_free.h"
#include "gvcst_delete_blk.h"
#include "gvcst_kill_sort.h"
#include "gvcst_expand_free_subtree.h"
#include "rc_cpt_ops.h"
#include "wcs_phase2_commit_wait.h"
GBLREF gd_region *gv_cur_region;
GBLREF sgmnt_addrs *cs_addrs;
GBLREF sgmnt_data_ptr_t cs_data;
GBLREF sgm_info *sgm_info_ptr;
GBLREF uint4 dollar_tlevel;
GBLREF unsigned char rdfail_detail;
GBLREF inctn_opcode_t inctn_opcode;
error_def(ERR_GVKILLFAIL);
error_def(ERR_IGNBMPMRKFREE);
void gvcst_expand_free_subtree(kill_set *ks_head)
{
blk_hdr_ptr_t bp;
blk_ident *ksb;
block_id blk;
boolean_t flush_cache = FALSE, was_crit;
cache_rec_ptr_t cr;
int cnt, cycle;
int4 kill_error, temp_long;
kill_set *ks;
off_chain chain;
rec_hdr_ptr_t rp, rp1, rtop;
uint4 save_dollar_tlevel;
sm_uc_ptr_t temp_buff;
sgmnt_addrs *csa;
sgmnt_data_ptr_t csd;
unsigned short temp_ushort;
trans_num ret_tn;
inctn_opcode_t save_inctn_opcode;
bt_rec_ptr_t bt;
unsigned int level;
csa = cs_addrs;
csd = cs_data;
/* If ever the following assert is removed, "flush_cache" shouldn't be set to FALSE unconditionally as it is now */
assert(!csd->dsid); /* see related comment in gvcst_kill before the call to this routine */
temp_buff = (unsigned char *)malloc(cs_data->blk_size);
for (ks = ks_head; NULL != ks; ks = ks->next_kill_set)
{
for (cnt = 0; cnt < ks->used; ++cnt)
{
ksb = &ks->blk[cnt];
if (0 != ksb->level)
{
if (!(was_crit = csa->now_crit))
grab_crit(gv_cur_region);
# ifdef UNIX
if (csa->onln_rlbk_cycle != csa->nl->onln_rlbk_cycle)
{ /* Concurrent online rollback. We don't want to continue with rest of the logic to add more
* blocks to the kill-set and do the gvcst_bmp_mark_free. Return to the caller. Since we
* haven't sync'ed the cycles, the next tranasction commit will detect the online rollback
* and the restart logic will handle it appropriately.
*/
free(temp_buff);
rel_crit(gv_cur_region);
send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_IGNBMPMRKFREE, 4, REG_LEN_STR(gv_cur_region),
DB_LEN_STR(gv_cur_region));
return;
}
# endif
if (dollar_tlevel && ksb->flag)
{
chain.flag = 1;
chain.next_off = 0;
chain.cw_index = ksb->block;
assert(SIZEOF(chain) == SIZEOF(blk));
blk = *(block_id *)&chain;
} else
blk = ksb->block;
if (!(bp = (blk_hdr_ptr_t)t_qread(blk, (sm_int_ptr_t)&cycle, &cr)))
{ /* This should have worked because t_qread was done in crit */
free(temp_buff);
rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_GVKILLFAIL, 2, 1, &rdfail_detail);
}
if (NULL != cr)
{ /* It is possible that t_qread returned a buffer from first_tp_srch_status.
* In that case, t_qread does not wait for cr->in_tend to be zero since
* there is no need to wait as long as all this is done inside of the TP
* transaction. But the gvcst_expand_free_subtree logic is special in that it
* is done AFTER the TP transaction is committed but with dollar_tlevel still
* set to non-zero. So it is possible that cr->in_tend is non-zero in this case.
* Hence we need to check if cr->in_tend is non-zero and if so wait for commit
* to complete before scanning the block for child-block #s to free.
*/
if (dollar_tlevel && cr->in_tend)
wcs_phase2_commit_wait(csa, cr);
assert(!cr->twin || cr->bt_index);
assert((NULL == (bt = bt_get(blk)))
|| (CR_NOTVALID == bt->cache_index)
|| (cr == (cache_rec_ptr_t)GDS_REL2ABS(bt->cache_index)) && (0 == cr->in_tend));
}
memcpy(temp_buff, bp, bp->bsiz);
if (!was_crit)
rel_crit(gv_cur_region);
for (rp = (rec_hdr_ptr_t)(temp_buff + SIZEOF(blk_hdr)),
rtop = (rec_hdr_ptr_t)(temp_buff + ((blk_hdr_ptr_t)temp_buff)->bsiz);
rp < rtop;
rp = rp1)
{
GET_USHORT(temp_ushort, &rp->rsiz);
rp1 = (rec_hdr_ptr_t)((sm_uc_ptr_t)rp + temp_ushort);
if ((sm_uc_ptr_t)rp1 < (sm_uc_ptr_t)(rp + 1) + SIZEOF(block_id))
{ /* This should have worked because a local copy was made while crit */
assert(FALSE);
kill_error = cdb_sc_rmisalign;
free(temp_buff);
rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_GVKILLFAIL, 2, 1, &kill_error);
}
GET_LONG(temp_long, (block_id_ptr_t)((sm_uc_ptr_t)rp1 - SIZEOF(block_id)));
if (dollar_tlevel)
{
chain = *(off_chain *)&temp_long;
if ((1 == chain.flag) && ((int)chain.cw_index >= sgm_info_ptr->cw_set_depth))
{
assert(sgm_info_ptr->tp_csa == cs_addrs);
GTMASSERT;
}
assert(chain.flag || temp_long < csa->ti->total_blks);
}
level = ((blk_hdr_ptr_t)temp_buff)->levl;
gvcst_delete_blk(temp_long, level - 1, TRUE);
if ((1 == level) && !dollar_tlevel && cs_data->dsid && !flush_cache)
rc_cpt_entry(temp_long); /* Invalidate single block */
}
ksb->level = 0;
} else
{
if (!dollar_tlevel && cs_data->dsid && !flush_cache)
rc_cpt_entry(ksb->block);
}
}
gvcst_kill_sort(ks);
save_dollar_tlevel = dollar_tlevel;
assert(1 >= dollar_tlevel);
dollar_tlevel = 0; /* temporarily for gvcst_bmp_mark_free */
GVCST_BMP_MARK_FREE(ks, ret_tn, inctn_invalid_op, inctn_bmp_mark_free_gtm, inctn_opcode, csa)
dollar_tlevel = save_dollar_tlevel;
}
free(temp_buff);
}