2012-02-05 11:35:58 -05:00
|
|
|
/****************************************************************
|
|
|
|
* *
|
2024-07-19 11:43:27 -04:00
|
|
|
* Copyright 2001, 2012 Fidelity Information Services, Inc *
|
2012-02-05 11:35:58 -05:00
|
|
|
* *
|
|
|
|
* 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 "gdsblk.h"
|
|
|
|
#include "gtm_facility.h"
|
|
|
|
#include "fileinfo.h"
|
|
|
|
#include "gdsbt.h"
|
|
|
|
#include "gdsfhead.h"
|
|
|
|
#include "cdb_sc.h"
|
|
|
|
#include "filestruct.h" /* needed for jnl.h */
|
|
|
|
#include "gdscc.h" /* needed for tp.h */
|
|
|
|
#include "jnl.h" /* needed for tp.h */
|
|
|
|
#include "gdskill.h" /* needed for tp.h */
|
|
|
|
#include "buddy_list.h" /* needed for tp.h */
|
|
|
|
#include "hashtab_int4.h" /* needed for tp.h */
|
|
|
|
#include "tp.h" /* needed for T_BEGIN_READ_NONTP_OR_TP macro */
|
2024-07-19 11:43:27 -04:00
|
|
|
#ifdef UNIX /* needed for frame_pointer in GVCST_ROOT_SEARCH_AND_PREP macro */
|
|
|
|
# include "repl_msg.h"
|
|
|
|
# include "gtmsource.h"
|
|
|
|
# include "rtnhdr.h"
|
|
|
|
# include "stack_frame.h"
|
|
|
|
#endif
|
2012-02-05 11:35:58 -05:00
|
|
|
|
|
|
|
#include "t_end.h" /* prototypes */
|
|
|
|
#include "t_retry.h"
|
|
|
|
#include "t_begin.h"
|
|
|
|
#include "gvcst_expand_key.h"
|
|
|
|
#include "gvcst_protos.h" /* for gvcst_lftsib,gvcst_search,gvcst_search_blk,gvcst_zprevious prototype */
|
|
|
|
|
2024-07-19 11:43:27 -04:00
|
|
|
/* needed for spanning nodes */
|
|
|
|
#include "op.h"
|
|
|
|
#include "op_tcommit.h"
|
|
|
|
#include "error.h"
|
|
|
|
#include "tp_frame.h"
|
|
|
|
#include "tp_restart.h"
|
|
|
|
#include "gtmimagename.h"
|
|
|
|
|
|
|
|
LITREF mval literal_batch;
|
|
|
|
|
2012-02-05 11:35:58 -05:00
|
|
|
GBLREF sgmnt_data_ptr_t cs_data;
|
|
|
|
GBLREF sgmnt_addrs *cs_addrs;
|
|
|
|
GBLREF gd_region *gv_cur_region;
|
|
|
|
GBLREF gv_namehead *gv_target;
|
|
|
|
GBLREF gv_key *gv_currkey, *gv_altkey;
|
|
|
|
GBLREF int4 gv_keysize;
|
|
|
|
GBLREF uint4 dollar_tlevel;
|
|
|
|
GBLREF unsigned int t_tries;
|
|
|
|
|
2024-07-19 11:43:27 -04:00
|
|
|
error_def(ERR_DBROLLEDBACK);
|
2012-03-24 14:06:46 -04:00
|
|
|
error_def(ERR_GVORDERFAIL);
|
2024-07-19 11:43:27 -04:00
|
|
|
error_def(ERR_TPRETRY);
|
|
|
|
|
|
|
|
DEFINE_NSB_CONDITION_HANDLER(gvcst_zprevious_ch)
|
2012-03-24 14:06:46 -04:00
|
|
|
|
2012-02-05 11:35:58 -05:00
|
|
|
bool gvcst_zprevious(void)
|
2024-07-19 11:43:27 -04:00
|
|
|
{ /* See gvcst_query.c */
|
|
|
|
bool found, is_hidden, sn_tpwrapped;
|
|
|
|
boolean_t est_first_pass;
|
|
|
|
char save_currkey[SIZEOF(gv_key) + DBKEYSIZE(MAX_KEY_SZ)];
|
|
|
|
gv_key *save_gv_currkey;
|
|
|
|
int end, prev, oldend;
|
|
|
|
int save_dollar_tlevel;
|
|
|
|
|
|
|
|
DEBUG_ONLY(save_dollar_tlevel = dollar_tlevel);
|
|
|
|
found = gvcst_zprevious2();
|
|
|
|
# ifdef UNIX
|
|
|
|
assert(save_dollar_tlevel == dollar_tlevel);
|
|
|
|
CHECK_HIDDEN_SUBSCRIPT_AND_RETURN(found, gv_altkey, is_hidden);
|
|
|
|
assert(found && is_hidden);
|
|
|
|
IF_SN_DISALLOWED_AND_NO_SPAN_IN_DB(return found);
|
|
|
|
SAVE_GV_CURRKEY_LAST_SUBSCRIPT(gv_currkey, prev, oldend);
|
|
|
|
if (!dollar_tlevel)
|
|
|
|
{
|
|
|
|
sn_tpwrapped = TRUE;
|
|
|
|
op_tstart((IMPLICIT_TSTART), TRUE, &literal_batch, 0);
|
|
|
|
ESTABLISH_NORET(gvcst_zprevious_ch, est_first_pass);
|
|
|
|
GVCST_ROOT_SEARCH_AND_PREP(est_first_pass);
|
|
|
|
} else
|
|
|
|
sn_tpwrapped = FALSE;
|
|
|
|
INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_zprev, (gtm_uint64_t) -1);
|
|
|
|
found = gvcst_zprevious2();
|
|
|
|
if (found)
|
|
|
|
{
|
|
|
|
CHECK_HIDDEN_SUBSCRIPT(gv_altkey, is_hidden);
|
|
|
|
if (is_hidden)
|
|
|
|
{ /* Replace last subscript to be the lowest possible hidden subscript so another
|
|
|
|
* gvcst_zprevious2 will give us the previous non-hidden subscript.
|
|
|
|
*/
|
|
|
|
end = gv_altkey->end;
|
|
|
|
gv_currkey->base[end - 4] = 2;
|
|
|
|
gv_currkey->base[end - 3] = 1;
|
|
|
|
gv_currkey->base[end - 2] = 1;
|
|
|
|
gv_currkey->base[end - 1] = 0;
|
|
|
|
gv_currkey->base[end + 0] = 0;
|
|
|
|
gv_currkey->end = end;
|
|
|
|
/* fix up since it should only be externally counted as one $zprevious */
|
|
|
|
INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_zprev, (gtm_uint64_t) -1);
|
|
|
|
found = gvcst_zprevious2();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (sn_tpwrapped)
|
|
|
|
{
|
|
|
|
op_tcommit();
|
|
|
|
REVERT; /* remove our condition handler */
|
|
|
|
}
|
|
|
|
RESTORE_GV_CURRKEY_LAST_SUBSCRIPT(gv_currkey, prev, oldend);
|
|
|
|
assert(save_dollar_tlevel == dollar_tlevel);
|
|
|
|
# endif
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool gvcst_zprevious2(void)
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
|
|
|
static gv_key *zprev_temp_key;
|
|
|
|
static int4 zprev_temp_keysize = 0;
|
|
|
|
blk_hdr_ptr_t bp;
|
|
|
|
bool found, two_histories;
|
|
|
|
enum cdb_sc status;
|
|
|
|
rec_hdr_ptr_t rp;
|
|
|
|
unsigned char *c1, *c2, *ctop;
|
|
|
|
srch_blk_status *bh;
|
|
|
|
srch_hist *lft_history;
|
|
|
|
|
|
|
|
T_BEGIN_READ_NONTP_OR_TP(ERR_GVORDERFAIL);
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
assert(t_tries < CDB_STAGNATE || cs_addrs->now_crit); /* we better hold crit in the final retry (TP & non-TP) */
|
|
|
|
two_histories = FALSE;
|
|
|
|
if (cdb_sc_normal == (status = gvcst_search(gv_currkey, NULL)))
|
|
|
|
{
|
|
|
|
found = TRUE;
|
|
|
|
bh = gv_target->hist.h;
|
|
|
|
if (0 == bh->prev_rec.offset)
|
|
|
|
{
|
|
|
|
two_histories = TRUE;
|
|
|
|
lft_history = gv_target->alt_hist;
|
|
|
|
status = gvcst_lftsib(lft_history);
|
|
|
|
if (cdb_sc_normal == status)
|
|
|
|
{
|
|
|
|
bh = lft_history->h;
|
|
|
|
if (cdb_sc_normal != (status = gvcst_search_blk(gv_currkey, bh)))
|
|
|
|
{
|
|
|
|
t_retry(status);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else if (cdb_sc_endtree == status)
|
|
|
|
{
|
|
|
|
found = FALSE;
|
|
|
|
two_histories = FALSE; /* second history not valid */
|
|
|
|
} else
|
|
|
|
{
|
|
|
|
t_retry(status);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found)
|
|
|
|
{ /* store new subscipt */
|
|
|
|
assert(gv_altkey->top == gv_currkey->top);
|
|
|
|
assert(gv_altkey->top == gv_keysize);
|
|
|
|
assert(gv_currkey->end < gv_currkey->top);
|
|
|
|
rp = (rec_hdr_ptr_t)(bh->buffaddr + bh->prev_rec.offset);
|
|
|
|
bp = (blk_hdr_ptr_t)bh->buffaddr;
|
|
|
|
c1 = gv_altkey->base;
|
|
|
|
memcpy(c1, gv_currkey->base, bh->prev_rec.match);
|
|
|
|
c1 += bh->prev_rec.match;
|
|
|
|
assert(zprev_temp_keysize <= gv_keysize);
|
|
|
|
if (zprev_temp_keysize < gv_keysize)
|
|
|
|
{
|
|
|
|
zprev_temp_keysize = gv_keysize;
|
|
|
|
GVKEY_INIT(zprev_temp_key, zprev_temp_keysize);
|
|
|
|
}
|
|
|
|
assert(zprev_temp_key->top >= gv_currkey->top);
|
|
|
|
if (cdb_sc_normal != (status = gvcst_expand_key((blk_hdr_ptr_t)bh->buffaddr, bh->prev_rec.offset,
|
|
|
|
zprev_temp_key)))
|
|
|
|
{
|
|
|
|
t_retry(status);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ((zprev_temp_key->end < gv_currkey->end) && (zprev_temp_key->end <= gv_currkey->prev))
|
|
|
|
found = FALSE;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
c2 = zprev_temp_key->base + bh->prev_rec.match;
|
|
|
|
ctop = zprev_temp_key->base + zprev_temp_key->end;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
if (c2 >= ctop)
|
|
|
|
{
|
|
|
|
assert(CDB_STAGNATE > t_tries);
|
|
|
|
status = cdb_sc_rmisalign;
|
|
|
|
goto restart; /* goto needed because of nested FOR loop */
|
|
|
|
}
|
|
|
|
if (0 == (*c1++ = *c2++))
|
|
|
|
{
|
|
|
|
*c1 = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
gv_altkey->end = c1 - gv_altkey->base;
|
|
|
|
assert(gv_altkey->end < gv_altkey->top);
|
|
|
|
}
|
|
|
|
if (!dollar_tlevel)
|
|
|
|
{
|
|
|
|
if ((trans_num)0 == t_end(&gv_target->hist, two_histories ? lft_history : NULL, TN_NOT_SPECIFIED))
|
|
|
|
continue;
|
|
|
|
} else
|
|
|
|
{
|
|
|
|
status = tp_hist(two_histories ? lft_history : NULL);
|
|
|
|
if (cdb_sc_normal != status)
|
|
|
|
{
|
|
|
|
t_retry(status);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert(cs_data == cs_addrs->hdr);
|
|
|
|
INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_zprev, 1);
|
|
|
|
return (found && (bh->prev_rec.match >= gv_currkey->prev));
|
|
|
|
}
|
|
|
|
restart: t_retry(status);
|
|
|
|
}
|
|
|
|
}
|