File: repl_inst_edit.c

package info (click to toggle)
fis-gtm 6.3-014-3
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 36,680 kB
  • sloc: ansic: 333,039; asm: 5,180; csh: 4,956; sh: 1,924; awk: 291; makefile: 66; sed: 13
file content (380 lines) | stat: -rwxr-xr-x 14,925 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
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
/****************************************************************
*								*
 * Copyright (c) 2006-2018 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_string.h"
#include "gtm_stdio.h"
#include "gtm_ipc.h"
#include <sys/sem.h>

#include "cli.h"
#include "util.h"
#include "repl_instance.h"
#include "gdsroot.h"
#include "gdsbt.h"
#include "gtm_facility.h"
#include "fileinfo.h"
#include "gdsfhead.h"
#include "filestruct.h"
#include "jnl.h"		/* for JNL_WHOLE_FROM_SHORT_TIME */
#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 "repl_msg.h"
#include "gtmsource.h"
#include "repl_inst_dump.h"
#include "is_proc_alive.h"
#include "repl_shutdcode.h"
#include "repl_sem.h"
#include "ftok_sems.h"
#include "gtm_sem.h"

GBLREF	jnlpool_addrs_ptr_t	jnlpool;		/* Used to access the gtmsource_local structures (slots) */
GBLREF	boolean_t		in_repl_inst_edit;	/* used by an assert in repl_inst_read/repl_inst_write */
GBLREF	boolean_t		detail_specified;	/* set to TRUE if -DETAIL is specified */
GBLREF	uint4			section_offset;		/* Used by PRINT_OFFSET_PREFIX macro in repl_inst_dump.c */

error_def(ERR_JNLPOOLSETUP);
error_def(ERR_MUPCLIERR);
error_def(ERR_SIZENOTVALID8);

void	mupcli_get_offset_size_value(uint4 *offset, uint4 *size, gtm_uint64_t *value, boolean_t *value_present)
{
	if (!cli_get_hex("OFFSET", offset))
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUPCLIERR);
	if (!cli_get_hex("SIZE", size))
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUPCLIERR);
	if (!((SIZEOF(char) == *size) || (SIZEOF(short) == *size) || (SIZEOF(int4) == *size) || (SIZEOF(gtm_int64_t) == *size)))
                rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_SIZENOTVALID8);
	if (0 > (int4)*size)
	{
		util_out_print("Error: SIZE specified cannot be negative", TRUE);
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUPCLIERR);
	}
	if (0 != (*offset % *size))
	{
		util_out_print("Error: OFFSET [0x!XL] should be a multiple of Size [!UL]", TRUE, *offset, *size);
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUPCLIERR);
	}
	if (CLI_PRESENT == cli_present("VALUE"))
	{
		*value_present = TRUE;
		if (!cli_get_hex64("VALUE", value))
			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUPCLIERR);
	} else
		*value_present = FALSE;
}

