249 lines
7.9 KiB
C
249 lines
7.9 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 <errno.h>
|
|
#ifdef VMS
|
|
#include <descrip.h> /* Required for gtmsource.h */
|
|
#include <nam.h> /* Required for the nam$l_esa members */
|
|
#endif
|
|
|
|
#include "gtm_inet.h" /* Required for gtmsource.h */
|
|
#include "gdsroot.h"
|
|
#include "gtm_facility.h"
|
|
#include "fileinfo.h"
|
|
#include "gdsbt.h"
|
|
#include "gdsfhead.h"
|
|
#include "gdsblk.h"
|
|
#include "gdskill.h"
|
|
#include "gdscc.h"
|
|
#include "min_max.h" /* needed for gdsblkops.h */
|
|
#include "gdsblkops.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 "ast.h"
|
|
#include "repl_msg.h"
|
|
#include "gtmsource.h"
|
|
#include "gtmrecv.h"
|
|
#include "error.h"
|
|
#ifdef UNIX
|
|
#include "io.h"
|
|
#include "gtmsecshr.h"
|
|
#include "mutex.h"
|
|
#include "ftok_sems.h"
|
|
#endif
|
|
|
|
#include "tp_change_reg.h"
|
|
#include "gds_rundown.h"
|
|
#include "dpgbldir.h"
|
|
#include "gvcmy_rundown.h"
|
|
#include "rc_cpt_ops.h"
|
|
#include "gv_rundown.h"
|
|
#include "targ_alloc.h"
|
|
#ifdef GTM_CRYPT
|
|
#include "gtmcrypt.h"
|
|
#endif
|
|
#if defined(DEBUG) && defined(UNIX)
|
|
#include "anticipatory_freeze.h"
|
|
#endif
|
|
|
|
GBLREF gd_region *gv_cur_region;
|
|
GBLREF sgmnt_addrs *cs_addrs;
|
|
GBLREF boolean_t pool_init;
|
|
GBLREF jnlpool_addrs jnlpool;
|
|
GBLREF recvpool_addrs recvpool;
|
|
GBLREF jnlpool_ctl_ptr_t jnlpool_ctl;
|
|
GBLREF gd_region *ftok_sem_reg;
|
|
|
|
#if defined(DEBUG) && defined(UNIX)
|
|
GBLREF boolean_t is_jnlpool_creator;
|
|
error_def(ERR_TEXT);
|
|
#endif
|
|
error_def(ERR_NOTALLDBRNDWN);
|
|
|
|
void gv_rundown(void)
|
|
{
|
|
gd_region *r_top, *r_save, *r_local;
|
|
gd_addr *addr_ptr;
|
|
sgm_info *si;
|
|
int4 rundown_status = EXIT_NRM; /* if gds_rundown went smoothly */
|
|
# ifdef VMS
|
|
vms_gds_info *gds_info;
|
|
# elif UNIX
|
|
unix_db_info *udi;
|
|
# endif
|
|
#if defined(DEBUG) && defined(UNIX)
|
|
sgmnt_addrs *csa;
|
|
# endif
|
|
DCL_THREADGBL_ACCESS;
|
|
|
|
SETUP_THREADGBL_ACCESS;
|
|
|
|
r_save = gv_cur_region; /* Save for possible core dump */
|
|
gvcmy_rundown();
|
|
ENABLE_AST
|
|
|
|
if (pool_init)
|
|
rel_lock(jnlpool.jnlpool_dummy_reg);
|
|
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 && dba_cm != r_local->dyn.addr->acc_meth)
|
|
{ /* Rundown has already occurred for GT.CM client regions through gvcmy_rundown() above.
|
|
* Hence the (dba_cm != ...) check in the if above. Note that for GT.CM client regions,
|
|
* region->open is TRUE although cs_addrs is NULL.
|
|
*/
|
|
# if defined(DEBUG) && defined(UNIX)
|
|
if (is_jnlpool_creator && ANTICIPATORY_FREEZE_AVAILABLE && TREF(gtm_test_fake_enospc))
|
|
{ /* Clear ENOSPC faking now that we are running down */
|
|
csa = REG2CSA(r_local);
|
|
if (csa->nl->fake_db_enospc || csa->nl->fake_jnl_enospc)
|
|
{
|
|
send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_TEXT, 2, DB_LEN_STR(r_local), ERR_TEXT,
|
|
2, LEN_AND_LIT("Resetting fake_db_enospc and fake_jnl_enospc"));
|
|
csa->nl->fake_db_enospc = FALSE;
|
|
csa->nl->fake_jnl_enospc = FALSE;
|
|
}
|
|
}
|
|
# endif
|
|
gv_cur_region = r_local;
|
|
tp_change_reg();
|
|
UNIX_ONLY(rundown_status |=) gds_rundown();
|
|
|
|
/* Now that gds_rundown is done, free up the memory associated with the region.
|
|
* Ideally the following memory freeing code should go to gds_rundown, but
|
|
* GT.CM calls gds_rundown() and we want to reuse memory for GT.CM.
|
|
*/
|
|
if (NULL != cs_addrs)
|
|
{
|
|
if (NULL != cs_addrs->dir_tree)
|
|
FREE_CSA_DIR_TREE(cs_addrs);
|
|
if (cs_addrs->sgm_info_ptr)
|
|
{
|
|
si = cs_addrs->sgm_info_ptr;
|
|
/* It is possible we got interrupted before initializing all fields of "si"
|
|
* completely so account for NULL values while freeing/releasing those fields.
|
|
*/
|
|
assert((si->tp_csa == cs_addrs) || (NULL == si->tp_csa));
|
|
if (si->jnl_tail)
|
|
{
|
|
CAREFUL_FREEUP_BUDDY_LIST(si->format_buff_list);
|
|
CAREFUL_FREEUP_BUDDY_LIST(si->jnl_list);
|
|
}
|
|
CAREFUL_FREEUP_BUDDY_LIST(si->recompute_list);
|
|
CAREFUL_FREEUP_BUDDY_LIST(si->new_buff_list);
|
|
CAREFUL_FREEUP_BUDDY_LIST(si->tlvl_info_list);
|
|
CAREFUL_FREEUP_BUDDY_LIST(si->tlvl_cw_set_list);
|
|
CAREFUL_FREEUP_BUDDY_LIST(si->cw_set_list);
|
|
if (NULL != si->blks_in_use)
|
|
{
|
|
free_hashtab_int4(si->blks_in_use);
|
|
free(si->blks_in_use);
|
|
si->blks_in_use = NULL;
|
|
}
|
|
if (si->cr_array_size)
|
|
{
|
|
assert(NULL != si->cr_array);
|
|
if (NULL != si->cr_array)
|
|
free(si->cr_array);
|
|
}
|
|
if (NULL != si->first_tp_hist)
|
|
free(si->first_tp_hist);
|
|
free(si);
|
|
}
|
|
if (cs_addrs->jnl)
|
|
{
|
|
assert(&FILE_INFO(cs_addrs->jnl->region)->s_addrs == cs_addrs);
|
|
if (cs_addrs->jnl->jnllsb)
|
|
{
|
|
UNIX_ONLY(assert(FALSE));
|
|
free(cs_addrs->jnl->jnllsb);
|
|
}
|
|
free(cs_addrs->jnl);
|
|
}
|
|
GTMCRYPT_ONLY(
|
|
if (cs_addrs->encrypted_blk_contents)
|
|
free(cs_addrs->encrypted_blk_contents);
|
|
)
|
|
}
|
|
assert(gv_cur_region->dyn.addr->file_cntl->file_info);
|
|
VMS_ONLY(
|
|
gds_info = (vms_gds_info *)gv_cur_region->dyn.addr->file_cntl->file_info;
|
|
if (gds_info->xabpro)
|
|
free(gds_info->xabpro);
|
|
if (gds_info->xabfhc)
|
|
free(gds_info->xabfhc);
|
|
if (gds_info->nam)
|
|
{
|
|
free(gds_info->nam->nam$l_esa);
|
|
free(gds_info->nam);
|
|
}
|
|
if (gds_info->fab)
|
|
free(gds_info->fab);
|
|
)
|
|
free(gv_cur_region->dyn.addr->file_cntl->file_info);
|
|
free(gv_cur_region->dyn.addr->file_cntl);
|
|
}
|
|
r_local->open = r_local->was_open = FALSE;
|
|
}
|
|
}
|
|
rc_close_section();
|
|
gv_cur_region = r_save; /* Restore value for dumps but this region is now closed and is otherwise defunct */
|
|
cs_addrs = NULL;
|
|
GTMCRYPT_ONLY(GTMCRYPT_CLOSE;)
|
|
#ifdef UNIX
|
|
gtmsecshr_sock_cleanup(CLIENT);
|
|
#ifndef MUTEX_MSEM_WAKE
|
|
mutex_sock_cleanup();
|
|
#endif
|
|
#endif
|
|
jnlpool_detach();
|
|
# ifdef UNIX
|
|
/* Clean up any left-over ftok semaphores. This part of the code can be reached by almost all of the exit handling routines.
|
|
* If the ftok semaphore is grabbed, but not released, ftok_sem_reg will have a non-null value and grabbed_ftok_sem will be
|
|
* TRUE. We cannot rely on gv_cur_region always as it is used in so many places in so many ways.
|
|
* Note: Typically, it should suffice to check for ftok_sem_reg being non-null and pass that to ftok_sem_release. But, there
|
|
* are some cases where ftok_sem_reg can be NULL and yet jnlpool.jnlpool_dummy_reg is non-null and the process holds an ftok
|
|
* semaphore. For instance, if GT.M opened a particular region and then did a jnlpool_init which ended up with an rts_error
|
|
* (after obtaining the ftok semaphore on jnlpool_dummy_reg), gds_rundown done above (to rundown the database) sets
|
|
* ftok_sem_reg to NULL (as part of ftok_sem_release). But, jnlpool_dummy_reg is still non-null and the lingering ftok
|
|
* should be released. So, even though a subset of the below conditions should be enough, we check for all there cases just
|
|
* to be safe.
|
|
*/
|
|
if (ftok_sem_reg)
|
|
{
|
|
udi = FILE_INFO(ftok_sem_reg);
|
|
assert(udi->grabbed_ftok_sem);
|
|
ftok_sem_release(ftok_sem_reg, TRUE, TRUE);
|
|
}
|
|
if (NULL != jnlpool.jnlpool_dummy_reg)
|
|
{
|
|
udi = FILE_INFO(jnlpool.jnlpool_dummy_reg);
|
|
if (udi->grabbed_ftok_sem)
|
|
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
|
|
}
|
|
if (NULL != recvpool.recvpool_dummy_reg)
|
|
{
|
|
udi = FILE_INFO(recvpool.recvpool_dummy_reg);
|
|
if (udi->grabbed_ftok_sem)
|
|
ftok_sem_release(recvpool.recvpool_dummy_reg, TRUE, TRUE);
|
|
}
|
|
# endif
|
|
|
|
if (EXIT_NRM != rundown_status)
|
|
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOTALLDBRNDWN);
|
|
}
|