221 lines
7.1 KiB
C
221 lines
7.1 KiB
C
/****************************************************************
|
|
* *
|
|
* Copyright 2001, 2011 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. *
|
|
* *
|
|
****************************************************************/
|
|
|
|
/* insert_region.c
|
|
* requirement
|
|
* reg initialized (gvcst_init)
|
|
* parameters
|
|
* reg the region to be inserted
|
|
* reg_list pointer to the pointer to the list head
|
|
* reg_free_list pointer to the pointer to the free list
|
|
* size size of the structure of each item in the list
|
|
* return
|
|
* pointer to the item in the list that is corresponding to the region.
|
|
* *reg_list and *reg_free_list are also updated if needed.
|
|
* fid_index field in csa and tp_reg_list is maintained by gvcst_init. Maintaining tp_reg_list is
|
|
* important, since the regions might be re-sorted in between insert_region() calls (i.e. new
|
|
* regions opening). All callers of insert_region except for dse_all() either use tp_reg_list or do not
|
|
* have the regions open. dse_all() opens the regions before it calls insert_region(), so maintaining
|
|
* fid_index in tp_reg_list is sufficient.
|
|
*/
|
|
|
|
#include "mdef.h"
|
|
|
|
#ifdef VMS
|
|
#include <rms>
|
|
#endif
|
|
|
|
#ifdef UNIX
|
|
#include "gtm_ipc.h" /* needed for FTOK */
|
|
#endif
|
|
|
|
#include "gtm_string.h"
|
|
#include "gdsroot.h"
|
|
#include "gtm_facility.h"
|
|
#include "fileinfo.h"
|
|
#include "gdsbt.h"
|
|
#include "gdsfhead.h"
|
|
#include "gdscc.h"
|
|
#include "gdskill.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 "iosp.h"
|
|
#include "dbfilop.h"
|
|
#include "gtmmsg.h"
|
|
#include "is_file_identical.h"
|
|
#include "tp_grab_crit.h"
|
|
#include "t_retry.h"
|
|
#include "wcs_mm_recover.h"
|
|
#include "gtmimagename.h"
|
|
|
|
GBLREF gd_region *gv_cur_region;
|
|
GBLREF uint4 dollar_tlevel;
|
|
GBLREF unsigned int t_tries;
|
|
|
|
tp_region *insert_region( gd_region *reg,
|
|
tp_region **reg_list,
|
|
tp_region **reg_free_list,
|
|
int4 size)
|
|
{
|
|
tp_region *tr, *tr_last, *tr_new;
|
|
unique_file_id local_id;
|
|
# ifdef VMS
|
|
char *local_id_fiptr;
|
|
file_control *fc;
|
|
uint4 status;
|
|
gd_region *temp_reg;
|
|
# endif
|
|
int4 local_fid_index;
|
|
sgmnt_addrs *csa;
|
|
int4 match;
|
|
DCL_THREADGBL_ACCESS;
|
|
|
|
SETUP_THREADGBL_ACCESS;
|
|
assert(SIZEOF(tp_region) <= size);
|
|
assert(!IS_GTM_IMAGE || dollar_tlevel);
|
|
if (reg->open)
|
|
csa = (sgmnt_addrs *)&FILE_INFO(reg)->s_addrs;
|
|
# if defined(VMS)
|
|
if (!reg->open)
|
|
{
|
|
temp_reg = gv_cur_region;
|
|
gv_cur_region = reg;
|
|
local_id_fiptr = local_id.file_id;
|
|
if (!mupfndfil(reg, NULL))
|
|
{
|
|
gv_cur_region = temp_reg;
|
|
return NULL;
|
|
}
|
|
FILE_CNTL_INIT_IF_NULL(reg->dyn.addr);
|
|
fc = reg->dyn.addr->file_cntl;
|
|
fc->file_type = reg->dyn.addr->acc_meth;
|
|
fc->op = FC_OPEN;
|
|
status = dbfilop(fc);
|
|
if (status & 1)
|
|
{
|
|
local_id_fiptr = &(FILE_INFO(reg)->file_id);
|
|
sys$dassgn(FILE_INFO(reg)->fab->fab$l_stv);
|
|
} else
|
|
{
|
|
gtm_putmsg(VARLSTCNT(1) status);
|
|
gv_cur_region = temp_reg;
|
|
return NULL;
|
|
}
|
|
gv_cur_region = temp_reg;
|
|
} else
|
|
local_fid_index = csa->fid_index;
|
|
# elif defined(UNIX)
|
|
if (!reg->open)
|
|
{
|
|
if (!mupfndfil(reg, NULL))
|
|
return NULL;
|
|
if (!filename_to_id(&local_id.uid, (char *)reg->dyn.addr->fname))
|
|
return NULL;
|
|
} else
|
|
local_fid_index = csa->fid_index;
|
|
# endif
|
|
/* See if the region is already on the list or if we have to add it */
|
|
for (tr = *reg_list, tr_last = NULL; NULL != tr; tr = tr->fPtr)
|
|
{
|
|
if (reg->open)
|
|
{ /* gvcst_init must have sorted them and filled in the fid_index field of node_local */
|
|
assert(tr->reg->open);
|
|
/* note that it is possible that "reg" and "tr->reg" are different although their "fid_index" is the same.
|
|
* this is possible if both regions point to the same physical file.
|
|
* in this case we return the existing "tr" instead of creating a new one.
|
|
*/
|
|
if (local_fid_index == tr->file.fid_index) /* Region is found */
|
|
{ /* assert we are not in final retry or we are in TP and have crit on the region already */
|
|
assert((CDB_STAGNATE > t_tries)
|
|
|| (dollar_tlevel && reg->open && csa->now_crit));
|
|
return tr;
|
|
}
|
|
if ((tr->file.fid_index > local_fid_index))
|
|
break; /* .. we have found our insertion point */
|
|
} else
|
|
{
|
|
if (reg == tr->reg) /* Region is found */
|
|
{ /* assert we are not in final retry or we are in TP and have crit on the region already */
|
|
assert((CDB_STAGNATE > t_tries)
|
|
|| (dollar_tlevel && reg->open && csa->now_crit));
|
|
return tr;
|
|
}
|
|
/* let's sort here */
|
|
if (!tr->reg->open)
|
|
{ /* all regions closed */
|
|
VMS_ONLY(match = memcmp(&(tr->file.file_id), local_id_fiptr, SIZEOF(gd_id)));
|
|
UNIX_ONLY(match = gdid_cmp(&(tr->file.file_id), &(local_id.uid)));
|
|
} else
|
|
{ /* the other regions are open, i.e. file is pointing to fid_index, use file_id
|
|
* from node_local */
|
|
VMS_ONLY(match = memcmp(
|
|
&(((sgmnt_addrs *)&FILE_INFO(tr->reg)->s_addrs)->nl->unique_id.file_id),
|
|
local_id_fiptr, SIZEOF(gd_id)));
|
|
UNIX_ONLY(match = gdid_cmp(
|
|
&(((sgmnt_addrs *)&FILE_INFO(tr->reg)->s_addrs)->nl->unique_id.uid), &(local_id.uid)));
|
|
}
|
|
if (0 == match)
|
|
return tr;
|
|
if (0 < match)
|
|
break; /* .. we have found our insertion point */
|
|
}
|
|
tr_last = tr;
|
|
}
|
|
if ((NULL != reg_free_list) && (NULL != *reg_free_list)) /* Get a used block off our unused queue */
|
|
{
|
|
tr_new = *reg_free_list; /* Get element */
|
|
*reg_free_list = tr_new->fPtr; /* Remove from queue */
|
|
} else /* get a new one */
|
|
{
|
|
tr_new = (tp_region *)malloc(size);
|
|
if (size > SIZEOF(tp_region))
|
|
memset(tr_new, 0, size);
|
|
}
|
|
tr_new->reg = reg; /* Add this region to end of list */
|
|
if (!reg->open)
|
|
{
|
|
VMS_ONLY(memcpy(&(tr_new->file.file_id), local_id_fiptr, SIZEOF(gd_id)));
|
|
UNIX_ONLY(tr_new->file.file_id = local_id.uid;)
|
|
} else
|
|
tr_new->file.fid_index = local_fid_index;
|
|
if (NULL == tr_last)
|
|
{ /* First element on the list */
|
|
tr_new->fPtr = *reg_list;
|
|
*reg_list = tr_new;
|
|
} else
|
|
{ /* Insert into list */
|
|
tr_new->fPtr = tr_last->fPtr;
|
|
tr_last->fPtr = tr_new;
|
|
}
|
|
if ((CDB_STAGNATE <= t_tries) && dollar_tlevel && reg->open && !csa->now_crit)
|
|
{ /* Final retry in TP and this region not locked down. Get crit on it if it is open.
|
|
* reg->open needs to be checked above to take care of the case where we do an insert_region() from gvcst_init()
|
|
* in the 3rd retry in TP when we have not yet opened the region. In case region is not open,
|
|
* tp_restart() (invoked through t_retry from gvcst_init) will open "reg" as well as get crit on it for us.
|
|
*/
|
|
DEBUG_ONLY(TREF(ok_to_call_wcs_recover) = TRUE;)
|
|
if (FALSE == tp_grab_crit(reg)) /* Attempt lockdown now */
|
|
{
|
|
DEBUG_ONLY(TREF(ok_to_call_wcs_recover) = FALSE;)
|
|
t_retry(cdb_sc_needcrit); /* avoid deadlock -- restart transaction */
|
|
assert(FALSE); /* should not come here as t_retry() does not return */
|
|
}
|
|
DEBUG_ONLY(TREF(ok_to_call_wcs_recover) = FALSE;)
|
|
assert(csa->now_crit); /* ensure we have crit now */
|
|
CHECK_MM_DBFILEXT_REMAP_IF_NEEDED(csa, reg);
|
|
}
|
|
DBG_CHECK_TP_REG_LIST_SORTING(*reg_list);
|
|
return tr_new;
|
|
}
|