File: mu_rndwn_replpool.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 (318 lines) | stat: -rw-r--r-- 12,947 bytes parent folder | download | duplicates (2)
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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
/****************************************************************
 *								*
 * Copyright (c) 2001-2023 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"

#include "gtm_unistd.h"
#include "gtm_inet.h"
#include "gtm_stdlib.h"
#include "gtm_string.h"
#include "gtm_stat.h"
#include "gtm_stdio.h"
#include "gtm_fcntl.h"

#include "gtm_ipc.h"
#include <sys/shm.h>
#include <errno.h>
#include <stddef.h>
#include <sys/sem.h>

#include "gdsroot.h"
#include "gdsblk.h"
#include "gtm_facility.h"
#include "fileinfo.h"
#include "gdsbt.h"
#include "gdsfhead.h"
#include "filestruct.h"
#include "iosp.h"
#include "gtmio.h"
#include "repl_instance.h"
#include "mutex.h"
#include "jnl.h"
#include "repl_sem.h"
#include "eintr_wrappers.h"
#include "mu_rndwn_file.h"
#include "repl_msg.h"
#include "gtmsource.h"
#include "gtmrecv.h"
#include "mu_rndwn_replpool.h"
#include "ipcrmid.h"
#include "do_semop.h"
#include "util.h"
#include "gtmmsg.h"
#include "gtm_sem.h"
#include "do_shmat.h"	/* for do_shmat() prototype */
#include "buddy_list.h"		/* needed for muprec.h */
#include "hashtab_int4.h"	/* needed for muprec.h */
#include "hashtab_int8.h"	/* needed for muprec.h */
#include "hashtab_mname.h"	/* needed for muprec.h */
#include "muprec.h"
#include "error.h"
#include "anticipatory_freeze.h"

GBLREF	boolean_t		argumentless_rundown;
GBLREF	jnl_gbls_t		jgbl;
GBLREF	jnlpool_addrs_ptr_t	jnlpool;
GBLREF	recvpool_addrs		recvpool;
GBLREF	mur_gbls_t		murgbl;
GBLREF	mur_opt_struct		mur_options;
GBLREF	uint4			mutex_per_process_init_pid;
GBLREF	uint4			process_id;
#ifdef DEBUG
GBLREF	bool			only_usr_jnlpool_flush;
#endif

LITREF char             	gtm_release_name[];
LITREF int4             	gtm_release_name_len;

error_def(ERR_REPLACCSEM);
error_def(ERR_REPLINSTOPEN);
error_def(ERR_REPLPOOLINST);
error_def(ERR_SYSCALL);
error_def(ERR_TEXT);

#define DETACH(START_ADDR, SHM_ID, INSTFILENAME)					\
{											\
	int		lcl_save_errno;							\
											\
	if (-1 == shmdt((void *)START_ADDR))						\
	{										\
		lcl_save_errno = errno;							\
		ISSUE_REPLPOOLINST(lcl_save_errno, SHM_ID, INSTFILENAME, "shmdt()");	\
	}										\
}

