fis-gtm/sr_port/op_gvrectarg.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;
}