File: trigger_fill_xecute_buffer.c

package info (click to toggle)
fis-gtm 7.1-006-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 32,908 kB
  • sloc: ansic: 344,906; asm: 5,184; csh: 4,859; sh: 2,000; awk: 294; makefile: 73; sed: 13
file content (202 lines) | stat: -rw-r--r-- 9,477 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/****************************************************************
 *								*
 * Copyright (c) 2010-2020 Fidelity National Information	*
 * Services, Inc. and/or its subsidiaries. All rights reserved.	*
 *								*
 *	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"

#ifdef GTM_TRIGGER

#include "gdsroot.h"			/* for gdsfhead.h */
#include "gdsbt.h"			/* for gdsfhead.h */
#include "gdsfhead.h"
#include "gvcst_protos.h"
#include <rtnhdr.h>
#include "gv_trigger.h"
#include "trigger.h"
#include "mv_stent.h"			/* for COPY_SUBS_TO_GVCURRKEY macro */
#include "gvsub2str.h"			/* for COPY_SUBS_TO_GVCURRKEY */
#include "format_targ_key.h"		/* for COPY_SUBS_TO_GVCURRKEY */
#include "targ_alloc.h"			/* for SET_GVTARGET_TO_HASHT_GBL */
#include "filestruct.h"			/* for INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED (FILE_INFO) */
#include "mvalconv.h"
#include "gdscc.h"			/* needed for tp.h */
#include "gdskill.h"			/* needed for tp.h */
#include "buddy_list.h"			/* needed for tp.h */
#include "jnl.h"			/* needed for tp.h */
#include "tp.h"				/* for sgm_info */
#include "tp_frame.h"
#include "tp_restart.h"
#include "tp_set_sgm.h"
#include "t_retry.h"
#include "op.h"
#include "op_tcommit.h"
#include "memcoherency.h"
#include "gtmimagename.h"
#include "trigger_fill_xecute_buffer.h"
#include "trigger_gbl_fill_xecute_buffer.h"
#include "gtm_trigger_trc.h"
#include "repl_msg.h"
#include "gtmsource.h"			/* for jnlpool_addrs_ptr_t */

GBLREF	sgmnt_data_ptr_t	cs_data;
GBLREF	sgmnt_addrs		*cs_addrs;
GBLREF	int4			gtm_trigger_depth;
GBLREF	gv_key			*gv_currkey;
GBLREF	gd_region		*gv_cur_region;
GBLREF	gv_namehead		*gv_target;
#ifdef DEBUG
GBLREF	boolean_t		is_updproc;
#endif
GBLREF	jnlpool_addrs_ptr_t	jnlpool;
GBLREF	sgm_info		*sgm_info_ptr;
GBLREF	boolean_t		skip_INVOKE_RESTART;
GBLREF	int			tprestart_state;
GBLREF	tp_frame		*tp_pointer;
GBLREF	int4			tstart_trigger_depth;

error_def(ERR_TPRETRY);

STATICFNDCL CONDITION_HANDLER(trigger_fill_xecute_buffer_ch);
STATICFNDCL void trigger_fill_xecute_buffer_read_trigger_source(gv_trigger_t *trigdsc);

/* Similar condition handler to above without the tp-restart - just unwind and let caller do the restart */
CONDITION_HANDLER(trigger_fill_xecute_buffer_ch)
{
	START_CH(TRUE);
	if ((int)ERR_TPRETRY == SIGNAL)
	{
		UNWIND(NULL, NULL);
	}
	NEXTCH;
}

int trigger_fill_xecute_buffer(gv_trigger_t *trigdsc)
{
	int	src_fetch_status;

	assert(!dollar_tlevel || (tstart_trigger_depth <= gtm_trigger_depth));
	/* We have 3 cases to consider - all of which REQUIRE a TP fence to already be in effect. The reason for this is, if we
	 * detect a restartable condition, we are going to cause this region's triggers to be unloaded which destroys the block
	 * our parameter is pointing to so the restart logic MUST take place outside of this routine.
	 *
	 *   1. We have an active transaction due to an IMPLICIT TSTART done by trigger handling but the trigger level has not yet
	 *	been created. We don't need another TP wrapper in this case but we do need a condition handler to trap the thrown
	 *	retry to again prevent C stack unwind and return to the caller in the same shape that gtm_trigger would return.
	 *   2. We have an active transaction due to an EXPLICIT M-code TSTART command. For this case, the trigger loads proceed
	 *   	as normal with restarts handled in the regular automatic fashion. Note this case also covers the tp restarts done
	 *	by both the update process and mupip recover forward since those functions have their own way of intercepting and
	 *	dealing with restarts. To cover those cases, tp->implicit_tstart can be TRUE but tp_implicit_trigger MUST be
	 *	FALSE.
	 *   3. We have an active transaction due to an IMPLICIT TSTART done by trigger handling and one or more triggers are
	 *	running. This becomes like case 2 since the restart will be handled by gtm_trigger and the proper thing will
	 *	be done.
	 *
	 * An extra note about case 3. Case 3 can be the identified case if in a nested trigger we are in trigger-no-mans-land
	 * with a base frame for the nested trigger (having driven one of a set of parallel nested triggers) but no actual trigger
	 * execution frame yet exists. This is really a case 1 situation with a nested trigger but it turns out that dealing with
	 * like case 3 does the right thing because if/when mdb_condition_handler catches a thrown TPRETRY error, mdb_condition
	 * handler will peal the nested trigger frame off before doing the restart which works for us and avoids issues of
	 * multi-level implicit restarts we would otherwise have to handle.
	 *
	 * Note, this routine is for loading trigger source when the trigger is to be driven. The trigger_source_read_andor_verify()
	 * routine should be used when fetching trigger source for reasons other than driving the triggers. This routine is lighter
	 * weight but has a dependence on the restartability of the trigger-drive logic for getting the triggers reloaded as
	 * necessary.
	 */
	assertpro(0 < dollar_tlevel);
	if (!tp_pointer->implicit_trigger		/* Case 2 */
		|| (tp_pointer->implicit_tstart && tp_pointer->implicit_trigger
		&& (tstart_trigger_depth != gtm_trigger_depth)))	/* Case 3 */
	{	/* Test for Case 3/4 where we get to do very little: */
		DBGTRIGR((stderr, "trigger_fill_xecute_buffer: Case 2/3\n"));
		assert((!tp_pointer->implicit_trigger) || (0 < gtm_trigger_depth));
		trigger_fill_xecute_buffer_read_trigger_source(trigdsc);
	} else
	{	/* Test for Case 1 where we only need a condition handler */
		DBGTRIGR((stderr, "trigger_fill_xecute_buffer: Case 1\n"));
		assert(tp_pointer->implicit_tstart && tp_pointer->implicit_trigger);
		assert(tstart_trigger_depth == gtm_trigger_depth);
		ESTABLISH_RET(trigger_fill_xecute_buffer_ch, SIGNAL);
		trigger_fill_xecute_buffer_read_trigger_source(trigdsc);
		REVERT;
	}
	/* return our bounty to caller */
	trigdsc->xecute_str.mvtype = MV_STR;
	return 0;	/* Could return ERR_TPRETRY if return is via our condition handler */
}