int     mu_rndwn_replpool2(replpool_identifier *replpool_id, repl_inst_hdr_ptr_t repl_inst_filehdr, int shm_id, boolean_t *ipc_rmvd,
			   char *instfilename, sm_uc_ptr_t start_addr, int nattch)
{
	int			save_errno, status;
	char			pool_type;
	unix_db_info		*udi;
	sgmnt_addrs		*csa;
	gd_region		*reg;
	boolean_t		anticipatory_freeze_available, reset_crash;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	pool_type = replpool_id->pool_type;
	anticipatory_freeze_available = INST_FREEZE_ON_ERROR_POLICY;
	/* assert that the identifiers are at the top of replpool control structure */
	assert(0 == offsetof(jnlpool_ctl_struct, jnlpool_id));
	assert(0 == offsetof(recvpool_ctl_struct, recvpool_id));
	memcpy((void *)replpool_id, (void *)start_addr, SIZEOF(replpool_identifier));
	if (memcmp(replpool_id->label, GDS_RPL_LABEL, GDS_LABEL_SZ - 1))
	{
		if (!memcmp(replpool_id->label, GDS_RPL_LABEL, GDS_LABEL_SZ - 3))
			util_out_print(
				"Incorrect version for the replpool segment (id = !UL) belonging to replication instance !AD",
					TRUE, shm_id, LEN_AND_STR(instfilename));
		else
			util_out_print("Incorrect replpool format for the segment (id = !UL) belonging to replication instance !AD",
					TRUE, shm_id, LEN_AND_STR(instfilename));
		DETACH(start_addr, shm_id, instfilename);
		return -1;
	}
	if (memcmp(replpool_id->now_running, gtm_release_name, gtm_release_name_len + 1))
	{
		util_out_print("Attempt to access with version !AD, while already using !AD for replpool segment (id = !UL)"
				" belonging to replication instance !AD.", TRUE, gtm_release_name_len, gtm_release_name,
				LEN_AND_STR(replpool_id->now_running), shm_id, LEN_AND_STR(instfilename));
		DETACH(start_addr, shm_id, instfilename);
		return -1;
	}
	reset_crash = (!anticipatory_freeze_available || argumentless_rundown);
	/* Assert that if we haven't yet attached to the journal pool yet, jnlpool_ctl better be NULL */
	assert((JNLPOOL_SEGMENT != pool_type) || ((NULL == jnlpool) || (NULL == jnlpool->jnlpool_ctl)));
	if (JNLPOOL_SEGMENT == pool_type)
	{	/* Initialize variables to simulate a "jnlpool_init". This is required by "repl_inst_flush_jnlpool" called below */
		SET_JNLPOOL_FROM_RECVPOOL_P(jnlpool);
		jnlpool->jnlpool_ctl = (jnlpool_ctl_ptr_t)start_addr;
		assert(NULL != jnlpool->jnlpool_dummy_reg);
		udi = FILE_INFO(jnlpool->jnlpool_dummy_reg);
		csa = &udi->s_addrs;
		csa->critical = (CRIT_PTR_T)((sm_uc_ptr_t)jnlpool->jnlpool_ctl + JNLPOOL_CTL_SIZE);
		csa->nl = (node_local_ptr_t)((sm_uc_ptr_t)csa->critical + JNLPOOL_CRIT_SPACE + SIZEOF(mutex_spin_parms_struct));
		/* secshr_db_clnup uses this relationship */
		assert(jnlpool->jnlpool_ctl->filehdr_off);
		assert(jnlpool->jnlpool_ctl->srclcl_array_off > jnlpool->jnlpool_ctl->filehdr_off);
		assert(jnlpool->jnlpool_ctl->sourcelocal_array_off > jnlpool->jnlpool_ctl->srclcl_array_off);
		/* Initialize "jnlpool->repl_inst_filehdr" and related fields as "repl_inst_flush_jnlpool" relies on that */
		jnlpool->repl_inst_filehdr = (repl_inst_hdr_ptr_t)((sm_uc_ptr_t)jnlpool->jnlpool_ctl
									+ jnlpool->jnlpool_ctl->filehdr_off);
		jnlpool->gtmsrc_lcl_array = (gtmsrc_lcl_ptr_t)((sm_uc_ptr_t)jnlpool->jnlpool_ctl
									+ jnlpool->jnlpool_ctl->srclcl_array_off);
		jnlpool->gtmsource_local_array = (gtmsource_local_ptr_t)((sm_uc_ptr_t)jnlpool->jnlpool_ctl
										+ jnlpool->jnlpool_ctl->sourcelocal_array_off);
		if (0 == nattch)
		{	/* No one attached. So, we can safely flush the journal pool so that the gtmsrc_lcl structures in the
			 * jnlpool and disk are in sync with each other. More importantly we are about to remove the jnlpool
			 * so we better get things in sync before that. If anticipatory freeze scheme is in effect, then we
			 * need to keep the journal pool up and running. So, don't reset the crash field in the instance file
			 * header (dictated by the second parameter to repl_inst_flush_jnlpool below).
			 * Note:
			 * If mu_rndwn_repl_instance created new semaphores (in mu_replpool_remove_sem), we need to flush those
			 * to the instance file as well. So, override the jnlpool_semid and jnlpool_semid_ctime with the new
			 * values.
			 */
			assert((INVALID_SEMID != repl_inst_filehdr->jnlpool_semid)
					&& (0 != repl_inst_filehdr->jnlpool_semid_ctime));
			jnlpool->repl_inst_filehdr->jnlpool_semid = repl_inst_filehdr->jnlpool_semid;
			jnlpool->repl_inst_filehdr->jnlpool_semid_ctime = repl_inst_filehdr->jnlpool_semid_ctime;
			DEBUG_ONLY(only_usr_jnlpool_flush = true;)
			repl_inst_flush_jnlpool(FALSE, reset_crash);
			DEBUG_ONLY(only_usr_jnlpool_flush = false;)
			assert(!jnlpool->repl_inst_filehdr->crash || !reset_crash);
			/* Refresh local copy (repl_inst_filehdr) with the copy that was just
				flushed (jnlpool->repl_inst_filehdr) */
			memcpy(repl_inst_filehdr, jnlpool->repl_inst_filehdr, SIZEOF(repl_inst_hdr));
			if (reset_crash)
			{ 	/* Now that jnlpool has been flushed and there is going to be no journal pool, reset
				 * "jnlpool->repl_inst_filehdr" as otherwise other routines (e.g. "repl_inst_recvpool_reset") are
				 * affected by whether this is NULL or not.
				 */
				JNLPOOL_CLEAR_FIELDS(jnlpool);
			}
		} /* else we are ONLINE ROLLBACK. repl_inst_flush_jnlpool will be done later after gvcst_init in mur_open_files */
	}
	if ((0 == nattch) && (reset_crash || (RECVPOOL_SEGMENT == pool_type)))
	{
		if (-1 == shmdt((caddr_t)start_addr))
		{
			save_errno = errno;
			ISSUE_REPLPOOLINST(save_errno, shm_id, instfilename, "shmdt()");
			return -1;
		}
		if (0 != shm_rmid(shm_id))
		{
			save_errno = errno;
			ISSUE_REPLPOOLINST(save_errno, shm_id, instfilename, "shm_rmid()");
			return -1;
		}
		if (JNLPOOL_SEGMENT == pool_type)
		{
			repl_inst_filehdr->jnlpool_shmid = INVALID_SHMID;
			repl_inst_filehdr->jnlpool_shmid_ctime = 0;
			assert((NULL == jnlpool) || ((NULL == jnlpool->jnlpool_ctl)));
			*ipc_rmvd = TRUE;
		} else
		{
			repl_inst_filehdr->recvpool_shmid = INVALID_SHMID;
			repl_inst_filehdr->recvpool_shmid_ctime = 0;
			if ((NULL != jnlpool) && (NULL != jnlpool->repl_inst_filehdr))
			{
				jnlpool->repl_inst_filehdr->recvpool_shmid = INVALID_SHMID;
				jnlpool->repl_inst_filehdr->recvpool_shmid_ctime = 0;
			}
			*ipc_rmvd = TRUE;
		}
	} else
	{
		assert((JNLPOOL_SEGMENT != pool_type) || ((NULL != jnlpool) && (NULL != jnlpool->jnlpool_ctl)));
		if (JNLPOOL_SEGMENT == pool_type)
		{
			*ipc_rmvd = FALSE;
			/* Caller can be MUPIP RUNDOWN (-reg * OR argumentless) or MUPIP ROLLBACK (online or standalone flavor).
			 * In all cases except the argumentless MUPIP RUNDOWN case return with jnlpool_ctl as is. Here is why.
			 * In the rollback case, we are ONLINE ROLLBACK OR anticipatory freeze is in effect and so we want to
			 * keep the journal pool available for the duration of the rollback (to record errors and trigger instance
			 * freeze). Do not detach from the journal pool in that case.
			 * In the rundown -reg * case, anticipatory freeze is in effect and we want to keep the journal pool
			 * available for the duration of the rundown (to record errors and trigger instance freeze). The actual
			 * jnlpool detach will happen in the caller ("mupip_rundown") once all regions have been rundown.
			 * In the argumentless rundown case, detach from the jnlpool. This does not honor the custom errors scheme
			 * and we do not want to be attached to a LOT of journal pools as the argumentless rundown proceeds
			 * (virtual memory bloat etc.).
			 */
			if (argumentless_rundown)
			{
				JNLPOOL_SHMDT(jnlpool, status, save_errno);
				assert(0 == status);	/* even if shmdt fails, there is not much we can do so move on in pro */
			}
		}
		if (RECVPOOL_SEGMENT == pool_type)
			*ipc_rmvd = FALSE;
	}
	return 0;
}

