148 lines
5.4 KiB
C
148 lines
5.4 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. *
|
|
* *
|
|
****************************************************************/
|
|
|
|
#include "mdef.h"
|
|
|
|
#include "gtm_string.h"
|
|
|
|
#include "gdsroot.h"
|
|
#include "gdskill.h"
|
|
#include "gtm_facility.h"
|
|
#include "fileinfo.h"
|
|
#include "gdsbt.h"
|
|
#include "gdsfhead.h"
|
|
#include "copy.h"
|
|
#include "gdscc.h" /* needed for tp.h */
|
|
#include "filestruct.h" /* needed for tp.h */
|
|
#include "jnl.h" /* needed for tp.h */
|
|
#include "buddy_list.h" /* needed for tp.h */
|
|
#include "hashtab_int4.h" /* needed for tp.h */
|
|
#include "tp.h"
|
|
#include "op.h"
|
|
|
|
#define DIR_ROOT 1
|
|
|
|
GBLREF gd_binding *gd_map;
|
|
GBLREF gd_region *gv_cur_region;
|
|
GBLREF gv_key *gv_currkey;
|
|
GBLREF gv_namehead *gv_target;
|
|
GBLREF sgm_info *first_sgm_info, *sgm_info_ptr;
|
|
GBLREF sgmnt_addrs *cs_addrs;
|
|
GBLREF sgmnt_data *cs_data;
|
|
GBLREF uint4 dollar_tlevel;
|
|
|
|
void op_gvrectarg(mval *v)
|
|
{
|
|
int len;
|
|
unsigned char *c;
|
|
short end;
|
|
sgm_info *si;
|
|
gd_region *reg;
|
|
gvsavtarg_t *gvsavtarg, gvst_tmp;
|
|
DEBUG_ONLY(
|
|
int n;
|
|
unsigned char *tmpc;
|
|
)
|
|
DCL_THREADGBL_ACCESS;
|
|
|
|
SETUP_THREADGBL_ACCESS;
|
|
/* You might be somewhat apprehensive at the seemingly cavalier use of GTMASSERT in this routine.
|
|
* First, let me explain myself. The mvals passed to RECTARG are supposed to come only from SAVTARG,
|
|
* and are to represent the state of gv_currkey when SAVTARG was done. Consequently, there are
|
|
* certain preconditions that one can expect. Namely,
|
|
* 1) SAVTARG makes all mvals MV_STR's. If this one isn't, it should be.
|
|
* 2) If gv_currkey existed for SAVTARG (len is > 0), it had better exist for RECTARG.
|
|
* 3) All gv_keys end with 00. When reading this mval, if you run out of characters
|
|
* before you see a 0, something is amiss.
|
|
*/
|
|
if (!MV_IS_STRING(v))
|
|
GTMASSERT;
|
|
len = v->str.len;
|
|
if (0 == len)
|
|
{
|
|
if (NULL != gv_currkey)
|
|
{ /* Reset gv_currkey.
|
|
* The following code (should be maintained in parallel with similar code in op_svput.c.
|
|
*/
|
|
gv_currkey->end = gv_currkey->prev = 0;
|
|
gv_currkey->base[0] = KEY_DELIMITER;
|
|
}
|
|
return;
|
|
}
|
|
if (NULL == gv_currkey)
|
|
GTMASSERT;
|
|
assert(GVSAVTARG_FIXED_SIZE <= len);
|
|
c = (unsigned char *)v->str.addr;
|
|
/* op_gvsavtarg had ensured 8-byte alignment of v->str.addr but it is possible a "stp_gcol" was invoked in between
|
|
* which could have repointed v->str.addr to a non-8-byte-aligned address. In this rare case, do special processing
|
|
* before dereferencing the fields of the structure.
|
|
*/
|
|
if ((UINTPTR_T)c == ROUND_UP2((UINTPTR_T)c, GVSAVTARG_ALIGN_BNDRY))
|
|
gvsavtarg = (gvsavtarg_t *)c;
|
|
else
|
|
{
|
|
gvsavtarg = &gvst_tmp;
|
|
memcpy(gvsavtarg, c, GVSAVTARG_FIXED_SIZE);
|
|
}
|
|
TREF(gd_targ_addr) = gvsavtarg->gd_targ_addr;
|
|
gd_map = gvsavtarg->gd_map;
|
|
reg = gvsavtarg->gv_cur_region;
|
|
TP_CHANGE_REG(reg); /* sets gv_cur_region, cs_addrs, cs_data */
|
|
gv_target = gvsavtarg->gv_target;
|
|
assert(dollar_tlevel || ((NULL == first_sgm_info) && (NULL == sgm_info_ptr)));
|
|
if (dollar_tlevel)
|
|
{ /* Restore sgm_info_ptr if needed.
|
|
* a) If first_sgm_info is NULL (possible if op_gvrectarg is called as part of tp restart handling),
|
|
* then no region is included in this TP so set sgm_info_ptr to NULL.
|
|
* b) If the region has not yet been opened in this TP transaction (si->fresh_start is TRUE), then
|
|
* again set sgm_info_ptr to NULL.
|
|
* c) If the region corresponding to the restored $reference has already been opened as part
|
|
* of this TP transaction, then set sgm_info_ptr to point to the corresponding tp structure.
|
|
*/
|
|
assert(cs_addrs == gv_target->gd_csa);
|
|
si = cs_addrs->sgm_info_ptr;
|
|
if ((NULL != first_sgm_info) && !si->fresh_start)
|
|
{ /* Case (c) */
|
|
sgm_info_ptr = si;
|
|
DBG_CHECK_IN_FIRST_SGM_INFO_LIST(si);
|
|
} else
|
|
{ /* Case (a) OR (b).
|
|
* In case of (b), note that first_sgm_info could be non-NULL while sgm_info_ptr is NULL.
|
|
* We can fix the latter to be a non-NULL value by invoking "tp_set_sgm". But we dont want
|
|
* to do that here because it can cause restarts (due to the "insert_region" call) and this
|
|
* function can be invoked by "gtm_trigger_fini" which cannot handle tp restarts within.
|
|
* We therefore keep first_sgm_info and sgm_info_ptr temporarily out-of-sync until the NEXT
|
|
* global reference (op_gvname, op_gvnaked or op_gvextnam) which would invoke "tp_set_sgm".
|
|
* The two need to be in sync BEFORE any database functions (gvcst_search.c, gvcst_get.c etc.)
|
|
* are invoked as they assume sgm_info_ptr is non-NULL if dollar_tlevel is non-zero.
|
|
*/
|
|
sgm_info_ptr = NULL;
|
|
}
|
|
assert((NULL != first_sgm_info) || (NULL == sgm_info_ptr));
|
|
}
|
|
TREF(gv_last_subsc_null) = gvsavtarg->gv_last_subsc_null;
|
|
TREF(gv_some_subsc_null) = gvsavtarg->gv_some_subsc_null;
|
|
gv_currkey->prev = gvsavtarg->prev;
|
|
gv_currkey->end = end = gvsavtarg->end;
|
|
assert(gv_currkey->end < gv_currkey->top);
|
|
c += GVSAVTARG_FIXED_SIZE;
|
|
assert(end == (len - GVSAVTARG_FIXED_SIZE));
|
|
if (0 < end)
|
|
{
|
|
memcpy(gv_currkey->base, c, end);
|
|
assert(KEY_DELIMITER == gv_currkey->base[end - 1]);
|
|
}
|
|
gv_currkey->base[end] = KEY_DELIMITER;
|
|
DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC;
|
|
DBG_CHECK_GVTARGET_CSADDRS_IN_SYNC;
|
|
return;
|
|
}
|