void	mupcli_edit_offset_size_value(sm_uc_ptr_t buff, uint4 offset, uint4 size, gtm_uint64_t value, boolean_t value_present)
{
	char		temp_str[MAX_REPL_OPMSG_LEN], temp_str1[MAX_REPL_OPMSG_LEN];
	gtm_uint64_t	old_value = -1;

	memset(temp_str, 0, MAX_REPL_OPMSG_LEN);
	memset(temp_str1, 0, MAX_REPL_OPMSG_LEN);
	if (SIZEOF(char) == size)
	{
		SNPRINTF(temp_str, MAX_REPL_OPMSG_LEN, "!UB [0x!XB]");
		old_value = *(sm_uc_ptr_t)buff;
	}
	else if (SIZEOF(short) == size)
	{
		SNPRINTF(temp_str, MAX_REPL_OPMSG_LEN, "!UW [0x!XW]");
		old_value = *(sm_ushort_ptr_t)buff;
	}
	else if (SIZEOF(int4) == size)
	{
		SNPRINTF(temp_str, MAX_REPL_OPMSG_LEN, "!UL [0x!XL]");
		old_value = *(sm_uint_ptr_t)buff;
	}
	else if (SIZEOF(gtm_int64_t) == size)
	{
		SNPRINTF(temp_str, MAX_REPL_OPMSG_LEN, "!@UQ [0x!@XQ]");
		old_value = *(qw_num_ptr_t)buff;
	}
	assert(-1 != old_value);
	if (value_present)
	{
		if (SIZEOF(char) == size)
			*(sm_uc_ptr_t)buff = (unsigned char)value;
		else if (SIZEOF(short) == size)
			*(sm_ushort_ptr_t)buff = (unsigned short)value;
		else if (SIZEOF(int4) == size)
			*(sm_uint_ptr_t)buff = (unsigned int)value;
		else if (SIZEOF(gtm_int64_t) == size)
			*(qw_num_ptr_t)buff = value;
	} else
		value = old_value;
	SNPRINTF(temp_str1, MAX_REPL_OPMSG_LEN, "Offset !UL [0x!XL] : Old Value = %s : New Value = %s : Size = !UB [0x!XB]",
		temp_str, temp_str);
	if (SIZEOF(int4) >= size)
		util_out_print(temp_str1, TRUE, offset, offset, (uint4)old_value, (uint4)old_value,
			(uint4)value, (uint4)value, size, size);
	else
		util_out_print(temp_str1, TRUE, offset, offset, &old_value, &old_value,
			&value, &value, size, size);
}

/* Description:
 *	Edits or displays the contents of a replication instance file.
 * Parameters:
 	None
 * Return Value:
 	None
 */
