fis-gtm/sr_unix/repl_inst_create.c

219 lines
9.3 KiB
C

/****************************************************************
* *
* Copyright 2006, 2013 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_stdlib.h"
#include "gtm_stdio.h"
#include "gtm_string.h"
#include "gtm_unistd.h"
#include "gtm_fcntl.h"
#include "gtm_stat.h"
#include "gtm_time.h"
#include "gtm_inet.h"
#include <sys/sem.h>
#include <sys/mman.h>
#include <errno.h>
#include "eintr_wrappers.h"
#include "gdsroot.h"
#include "gdsblk.h"
#include "gtm_facility.h"
#include "fileinfo.h"
#include "gdsbt.h"
#include "gdsfhead.h"
#include "filestruct.h"
#include "jnl.h"
#include "repl_msg.h"
#include "gtmsource.h"
#include "cli.h"
#include "gtmrecv.h"
#include "iosp.h"
#include "gtmio.h"
#include "gtm_logicals.h"
#include "trans_log_name.h"
#include "gtmmsg.h"
#include "repl_sem.h"
#include "repl_instance.h"
#include "gtm_rename.h"
GBLREF boolean_t in_repl_inst_create; /* used by repl_inst_read/repl_inst_write */
GBLREF uint4 process_id;
error_def(ERR_FILEEXISTS);
error_def(ERR_FILERENAME);
error_def(ERR_LOGTOOLONG);
error_def(ERR_RENAMEFAIL);
error_def(ERR_REPLINSTACC);
error_def(ERR_REPLINSTNMLEN);
error_def(ERR_REPLINSTNMUNDEF);
error_def(ERR_REPLINSTSTNDALN);
error_def(ERR_TEXT);
/* Description:
* Creates replication instance file.
* Parameters:
* None
* Return Value:
* None
*/
void repl_inst_create(void)
{
unsigned int inst_fn_len;
unsigned short inst_name_len;
int rename_fn_len;
char rename_fn[MAX_FN_LEN];
char inst_fn[MAX_FN_LEN + 1], inst_name[MAX_FN_LEN + 1];
char machine_name[MAX_MCNAMELEN], buff_unaligned[REPL_INST_HDR_SIZE + GTMSRC_LCL_SIZE + 8];
char *buff_8byte_aligned;
int idx, status;
struct stat stat_buf;
repl_inst_hdr_ptr_t repl_instance;
gtmsrc_lcl_ptr_t gtmsrc_lcl_array;
mstr log_nam, trans_name;
uint4 status2;
jnl_tm_t now;
if (!repl_inst_get_name(inst_fn, &inst_fn_len, MAX_FN_LEN + 1, issue_rts_error))
GTMASSERT; /* rts_error should have been issued by repl_inst_get_name */
/* Although the maximum length of an instance name is MAX_INSTNAME_LEN-1 characters, the input buffer needs to hold a lot
* more since the input instance name might be longer. Hence inst_name (containing MAX_FN_LEN+1 = 257 bytes) is used.
*/
inst_name_len = 0;
if (cli_present("NAME"))
{
inst_name_len = SIZEOF(inst_name);
if (!cli_get_str("NAME", &inst_name[0], &inst_name_len))
rts_error(VARLSTCNT(4) ERR_TEXT, 2, RTS_ERROR_TEXT("Error parsing NAME qualifier"));
} else
{
log_nam.addr = GTM_REPL_INSTNAME;
log_nam.len = SIZEOF(GTM_REPL_INSTNAME) - 1;
trans_name.addr = &inst_name[0];
if (SS_NORMAL != (status = TRANS_LOG_NAME(&log_nam, &trans_name, inst_name, SIZEOF(inst_name),
dont_sendmsg_on_log2long)))
{
if (SS_LOG2LONG == status)
rts_error(VARLSTCNT(5) ERR_LOGTOOLONG, 3, log_nam.len, log_nam.addr, SIZEOF(inst_name) - 1);
else
rts_error(VARLSTCNT(1) ERR_REPLINSTNMUNDEF);
}
inst_name_len = trans_name.len;
}
if ((MAX_INSTNAME_LEN <= inst_name_len) || (0 == inst_name_len))
rts_error(VARLSTCNT(4) ERR_REPLINSTNMLEN, 2, inst_name_len, inst_name);
inst_name[inst_name_len] = '\0';
buff_8byte_aligned = &buff_unaligned[0];
buff_8byte_aligned = (char *)ROUND_UP2((INTPTR_T)buff_8byte_aligned, 8);
repl_instance = (repl_inst_hdr_ptr_t)&buff_8byte_aligned[0];
gtmsrc_lcl_array = (gtmsrc_lcl_ptr_t)&buff_8byte_aligned[REPL_INST_HDR_SIZE];
memset(machine_name, 0, SIZEOF(machine_name));
if (GETHOSTNAME(machine_name, MAX_MCNAMELEN, status))
rts_error(VARLSTCNT(5) ERR_TEXT, 2, RTS_ERROR_TEXT("Unable to get the hostname"), errno);
STAT_FILE(inst_fn, &stat_buf, status);
if (-1 != status)
{
if (cli_present("NOREPLACE")) /* the file exists, so error out */
rts_error(VARLSTCNT(4) ERR_FILEEXISTS, 2, inst_fn_len, inst_fn);
in_repl_inst_create = TRUE; /* used by an assert in the call to "repl_inst_read" below */
repl_inst_read(inst_fn, (off_t)0, (sm_uc_ptr_t)repl_instance, SIZEOF(repl_inst_hdr));
in_repl_inst_create = FALSE;
if ((INVALID_SEMID != repl_instance->jnlpool_semid) || (INVALID_SHMID != repl_instance->jnlpool_shmid)
|| (INVALID_SEMID != repl_instance->recvpool_semid) || (INVALID_SHMID != repl_instance->recvpool_shmid))
{
rts_error(VARLSTCNT(4) ERR_REPLINSTSTNDALN, 2, inst_fn_len, inst_fn);
assert(FALSE);
}
JNL_SHORT_TIME(now);
if (SS_NORMAL != (status = prepare_unique_name((char *)inst_fn, inst_fn_len, "", "",
rename_fn, &rename_fn_len, now, &status2)))
{
gtm_putmsg(VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT("Error preparing unique name for renaming instance file"));
if (SS_NORMAL != status2)
rts_error(VARLSTCNT(7) ERR_REPLINSTACC, 2, inst_fn_len, inst_fn, status, 0, status2);
else
rts_error(VARLSTCNT(5) ERR_REPLINSTACC, 2, inst_fn_len, inst_fn, status);
}
if (SS_NORMAL != (status = gtm_rename((char *)inst_fn, (int)inst_fn_len,
(char *)rename_fn, rename_fn_len, &status2)))
{
if (SS_NORMAL != status2)
rts_error(VARLSTCNT(9) ERR_RENAMEFAIL, 4, inst_fn_len, inst_fn,
rename_fn_len, rename_fn, status, 0, status2);
else
rts_error(VARLSTCNT(7) ERR_RENAMEFAIL, 4, inst_fn_len, inst_fn, rename_fn_len, rename_fn, status);
} else /* successfully renamed the existing file; print a message */
gtm_putmsg(VARLSTCNT(6) ERR_FILERENAME, 4, inst_fn_len, inst_fn, rename_fn_len, rename_fn);
} else if (ENOENT != errno) /* some error happened */
rts_error(VARLSTCNT(5) ERR_REPLINSTACC, 2, inst_fn_len, inst_fn, errno);
/* The instance file consists of 3 parts.
* File header ("repl_inst_hdr" structure)
* Array of 16 "gtmsrc_lcl" structures
* Variable length array of "repl_histinfo" structures
* Of these the last part is not allocated at file creation time. The rest have to be initialized now.
*/
/************************** Initialize "repl_inst_hdr" section ***************************/
memset(repl_instance, 0, SIZEOF(repl_inst_hdr));
memcpy(&repl_instance->label[0], GDS_REPL_INST_LABEL, GDS_REPL_INST_LABEL_SZ-1);
repl_instance->replinst_minorver = GDS_REPL_INST_MINOR_LABEL;
repl_instance->is_little_endian = GTM_IS_LITTLE_ENDIAN;
repl_instance->is_64bit = GTM_IS_64BIT;
repl_instance->jnlpool_semid = INVALID_SEMID;
repl_instance->jnlpool_shmid = INVALID_SHMID;
repl_instance->recvpool_semid = INVALID_SEMID;
repl_instance->recvpool_shmid = INVALID_SHMID;
/********* initialize "inst_info" structure member of "repl_inst_hdr" ***********/
/* machine_name was obtained from GETHOSTNAME above. It is an array of MAX_MCNAMELEN (256) bytes. The actual
* machine name might be longer than can fit in the "created_nodename" field which is MAX_NODENAME_LEN (16) in size.
* Take care to copy only as much as needed leaving one character for the null-termination.
*/
assert(MAX_NODENAME_LEN <= MAX_MCNAMELEN); /* '=' is valid since we have space to store MAX_NODENAME_LEN characters */
memcpy(repl_instance->inst_info.created_nodename, machine_name, MAX_NODENAME_LEN);
/* if machine_name is less than MAX_NODENAME_LEN then set the last valid character of created_nodename array to '\0' which
* is relied by repl_inst_dump_filehdr
*/
if (MAX_NODENAME_LEN > STRLEN(machine_name))
repl_instance->inst_info.created_nodename[MAX_NODENAME_LEN - 1] = '\0';
DBG_CHECK_CREATED_NODENAME(repl_instance->inst_info.created_nodename);
memcpy(repl_instance->inst_info.this_instname, inst_name, inst_name_len);
JNL_SHORT_TIME(repl_instance->inst_info.created_time);
assert(process_id == getpid());
repl_instance->inst_info.creator_pid = process_id;
/* repl_instance->lms_group_info should be initialized to NULL at this point.
* That is the case already because of the memset above. So nothing more needed for now.
*/
repl_instance->jnl_seqno = 0;
repl_instance->root_primary_cycle = 0;
repl_instance->num_histinfo = 0;
repl_instance->num_alloc_histinfo = 0;
repl_instance->crash = FALSE;
repl_instance->was_rootprimary = FALSE;
repl_instance->is_supplementary = cli_present("SUPPLEMENTARY");
for (idx = 0; idx < MAX_SUPPL_STRMS; idx++)
repl_instance->last_histinfo_num[idx] = INVALID_HISTINFO_NUM;
/* strm_seqno[] and strm_group_info[] are already initialized to 0 as part of the memset above. Nothing more needed
* except the 0th stream seqno. This needs to be set to 1 so the first local update done on a supplementary instance
* correctly uses the stream seqno of 1. For non-zero stream #s, a UPDATERESYNC= startup of the receiver to be done
* anyways from a supplementary root primary instance and so that will initialize the strm_seqno[] to a non-zero
* value before any updates from that stream occur.
*/
if (repl_instance->is_supplementary)
repl_instance->strm_seqno[0] = 1; /* Initialize 0th stream starting sequence number */
/************************** Initialize "gtmsrc_lcl" section ***************************/
memset(gtmsrc_lcl_array, 0, GTMSRC_LCL_SIZE);
/************************** Write stuff to file on disk ***********************************/
in_repl_inst_create = TRUE; /* used by repl_inst_write to determine if O_CREAT needs to be specified in the open */
repl_inst_write(inst_fn, (off_t)0, (sm_uc_ptr_t)repl_instance, REPL_INST_HDR_SIZE + GTMSRC_LCL_SIZE);
in_repl_inst_create = FALSE;
}