fis-gtm/sr_port/have_crit.c

147 lines
4.9 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_inet.h"
#ifdef VMS
#include <descrip.h> /* Required for gtmsource.h */
#endif
#include "gdsroot.h"
#include "gtm_facility.h"
#include "fileinfo.h"
#include "gdsbt.h"
#include "gdsfhead.h"
#include "repl_msg.h"
#include "gtmsource.h"
#include "filestruct.h"
#include "jnl.h"
#include "dpgbldir.h"
#include "have_crit.h"
#include "send_msg.h"
GBLREF volatile int4 crit_count;
GBLREF jnlpool_addrs jnlpool;
GBLREF uint4 process_id;
GBLREF uint4 crit_deadlock_check_cycle;
GBLREF uint4 dollar_tlevel;
GBLREF unsigned int t_tries;
#if defined(UNIX) && defined(DEBUG)
GBLREF jnl_gbls_t jgbl;
#endif
error_def(ERR_MUTEXRELEASED);
/* Return number of regions (including jnlpool dummy region) if have or are aquiring crit or in_wtstart
* ** NOTE ** This routine is called from signal handlers and is thus called asynchronously.
* If CRIT_IN_COMMIT bit is set, we check if in middle of commit (PHASE1 inside crit or PHASE2 outside crit) on some region.
* If CRIT_RELEASE bit is set, we release crit on region(s) that:
* 1) we hold crit on (neither CRIT_IN_COMMIT NOR CRIT_TRANS_NO_REG is specified)
* 2) are part of the current transactions except those regions that are marked as being valid
* to have crit in by virtue of their crit_check_cycle value is the same as crit_deadlock_check_cycle.
* Note: CRIT_RELEASE implies CRIT_ALL_REGIONS
* If CRIT_ALL_REGIONS bit is set, go through the entire list of regions
*/
uint4 have_crit(uint4 crit_state)
{
gd_region *r_top, *r_local;
gd_addr *addr_ptr;
sgmnt_addrs *csa;
uint4 crit_reg_cnt = 0;
/* in order to proper release the necessary regions, CRIT_RELEASE implies going through all the regions */
if (crit_state & CRIT_RELEASE)
{
UNIX_ONLY(assert(!jgbl.onlnrlbk)); /* should not request crit to be released if online rollback */
crit_state |= CRIT_ALL_REGIONS;
}
if (0 != crit_count)
{
crit_reg_cnt++;
if (0 == (crit_state & CRIT_ALL_REGIONS))
return crit_reg_cnt;
}
for (addr_ptr = get_next_gdr(NULL); addr_ptr; addr_ptr = get_next_gdr(addr_ptr))
{
for (r_local = addr_ptr->regions, r_top = r_local + addr_ptr->n_regions; r_local < r_top; r_local++)
{
if (r_local->open && !r_local->was_open)
{
csa = &FILE_INFO(r_local)->s_addrs;
if (NULL != csa)
{
if (csa->now_crit)
{
crit_reg_cnt++;
/* It is possible that if DSE has done a CRIT REMOVE and stolen our crit, it
* could be given to someone else which would cause this test to fail. The
* current thinking is that the state DSE put this process is no longer viable
* and it should die at the earliest opportunity, there being no way to know if
* that is what happened anyway.
*/
if (csa->nl->in_crit != process_id)
GTMASSERT;
/* If we are releasing (all) regions with critical section or if special
* TP case, release if the cycle number doesn't match meaning this is a
* region we should not hold crit in (even if it is part of tp_reg_list).
*/
if ((0 != (crit_state & CRIT_RELEASE)) &&
(0 == (crit_state & CRIT_NOT_TRANS_REG) ||
crit_deadlock_check_cycle != csa->crit_check_cycle))
{
assert(FALSE);
assert(!csa->hold_onto_crit);
rel_crit(r_local);
send_msg(VARLSTCNT(8) ERR_MUTEXRELEASED, 6,
process_id, process_id, DB_LEN_STR(r_local),
dollar_tlevel, t_tries);
}
if (0 == (crit_state & CRIT_ALL_REGIONS))
return crit_reg_cnt;
}
/* In Commit-crit is defined as the time since when early_tn is 1 + curr_tn upto when
* t_commit_crit is set to FALSE. Note that the first check should be done only if we
* hold crit as otherwise we could see inconsistent values.
*/
if ((crit_state & CRIT_IN_COMMIT)
&& (csa->now_crit && (csa->ti->early_tn != csa->ti->curr_tn) || csa->t_commit_crit))
{
crit_reg_cnt++;
if (0 == (crit_state & CRIT_ALL_REGIONS))
return crit_reg_cnt;
}
if ((crit_state & CRIT_IN_WTSTART) && csa->in_wtstart)
{
crit_reg_cnt++;
if (0 == (crit_state & CRIT_ALL_REGIONS))
return crit_reg_cnt;
}
}
}
}
}
if (NULL != jnlpool.jnlpool_ctl)
{
csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;
if (NULL != csa && csa->now_crit)
{
crit_reg_cnt++;
if (0 != (crit_state & CRIT_RELEASE))
{
assert(!csa->hold_onto_crit);
rel_lock(jnlpool.jnlpool_dummy_reg);
}
}
}
return crit_reg_cnt;
}