void	repl_inst_edit(void)
{
	unsigned short		inst_fn_len, instname_len;
	char			inst_fn[MAX_FN_LEN + 1], buff_unaligned[REPL_INST_HDR_SIZE + GTMSRC_LCL_SIZE + 8];
	char			instname[MAX_INSTNAME_LEN];
	char			*buff;
	repl_inst_hdr_ptr_t	repl_instance;
	gtmsrc_lcl_ptr_t	gtmsrclcl_ptr;
	gtmsource_local_ptr_t	gtmsourcelocal_ptr;
	uint4			offset, size;
	gtm_uint64_t		value;
	boolean_t		value_present, name_present, change_present, jnlpool_available, need_inst_access, need_lock;
	int			idx, num_slots_cleaned;
	int 			status, save_errno;
	int			qdbrundown_status, cleanslots_status;
	off_t			off;
	unix_db_info		*udi;
	union semun		semarg;
	struct semid_ds		semstat;

	in_repl_inst_edit = IN_REPL_INST_EDIT_TRUE;	/* Indicate to "repl_inst_read" and "jnlpool_init"
							 * we are in MUPIP REPLIC -EDITINSTANCE
							 */
	inst_fn_len = MAX_FN_LEN;
	if (!cli_get_str("INSTFILE", inst_fn, &inst_fn_len) || (0 == inst_fn_len))
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUPCLIERR);
	inst_fn[inst_fn_len] = '\0';
	buff = &buff_unaligned[0];
	buff = (char *)ROUND_UP2((INTPTR_T)buff, 8);
	/* Make sure journal pool is initially not open while we're in  MUPIP REPLIC -EDITINSTANCE */
	assert(NULL == jnlpool);
	jnlpool_available = FALSE;
	if (CLI_PRESENT == cli_present("SHOW"))
	{
		detail_specified = (CLI_PRESENT == cli_present("DETAIL"));
		repl_inst_read(inst_fn, (off_t)0, (sm_uc_ptr_t)buff, REPL_INST_HDR_SIZE + GTMSRC_LCL_SIZE);
		util_out_print("GTM-I-MUREPLSHOW, SHOW output for replication instance file !AD", TRUE, inst_fn_len, inst_fn);
		repl_instance = (repl_inst_hdr_ptr_t)&buff[0];
		section_offset = 0;
		repl_inst_dump_filehdr(repl_instance);
		section_offset = REPL_INST_HDR_SIZE;
		repl_inst_dump_gtmsrclcl((gtmsrc_lcl_ptr_t)&buff[REPL_INST_HDR_SIZE]);
		section_offset = REPL_INST_HISTINFO_START;
		repl_inst_dump_history_records(inst_fn, repl_instance->num_histinfo);
	}
	change_present = (CLI_PRESENT == cli_present("CHANGE"));
	name_present = (CLI_PRESENT == cli_present("NAME"));
	qdbrundown_status = cli_present("QDBRUNDOWN");
	cleanslots_status = cli_present("CLEANSLOTS");
	/* Check if need to access and modify the instance file */
	need_inst_access = change_present || name_present || qdbrundown_status || cleanslots_status;
	need_lock = FALSE;
	if (need_inst_access)
	{
		need_lock = TRUE;
		repl_inst_read(inst_fn, (off_t)0, (sm_uc_ptr_t)buff, REPL_INST_HDR_SIZE);
		repl_instance = (repl_inst_hdr_ptr_t)&buff[0];
		semarg.buf = &semstat;
		/* Check if primary instance has potentially crashed.
		 * If so, set need_lock to FALSE so we can avoid calling
		 * jnlpool_init() and avoid a REPLREQROLLBACK error.
		 */
		if ((INVALID_SEMID != repl_instance->jnlpool_semid)
				&& (-1 == semctl(repl_instance->jnlpool_semid, DB_CONTROL_SEM, IPC_STAT, semarg)))
			need_lock = FALSE;
	}
	if (need_lock)
	{
		assert(NULL == jnlpool);
		/* Attach to journal pool so we can obtain locks and access slots */
		jnlpool_init(GTMRELAXED, (boolean_t)FALSE, (boolean_t *)NULL, NULL);
		assert(NULL != jnlpool);
		jnlpool_available = ((NULL != jnlpool->repl_inst_filehdr)
					&& (INVALID_SEMID != jnlpool->repl_inst_filehdr->jnlpool_semid)
					&& (INVALID_SHMID != jnlpool->repl_inst_filehdr->jnlpool_shmid));
		assert(NULL != jnlpool->jnlpool_dummy_reg);
		udi = FILE_INFO(jnlpool->jnlpool_dummy_reg);
		assert((NULL != udi) && udi->grabbed_ftok_sem);
		if (jnlpool_available)
		{
			assert(!udi->grabbed_access_sem);
			/* Journal pool shared memory and semaphore is available
			 * so grab the journal pool access semaphore
			 */
			status = grab_sem(SOURCE, JNL_POOL_ACCESS_SEM);
			if (SS_NORMAL != status)
			{
				save_errno = errno;
				ftok_sem_release(jnlpool->jnlpool_dummy_reg, udi->counter_ftok_incremented, TRUE);
				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
					RTS_ERROR_LITERAL("Error with journal pool access semaphore, no changes were made"),
					save_errno);
			}
			udi->grabbed_access_sem = TRUE;
			udi->counter_acc_incremented = TRUE;
			/* Now that we have the access semaphore, we
			 * can release the ftok and then do grab_lock.
			 */
			ftok_sem_release(jnlpool->jnlpool_dummy_reg, udi->counter_ftok_incremented, FALSE);
			grab_lock(jnlpool->jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK);
		}
	}
	/* Assert that when lock is needed, jnlpool is attached and either the ftok or jnlpool access semaphore is obtained */
	assert(!need_inst_access || !need_lock
			|| ((NULL != jnlpool) && (NULL != udi)
				&& ((jnlpool_available && udi->grabbed_access_sem)
					|| (!jnlpool_available && udi->grabbed_ftok_sem))));
	if (change_present)
	{
		/* Indicate to "repl_inst_read" that we are in a MUPIP REPLIC -EDITINSTANCE -CHANGE command by modifying
		 * the global variable "in_repl_inst_edit" to a more specific value for the duration of the CHANGE command.
		 */
		assert(IN_REPL_INST_EDIT_CHANGE_OFFSET != IN_REPL_INST_EDIT_TRUE);
		assert(IN_REPL_INST_EDIT_CHANGE_OFFSET != IN_REPL_INST_EDIT_FALSE);
		in_repl_inst_edit = IN_REPL_INST_EDIT_CHANGE_OFFSET;	/* needed by "repl_inst_read" to avoid errors */
		mupcli_get_offset_size_value(&offset, &size, &value, &value_present);
		assert(size <= REPL_INST_HDR_SIZE + GTMSRC_LCL_SIZE);
		repl_inst_read(inst_fn, (off_t)offset, (sm_uc_ptr_t)buff, size);
		mupcli_edit_offset_size_value((sm_uc_ptr_t)buff, offset, size, value, value_present);
		repl_inst_write(inst_fn, (off_t)offset, (sm_uc_ptr_t)buff, size);
		in_repl_inst_edit = IN_REPL_INST_EDIT_TRUE;
	}
	if (name_present || qdbrundown_status || cleanslots_status)
	{
		if (name_present)
		{	/* Edit the instance name */
			instname_len = MAX_INSTNAME_LEN;
			assert(MAX_INSTNAME_LEN == SIZEOF(instname));
			if (!cli_get_str("NAME", instname, &instname_len))
				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUPCLIERR);
			assert(MAX_INSTNAME_LEN >= instname_len);
			if (MAX_INSTNAME_LEN == instname_len)
			{
				util_out_print("Error: Instance name length can be at most 15", TRUE);
				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUPCLIERR);
			}
		}
		repl_inst_read(inst_fn, (off_t)0, (sm_uc_ptr_t)buff, REPL_INST_HDR_SIZE + GTMSRC_LCL_SIZE);
		repl_instance = (repl_inst_hdr_ptr_t)&buff[0];
		if (name_present)
		{
			util_out_print("HDR Instance Name changing from !AZ to !AZ",
					TRUE, repl_instance->inst_info.this_instname, instname);
			assert('\0' == instname[instname_len]);
			memcpy(repl_instance->inst_info.this_instname, instname, instname_len + 1);
		}
		if (qdbrundown_status)
		{
			util_out_print("HDR Quick database rundown is active changing from !AZ to !AZ",
					TRUE, repl_instance->qdbrundown ? "TRUE" : "FALSE",
					(CLI_PRESENT == qdbrundown_status) ? "TRUE" : "FALSE");
			repl_instance->qdbrundown = (CLI_PRESENT == qdbrundown_status);
		}
		if (cleanslots_status && jnlpool_available)
		{
			assert(udi->grabbed_access_sem);
			/* If shared memory is available and clean up desired,
			 * then clean up the inactive gtmsource_local structures (slots)
			 * from shared memory and make the corresponding changes to the
			 * gtmsrc_lcl strunctures in the instance file header
			 */
			assert((NULL != jnlpool->jnlpool_dummy_reg) && jnlpool->jnlpool_dummy_reg->open);
			gtmsourcelocal_ptr = &jnlpool->gtmsource_local_array[0];
			gtmsrclcl_ptr = (gtmsrc_lcl_ptr_t)&buff[REPL_INST_HDR_SIZE];
			num_slots_cleaned = 0;
			for (idx = 0; idx < NUM_GTMSRC_LCL; idx++, gtmsourcelocal_ptr++, gtmsrclcl_ptr++)
			{
				assert((NULL != gtmsourcelocal_ptr) && (NULL != gtmsrclcl_ptr));
				/* Check if slot is used and inactive */
				if ((('\0' != gtmsourcelocal_ptr->secondary_instname[0])
						|| (0 != gtmsourcelocal_ptr->read_jnl_seqno)
						|| (0 != gtmsourcelocal_ptr->connect_jnl_seqno))
					&& ((GTMSOURCE_DUMMY_STATE == gtmsourcelocal_ptr->gtmsource_state)
						|| (NO_SHUTDOWN != gtmsourcelocal_ptr->shutdown)
						|| !is_proc_alive(gtmsourcelocal_ptr->gtmsource_pid, 0)))
				{
					/* Slot is inactive so clean (i.e. set certain
					 * fields to default value so slot can be reused)
					 */
					gtmsourcelocal_ptr->secondary_instname[0] = '\0';
					gtmsourcelocal_ptr->gtmsource_state = GTMSOURCE_DUMMY_STATE;
					gtmsourcelocal_ptr->read_jnl_seqno = 0;
					gtmsourcelocal_ptr->connect_jnl_seqno = 0;
					gtmsourcelocal_ptr->gtmsource_pid = 0;
					/* Clean the corresponding gtmsrc_lcl structure */
					COPY_GTMSOURCELOCAL_TO_GTMSRCLCL(gtmsourcelocal_ptr, gtmsrclcl_ptr);
					gtmsourcelocal_ptr->last_flush_resync_seqno = gtmsourcelocal_ptr->read_jnl_seqno;
					num_slots_cleaned++;
				}
			}
		} else if (cleanslots_status)
		{
			assert(udi->grabbed_ftok_sem);
			/* If shared memory is not available and cleaning desired,
			 * only clean the inactive gtmsrc_lcl structures because the
			 * gtmsource_local structures are not available.
			 */
			gtmsrclcl_ptr = (gtmsrc_lcl_ptr_t)&buff[REPL_INST_HDR_SIZE];
			num_slots_cleaned = 0;
			for (idx = 0; idx < NUM_GTMSRC_LCL; idx++, gtmsrclcl_ptr++)
			{
				assert(NULL != gtmsrclcl_ptr);
				/* Skip slots that are not used */
				if (('\0' == gtmsrclcl_ptr->secondary_instname[0])
						&& (0 == gtmsrclcl_ptr->resync_seqno)
						&& (0 == gtmsrclcl_ptr->connect_jnl_seqno))
					continue;
				/* Clean the slot. The gtmsrc_lcl structure only has three
				 * fields as opposed to the gtmsource_local structure which
				 * has numerous fields.
				 */
				gtmsrclcl_ptr->secondary_instname[0] = '\0';
				gtmsrclcl_ptr->resync_seqno = 0;
				gtmsrclcl_ptr->connect_jnl_seqno = 0;
				num_slots_cleaned++;
			}
		}
		if (cleanslots_status)
		{
			util_out_print("Cleaned !2UL inactive source server slot(s) from instance file header",
					TRUE, num_slots_cleaned);
		}
		/* Write/Flush any changes to the instance file header */
		repl_inst_write(inst_fn, (off_t)0, (sm_uc_ptr_t)buff, REPL_INST_HDR_SIZE + GTMSRC_LCL_SIZE);
	}
	if (need_lock)
	{
		if (jnlpool_available)
		{
			assert(udi->grabbed_access_sem);
			/* Release the lock and journal pool access semaphore */
			rel_lock(jnlpool->jnlpool_dummy_reg);
			rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM);
			udi->grabbed_access_sem = FALSE;
			udi->counter_acc_incremented = FALSE;
		} else
		{
			assert(udi->grabbed_ftok_sem);
			/* Release the ftok */
			ftok_sem_release(jnlpool->jnlpool_dummy_reg, udi->counter_ftok_incremented, FALSE);
		}
	}
	in_repl_inst_edit = IN_REPL_INST_EDIT_FALSE;
}