189 lines
5.7 KiB
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);
|
|
}
|