int 	mu_rndwn_replpool(replpool_identifier *replpool_id, repl_inst_hdr_ptr_t repl_inst_filehdr, int shm_id, boolean_t *ipc_rmvd)
{
	int			status, save_errno, nattch;
	char			*instfilename;
	sm_uc_ptr_t		start_addr;
	struct shmid_ds		shm_buf;
	boolean_t		force_attach;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;

	assert(INVALID_SHMID != shm_id);
	instfilename = replpool_id->instfilename;
	assert((JNLPOOL_SEGMENT == replpool_id->pool_type) || (RECVPOOL_SEGMENT == replpool_id->pool_type));
	assert(!jgbl.mur_rollback || !jgbl.mur_options_forward); /* ROLLBACK -FORWARD should not call this function */
	force_attach = (jgbl.onlnrlbk || (!jgbl.mur_rollback && !argumentless_rundown && INST_FREEZE_ON_ERROR_POLICY));
	if (-1 == shmctl(shm_id, IPC_STAT, &shm_buf))
	{
		save_errno = errno;
		ISSUE_REPLPOOLINST(save_errno, shm_id, instfilename, "shmctl()");
		return -1;
	}
	nattch = shm_buf.shm_nattch;
	if ((0 != nattch) && !force_attach)
	{
		util_out_print("Replpool segment (id = !UL) for replication instance !AD is in use by another process.",
				TRUE, shm_id, LEN_AND_STR(instfilename));
		return -1;
	}
	if (-1 == (sm_long_t)(start_addr = (sm_uc_ptr_t) do_shmat(shm_id, 0, 0)))
	{
		save_errno = errno;
		ISSUE_REPLPOOLINST(save_errno, shm_id, instfilename, "shmat()");
		return -1;
	}
	ESTABLISH_RET(mu_rndwn_replpool_ch, -1);
	status = mu_rndwn_replpool2(replpool_id, repl_inst_filehdr, shm_id, ipc_rmvd, instfilename, start_addr, nattch);
	REVERT;
	return status;
}

