fis-gtm/sr_port/gvcst_delete_blk.c

189 lines
5.7 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 "gdsroot.h"
#include "gdskill.h"
#include "gdsblk.h"
#include "gtm_facility.h"
#include "fileinfo.h"
#include "gdsbt.h"
#include "gdsfhead.h"
#include "gdscc.h"
#include "copy.h"
#include "filestruct.h"
#include "jnl.h"
#include "buddy_list.h" /* needed for tp.h */
#include "hashtab_int4.h" /* needed for tp.h */
#include "tp.h"
#include "gvcst_blk_build.h"
#include "gvcst_delete_blk.h"
GBLREF kill_set *kill_set_tail;
GBLREF sgm_info *sgm_info_ptr;
GBLREF uint4 dollar_tlevel;
GBLREF gv_namehead *gv_target;
GBLREF boolean_t horiz_growth;
GBLREF sgmnt_addrs *cs_addrs;
GBLREF unsigned int t_tries;
#ifdef VMS
GBLREF boolean_t tp_has_kill_t_cse; /* cse->mode of kill_t_write or kill_t_create got created in this transaction */
#endif
void gvcst_delete_blk(block_id blk, int level, boolean_t committed)
{
cw_set_element *cse, *old_cse;
kill_set *ks;
off_chain chain;
srch_blk_status *tp_srch_status;
uint4 iter;
ht_ent_int4 *tabent;
DEBUG_ONLY(
boolean_t block_already_in_hist = FALSE;
)
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
horiz_growth = FALSE;
if (!dollar_tlevel)
ks = kill_set_tail;
else
{
PUT_LONG(&chain, blk);
tp_srch_status = NULL;
if (chain.flag == 1)
tp_get_cw(sgm_info_ptr->first_cw_set, (int)chain.cw_index, &cse);
else
{
if (NULL != (tabent = lookup_hashtab_int4(sgm_info_ptr->blks_in_use, (uint4 *)&blk)))
tp_srch_status = (srch_blk_status *)tabent->value;
cse = tp_srch_status ? tp_srch_status->cse : NULL;
}
if (cse)
{
if (!committed)
{
assert(dollar_tlevel >= cse->t_level);
if (NULL != cse->high_tlevel)
{ /* this is possible only if this block is already part of either of the tree paths
* in gv_target->hist or alt_hist (see gvcst_kill.c) and got a newer cse created as
* part of a gvcst_kill_blk on this block in gvcst_kill.c a little before the call
* to gvcst_kill_blk of a parent block which in turn decided to delete this block
* as part of its records that are getting removed. this is a guaranteed restartable
* situation. since gvcst_delete_blk does not return any status, proceed with the
* newer cse and return. the restart will be later detected by tp_hist.
*/
cse = cse->high_tlevel;
DEBUG_ONLY(TREF(donot_commit) |= DONOTCOMMIT_GVCST_DELETE_BLK_CSE_TLEVEL;)
DEBUG_ONLY(block_already_in_hist = TRUE;)
}
assert(!cse->high_tlevel);
if (cse->t_level != dollar_tlevel)
{ /* this part of the code is almost similar to that in t_write(),
* any changes in one should be reflected in the other */
horiz_growth = TRUE;
old_cse = cse;
cse = (cw_set_element *)get_new_free_element(sgm_info_ptr->tlvl_cw_set_list);
memcpy(cse, old_cse, SIZEOF(cw_set_element));
cse->low_tlevel = old_cse;
cse->high_tlevel = NULL;
old_cse->high_tlevel = cse;
cse->t_level = dollar_tlevel;
assert(2 == (SIZEOF(cse->undo_offset) / SIZEOF(cse->undo_offset[0])));
assert(2 == (SIZEOF(cse->undo_next_off) / SIZEOF(cse->undo_next_off[0])));
for (iter = 0; iter < 2; iter++)
cse->undo_next_off[iter] = cse->undo_offset[iter] = 0;
if (old_cse->done)
{
assert(NULL != old_cse->new_buff);
cse->new_buff = (unsigned char *)get_new_free_element(sgm_info_ptr->new_buff_list);
memcpy(cse->new_buff, old_cse->new_buff, ((blk_hdr_ptr_t)old_cse->new_buff)->bsiz);
} else
cse->new_buff = NULL;
assert(!block_already_in_hist);
/* tp_hist (called from gvcst_kill) updates "->cse" fields for all blocks that are
* part of the left or right histories of the M-kill. But this block is not one of
* those. Hence tp_srch_status->cse has to be updated here explicitly.
*/
if (tp_srch_status)
tp_srch_status->cse = (void *)cse;
}
switch (cse->mode)
{
case gds_t_create:
cse->mode = kill_t_create;
VMS_ONLY(tp_has_kill_t_cse = TRUE;)
if (level == 0)
return;
break;
case gds_t_write:
cse->mode = kill_t_write;
VMS_ONLY(tp_has_kill_t_cse = TRUE;)
break;
default:
;
}
} else
{
switch(cse->mode)
{
case kill_t_create:
VMS_ONLY(assert(tp_has_kill_t_cse));
if (level == 0)
return;
break;
default:
if (chain.flag)
{
chain.flag = 0;
blk = cse->blk;
}
break;
}
}
}
ks = sgm_info_ptr->kill_set_tail;
if (NULL == ks) /* Allocate first kill set to sgm_info_ptr block */
{
ks = sgm_info_ptr->kill_set_tail = sgm_info_ptr->kill_set_head = (kill_set *)malloc(SIZEOF(kill_set));
ks->used = 0;
ks->next_kill_set = NULL;
}
}
while (ks->used >= BLKS_IN_KILL_SET)
{
if (ks->next_kill_set == NULL)
{
ks->next_kill_set = (kill_set *)malloc(SIZEOF(kill_set));
ks->next_kill_set->used = 0;
ks->next_kill_set->next_kill_set = NULL;
}
ks = kill_set_tail
= ks->next_kill_set;
}
ks->blk[ks->used].level = (level) ? 1 : 0;
if (!dollar_tlevel || !chain.flag)
{
assert((CDB_STAGNATE > t_tries) || (blk < cs_addrs->ti->total_blks));
ks->blk[ks->used].block = blk;
ks->blk[ks->used].flag = 0;
} else
{
ks->blk[ks->used].block = chain.cw_index;
ks->blk[ks->used].flag = chain.flag;
}
++ks->used;
assert(ks->used <= BLKS_IN_KILL_SET);
}