/* Workhorse of fetching source for given trigger.
 */
STATICFNDEF void trigger_fill_xecute_buffer_read_trigger_source(gv_trigger_t *trigdsc)
{
	enum cdb_sc		cdb_status;
	int4			index;
	mstr			gbl, xecute_buff;
	mval			trig_index;
	sgmnt_addrs		*csa;
	sgmnt_data_ptr_t	csd;
	gvt_trigger_t		*gvt_trigger;
	gv_namehead		*gvt;
	gv_namehead		*save_gv_target;
	gd_region		*save_gv_cur_region;
	sgm_info		*save_sgm_info_ptr;
	jnlpool_addrs_ptr_t	save_jnlpool;
	gv_key_buf		save_currkey;

	assert(0 < dollar_tlevel);
	assert(NULL != trigdsc);
	SAVE_REGION_INFO(save_currkey, save_gv_target, save_gv_cur_region, save_sgm_info_ptr, save_jnlpool);

	gvt_trigger = trigdsc->gvt_trigger;			/* We now know our base block now */
	index = trigdsc - gvt_trigger->gv_trig_array + 1;	/* We now know our trigger index value */
	i2mval(&trig_index, index);
	DBGTRIGR((stderr, "trigger_fill_xecute_buffer_read_trigger_source: entry $tlevel:%d\tindex:%d of %d\n",
				dollar_tlevel, index, gvt_trigger->num_gv_triggers));
	gvt = gv_target = gvt_trigger->gv_target;		/* gv_target contains global name */
	gbl.addr = gvt->gvname.var_name.addr;
	gbl.len = gvt->gvname.var_name.len;
	/* Our situation is that while our desired gv_target has csa information, we don't know specifically
	 * which global directory was in use so we can't run gv_bind_name() lest we find the given global
	 * name in the wrong global directory thus running the wrong triggers. But we know this target is
	 * properly formed since it had to be when it was recorded when the triggers were loaded. Because of
	 * that, we can get the correct csa and gv_target and csa-region will point us to a region that will
	 * work even if it isn't exactly the one we used to get to this trigger.
	 */
	TP_CHANGE_REG_IF_NEEDED(gvt->gd_csa->region);
	csa = cs_addrs;
	csd = csa->hdr;
	assert(csd == cs_data);
	tp_set_sgm();
	/* See if we need to reload our triggers */
	if ((csa->db_trigger_cycle != gvt->db_trigger_cycle)
	    || (csa->db_dztrigger_cycle && (gvt->db_dztrigger_cycle != csa->db_dztrigger_cycle)))
	{       /* The process' view of the triggers is likely stale. Restart to be safe.
		 * Triggers can be invoked only by GT.M and Update process. We expect to see GT.M processes to
		 * restart due to concurrent trigger changes. The Update Process should only restart if it is a
		 * supplementary instance. Assert accordingly. Note similar asserts occur in t_end.c and
		 * tp_tend.c.
		 */
		DBGTRIGR((stderr, "trigger_fill_xecute_buffer_read_trigger_source: stale trigger view\n"));
		assert(CDB_STAGNATE > t_tries);
		assert(!is_updproc || (jnlpool && jnlpool->repl_inst_filehdr->is_supplementary
					&& !jnlpool->jnlpool_ctl->upd_disabled));
		t_retry(cdb_sc_triggermod);
	}
	SET_GVTARGET_TO_HASHT_GBL(csa);
	INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
	assert(0 == trigdsc->xecute_str.str.len);	/* Make sure not replacing/losing a buffer */
	xecute_buff.addr = trigger_gbl_fill_xecute_buffer(gbl.addr, gbl.len, &trig_index, NULL, (int4 *)&xecute_buff.len);
	trigdsc->xecute_str.str = xecute_buff;
	/* Restore gv_target/gv_currkey which need to be kept in sync */
	RESTORE_REGION_INFO(save_currkey, save_gv_target, save_gv_cur_region, save_sgm_info_ptr, save_jnlpool);
	return;
}
#endif /* GTM_TRIGGER */