CONDITION_HANDLER(mu_rndwn_replpool_ch)
{
	unix_db_info		*udi;
	int			status, save_errno;
	int			jnlpool_shmid;

	START_CH(TRUE);
	PRN_ERROR; /* flush the error string */
	if (SEVERITY == SEVERE)
		NEXTCH;
	/* If we have a journal pool, detach it to prevent leaking the shared memory.
	 * However, if IFOE is configured, we may need the journal pool attached so that we can check for instance freeze
	 * in database rundown.
	 * In that case, the detach will happen automatically when the process terminates.
	 * On the other hand, we don't respect IFOE in argumentless rundown, so go ahead and detach in that case, since otherwise
	 * we could potentially leak the shared memory of multiple journal pools.
	 */
	if (((NULL != jnlpool) && (NULL != jnlpool->jnlpool_ctl)) && (!INST_FREEZE_ON_ERROR_POLICY || argumentless_rundown))
	{
		jnlpool_shmid = jnlpool->repl_inst_filehdr->jnlpool_shmid;
		JNLPOOL_SHMDT(jnlpool, status, save_errno);
		if (0 > status)
		{
			assert(NULL != jnlpool->jnlpool_dummy_reg);
			udi = FILE_INFO(jnlpool->jnlpool_dummy_reg);
			assert(ERR_REPLINSTOPEN == SIGNAL); /* only reason we know why mu_rndwn_replpool can fail */
			ISSUE_REPLPOOLINST(save_errno, jnlpool_shmid, udi->fn, "shmdt()");
		}
	}
	UNWIND(NULL, NULL);
}