Пример #1
0
/* routine exposed to call-in user to exit from active GT.M environment */
int gtm_exit()
{
	error_def(ERR_INVGTMEXIT);

	if (!gtm_startup_active)
		return 0;		/* GT.M environment not setup yet - quietly return */
	ESTABLISH_RET(gtmci_ch, mumps_status);

	assert(NULL != frame_pointer);
	/* Do not allow gtm_exit() to be invoked from external calls */
	if (!(SFF_CI & frame_pointer->flags) || !(MUMPS_CALLIN & invocation_mode) || (1 < nested_level))
		rts_error(VARLSTCNT(1) ERR_INVGTMEXIT);
	/* Now get rid of the whole M stack - end of GT.M environment */
	while (NULL != frame_pointer)
	{
		while (NULL != frame_pointer && !(frame_pointer->flags & SFF_CI))
			op_unwind();
		if (NULL != frame_pointer)
		{ /* unwind the current invocation of call-in environment */
			assert(frame_pointer->flags & SFF_CI);
			ci_ret_code_quit();
		}
	}
	gtm_exit_handler(); /* rundown all open database resource */
	REVERT;
	gtm_startup_active = FALSE;
	return 0;
}
Пример #2
0
int gtm_init()
{
	rhdtyp          	*base_addr;
	unsigned char   	*transfer_addr;
	error_def(ERR_CITPNESTED);
	error_def(ERR_CIMAXLEVELS);

	if (!gtm_startup_active)
	{ /* call-in invoked from C as base. GT.M hasn't been started up yet. */
		image_type = GTM_IMAGE;
		gtm_env_init();	/* read in all environment variables */
		err_init(stop_image_conditional_core);
		cli_lex_setup(0, NULL);
		/* Initialize msp to the maximum so if errors occur during GT.M startup below,
		 * the unwind logic in gtmci_ch() will get rid of the whole stack. */
		msp = (unsigned char*)-1;
	}
	ESTABLISH_RET(gtmci_ch, mumps_status);
	if (!gtm_startup_active)
	{ /* GT.M is not active yet. Create GT.M startup environment */
		invocation_mode = MUMPS_CALLIN;
		init_gtm();
		gtm_savetraps(); /* nullify default $ZTRAP handling */
		assert(gtm_startup_active);
		assert(frame_pointer->flags & SFF_CI);
		nested_level = 1;
	}
	else if (!(frame_pointer->flags & SFF_CI))
	{ /* Nested call-in: setup a new CI environment (SFF_CI frame on top of base-frame) */
		/* Mark the beginning of the new stack so that initialization errors in
		 * call-in frame do not unwind entries of the previous stack (see gtmci_ch).*/
		fgncal_stack = msp;
		/* Report if condition handlers stack may overrun during this callin level.
		 * Every underlying level can not have more than 2 active condition handlers,
		 * plus extra MAX_HANDLERS are reserved for this level. */
		if (chnd_end - ctxt <= MAX_HANDLERS)
			rts_error(VARLSTCNT(3) ERR_CIMAXLEVELS, 1, nested_level);
		/* Disallow call-ins within a TP boundary since TP restarts are not supported
		 * currently across nested call-ins. When we implement TP restarts across call-ins,
		 * this error needs be changed to a Warning or Notification */
		if (0 < dollar_tlevel)
			rts_error(VARLSTCNT(1) ERR_CITPNESTED);
		base_addr = make_cimode();
		transfer_addr = PTEXT_ADR(base_addr);
		gtm_init_env(base_addr, transfer_addr);
		SET_CI_ENV(ci_ret_code_exit);
		gtmci_isv_save();
		nested_level++;
	}
	/* Now that GT.M is initialized. Mark the new stack pointer (msp) so that errors
	 * while executing an M routine do not unwind stack below this mark. It important that
	 * the call-in frames (SFF_CI), that hold nesting information (eg. $ECODE/$STACK data
	 * of the previous stack), are kept from being unwound. */
	fgncal_stack = msp;
	REVERT;
	return 0;
}
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 */
}
Пример #4
0
/* On OSF/1 (Digital Unix), pointers are 64 bits wide; the only exception to this is C programs for which one may
 * specify compiler and link editor options in order to use (and allocate) 32-bit pointers.  However, since C is
 * the only exception and, in particular because the operating system does not support such an exception, the argv
 * array passed to the main program is an array of 64-bit pointers.  Thus the C program needs to declare argv[]
 * as an array of 64-bit pointers and needs to do the same for any pointer it sets to an element of argv[].
 */
int main(int argc, char_ptr_t argv[])
{
	omi_conn_ll	conns;
	bool	  	set_pset();
	int 		ret_val;
	DCL_THREADGBL_ACCESS;

	GTM_THREADGBL_INIT;
	ctxt = NULL;
	common_startup_init(GTCM_SERVER_IMAGE);
	SPRINTF(image_id,"%s=gtcm_server", image_id);
#	ifdef SEQUOIA
	if (!set_pset())
		exit(-1);
#	endif
	/*  Initialize everything but the network */
	err_init(gtcm_exit_ch);
	gtm_chk_dist(argv[0]);
	omi_errno = OMI_ER_NO_ERROR;
	ctxt = ctxt;
	ESTABLISH_RET(omi_dbms_ch, -1);	/* any return value to signify error return */
	gtcm_init(argc, argv);
	gtcm_ltime = gtcm_stime = (int4)time(0);
#	ifdef GTCM_RC
	rc_create_cpt();
#	endif
	REVERT;
	if (OMI_ER_NO_ERROR != omi_errno)
		exit(omi_errno);
	/*  Initialize the network interface */
	if (0 != (ret_val = gtcm_bgn_net(&conns)))	/* Warning - assignment */
	{
		gtcm_rep_err("Error initializing TCP", ret_val);
		gtcm_exi_condition = ret_val;
		gtcm_exit();
	}
	SPRINTF(image_id,"%s(pid=%d) %s %s %s -id %d -service %s",
		image_id,
		omi_pid,
		( history ? "-hist" : "" ),
		( authenticate ? "-auth" : "" ),
		( ping_keepalive ? "-ping" : "" ),
		rc_server_id,
		omi_service
		);
	OPERATOR_LOG_MSG;
	omi_conns = &conns;
	/*  Should be forever, unless an error occurs */
	gtcm_loop(&conns);
	/*  Clean up */
	gtcm_end_net(&conns);
	gtcm_exit();
	return 0;
}
Пример #5
0
int file_input_get(char **in_ptr)
{
	char	*ptr, *tmp_ptr;
	int	rd_len, s1;
	mval	val;
	static unsigned int mbuff_len = BUFF_SIZE;
	unsigned int new_mbuff_len, ret_len;
	static char *mbuff = buff1;

	ESTABLISH_RET(mupip_load_ch, 0);
	ret_len = 0;
	for (;;)
	{	/* one-time only reads if in TP to avoid TPNOTACID, otherwise use untimed reads */
		op_read(&val, dollar_tlevel ? 0: NO_M_TIMEOUT);
		rd_len = val.str.len;
		if ((0 == rd_len) && io_curr_device.in->dollar.zeof)
		{
			REVERT;
			if (io_curr_device.in->dollar.x)
				rts_error(VARLSTCNT(1) ERR_PREMATEOF);
			return -1;
		}
		if (mbuff_len < ret_len + rd_len)
		{
			new_mbuff_len = MAX(ret_len,(2 * mbuff_len));
			tmp_ptr = (char *)malloc(new_mbuff_len);
			if (NULL == tmp_ptr)
			{
				REVERT;
				return -1;
			}
			if (mbuff != buff1)
			{
				memcpy(tmp_ptr, mbuff, (ret_len));
				free (mbuff);
			}
			else
				memcpy(tmp_ptr, buff1, (ret_len));

			mbuff = tmp_ptr;
			mbuff_len = new_mbuff_len;

		}
		memcpy((unsigned char *) (mbuff + ret_len), val.str.addr, rd_len);
		ret_len += rd_len;
		if ( !(io_curr_device.in->dollar.x) )
		{
			*in_ptr = mbuff;
			REVERT;
			return ret_len;
		}
	}
}
Пример #6
0
static bool lke_process(int argc)
{
    bool		flag = FALSE;
    int		res;
    static int	save_stderr = SYS_STDERR;

    ESTABLISH_RET(util_ch, TRUE);
    if (util_interrupt)
        rts_error(VARLSTCNT(1) ERR_CTRLC);
    if (SYS_STDERR != save_stderr)  /* necesary in case of rts_error */
        close_fileio(&save_stderr);
    assert(SYS_STDERR == save_stderr);

    func = 0;
    util_interrupt = 0;
    if (argc < 2)
        display_prompt();
    if ( EOF == (res = parse_cmd()))
    {
        if (util_interrupt)
        {
            rts_error(VARLSTCNT(1) ERR_CTRLC);
            REVERT;
            return TRUE;
        }
        else
        {
            REVERT;
            return FALSE;
        }
    } else if (res)
    {
        if (1 < argc)
        {
            REVERT;
            rts_error(VARLSTCNT(4) res, 2, LEN_AND_STR(cli_err_str));
        } else
            gtm_putmsg(VARLSTCNT(4) res, 2, LEN_AND_STR(cli_err_str));
    }
    if (func)
    {
        flag = open_fileio(&save_stderr); /* save_stderr = SYS_STDERR if -output option not present */
        func();
        if (flag)
            close_fileio(&save_stderr);
        assert(SYS_STDERR == save_stderr);
    }
    REVERT;
    return(1 >= argc);
}
Пример #7
0
int
omi_prc_set(omi_conn *cptr, char *xend, char *buff, char *bend)
{
    int		 rv;
    omi_si	 replicate;
    omi_li	 li;
    mval	 v;

/*  Replicate flag */
    OMI_SI_READ(&replicate, cptr->xptr);

/*  Global Ref */
    OMI_LI_READ(&li, cptr->xptr);
/*  Condition handler for DBMS operations */
    ESTABLISH_RET(omi_dbms_ch,0);
    rv = omi_gvextnam(cptr, li.value, cptr->xptr);
/*  If true, there was an error finding the global reference in the DBMS */
    if (rv < 0) {
	REVERT;
	return rv;
    }
    cptr->xptr += li.value;

/*  Bounds checking */
    if (cptr->xptr > xend) {
	REVERT;
	return -OMI_ER_PR_INVMSGFMT;
    }

/*  Global Data */
    OMI_LI_READ(&li, cptr->xptr);
    v.mvtype    = MV_STR;
    v.str.len   = li.value;
    v.str.addr  = cptr->xptr;

    op_gvput(&v);

    REVERT;

    cptr->xptr += li.value;
/*  Bounds checking */
    if (cptr->xptr > xend)
	return -OMI_ER_PR_INVMSGFMT;

/*  The response contains only a header */
    return 0;

}
Пример #8
0
int	file_input_bin_get(char **in_ptr, ssize_t *file_offset, char **buff_base)
{
	char	*ptr;
	int	rd_cnt, rd_len, s1;
	unsigned short	s1s;

	ESTABLISH_RET(mupip_load_ch, 0);
	if (SIZEOF(short) > (buff1_end - buff1_ptr))
	{
		if (0 >= (rd_len = file_input_bin_read()))	/* NOTE assignment */
		{
			if (buff1_end != buff1_ptr)
				rts_error(VARLSTCNT(1) ERR_PREMATEOF);
			else  if (-1 == rd_len)
				rts_error(VARLSTCNT(4) ERR_LOADFILERR, 2, load_fn_len, load_fn_ptr);
			else
			{
				REVERT;
				return 0;
			}
		}
		buff1_end += rd_len;
	}
	GET_USHORT(s1s, buff1_ptr);
	buff1_ptr += SIZEOF(short);
	s1 = s1s;
	assert(0 < s1);
	assert(BUFF_SIZE >= s1);
	if ((buff1_end - buff1_ptr) < s1)
	{
		/* not enough data in buffer, read additional bytes */
		rd_len = file_input_bin_read();
		if ((rd_len + buff1_end - buff1_ptr) < s1)
		{
			if (-1 == rd_len)
				rts_error(VARLSTCNT(4) ERR_LOADFILERR, 2, load_fn_len, load_fn_ptr);
			rts_error(VARLSTCNT(1) ERR_PREMATEOF);
		}
		buff1_end += rd_len;
	}
	*in_ptr = buff1_ptr;
	buff1_ptr += s1;
	*file_offset = buff1_ptr_file_offset;
	*buff_base = buff1;
	REVERT;
	return s1;
}
Пример #9
0
int rc_prc_set(rc_q_hdr *qhdr)
{
    rc_set	*req, *rsp;
    rc_swstr	*data;
    short	len;
    int		 i;
    mval	 v;
    mname_entry	gvname;
    char	*cp1;
    gvnh_reg_t	*gvnh_reg;

    ESTABLISH_RET(rc_dbms_ch, RC_SUCCESS);
    if ((qhdr->a.erc.value = rc_fnd_file(&qhdr->r.xdsid)) != RC_SUCCESS)
    {
	REVERT;
	DEBUG_ONLY(gtcm_cpktdmp((char *)qhdr,qhdr->a.len.value,"rc_fnd_file.");)
	return -1;
Пример #10
0
int
omi_prc_rord(omi_conn *cptr, char *xend, char *buff, char *bend)
{
    char	*bptr;
    int		 rv;
    omi_li	 len;
    mval	 v;

    bptr = buff;

/*  Global Ref */
    OMI_LI_READ(&len, cptr->xptr);
/*  Condition handler for DBMS operations */
    ESTABLISH_RET(omi_dbms_ch,0);
    rv = omi_gvextnam(cptr, len.value, cptr->xptr);
/*  If true, there was an error finding the global reference in the DBMS */
    if (rv < 0) {
	REVERT;
	return rv;
    }
    cptr->xptr += len.value;

/*  Bounds checking */
    if (cptr->xptr > xend) {
	REVERT;
	return -OMI_ER_PR_INVMSGFMT;
    }

    op_zprevious(&v);

    REVERT;

    if (v.str.len > 255)
	return -OMI_ER_DB_UNRECOVER;
    OMI_SI_WRIT(v.str.len, bptr);
    if (v.str.len) {
	memcpy(bptr, v.str.addr, v.str.len);
	bptr += v.str.len;
    }

    return (int)(bptr - buff);

}
Пример #11
0
int
omi_prc_unlc(omi_conn *cptr, char *xend, char *buff, char *bend)
{
	GBLREF int		omi_pid;
	GBLREF mlk_pvtblk	*mlk_pvt_root;

	int			rv;
	omi_si		  	si;
	char		 	*jid;
	mlk_pvtblk		**prior;

	/*  Client's $JOB */
	OMI_SI_READ(&si, cptr->xptr);
	jid         = cptr->xptr;
	cptr->xptr += si.value;

	/*  Bounds checking */
	if (cptr->xptr > xend)
		return -OMI_ER_PR_INVMSGFMT;

	/*  Condition handler for DBMS operations */
	ESTABLISH_RET(omi_dbms_ch,0);

	/*  Loop through all the locks, unlocking ones that belong to this client */
	for (prior = &mlk_pvt_root; *prior; ) {
		if (!(*prior)->granted || !(*prior)->nodptr
		    || (*prior)->nodptr->owner != omi_pid)
			mlk_pvtblk_delete(prior);
		else if ((*prior)->nodptr->auxowner == (UINTPTR_T)cptr
			 && si.value == (*prior)->value[(*prior)->total_length]
			 && memcmp(&(*prior)->value[(*prior)->total_length+1],
				   jid, si.value) == 0) {
			mlk_unlock(*prior);
			mlk_pvtblk_delete(prior);
		} else
			prior = &(*prior)->next;
	}

	REVERT;

	return 0;
}
Пример #12
0
STATICFNDEF int gtm_trigger_invoke(void)
{	/* Invoke trigger M routine. Separate so error returns to gtm_trigger with proper retcode */
	int		rc;

	ESTABLISH_RET(gtm_trigger_ch, mumps_status);
	gtm_trigger_depth++;
	DBGTRIGR((stderr, "gtm_trigger: Dispatching trigger at depth %d\n", gtm_trigger_depth));
	assert(0 < gtm_trigger_depth);
	assert(GTM_TRIGGER_DEPTH_MAX >= gtm_trigger_depth);
	/* Allow interrupts to occur while the trigger is running */
	ENABLE_INTERRUPTS(INTRPT_IN_TRIGGER_NOMANS_LAND);
	rc = dm_start();
	/* Now that we no longer have a trigger stack frame, we are back in trigger no-mans-land */
	DEFER_INTERRUPTS(INTRPT_IN_TRIGGER_NOMANS_LAND);
	gtm_trigger_depth--;
	DBGTRIGR((stderr, "gtm_trigger: Trigger returns with rc %d\n", rc));
	REVERT;
	assert(frame_pointer->type & SFT_TRIGR);
	assert(0 <= gtm_trigger_depth);
	return rc;
}
Пример #13
0
/*
 *  Return:
 *	length of line read
 */
int4	read_source_file (void)
{
	unsigned char	*cp;
	mval		val;

	errno = 0;
	tmp_list_dev = io_curr_device;
	io_curr_device = compile_src_dev;
	ESTABLISH_RET(read_source_ch, -1);
	op_readfl(&val, MAX_SRCLINE, NO_M_TIMEOUT);
	REVERT;
	memcpy((char *)source_buffer, val.str.addr, val.str.len);
	cp = source_buffer + val.str.len;
	/*	if there is a newline charactor (end of a line)	*/
	if (!(io_curr_device.in->dollar.x))
		*cp++ = '\n';
	*cp = '\0';
	if ( FALSE != io_curr_device.in->dollar.zeof )
		return -1;
	io_curr_device = tmp_list_dev;	/*	restore list file after reading	if it's opened	*/
	return (int4)(cp - source_buffer);	/*	var.str.len	*/
}
Пример #14
0
static bool	dse_process(int argc)
{
	int	res;

	ESTABLISH_RET(util_ch, TRUE);
	func = 0;
	util_interrupt = 0;
	if (EOF == (res = parse_cmd()))
	{
		if (util_interrupt)
		{
			rts_error(VARLSTCNT(1) ERR_CTRLC);
			REVERT;
			return TRUE;
		} else
		{
			REVERT;
			return FALSE;
		}
	} else if (res)
	{
		if (1 < argc)
		{
			/* Here we need to REVERT since otherwise we stay in dse in a loop
			 * The design of dse needs to be changed to act like VMS (which is:
			 * if there is an error in the dse command (dse dumpoa), go to command
			 * prompt, but UNIX exits
			 */
			REVERT;
			rts_error(VARLSTCNT(4) res, 2, LEN_AND_STR(cli_err_str));
		} else
			gtm_putmsg(VARLSTCNT(4) res, 2, LEN_AND_STR(cli_err_str));
	}
	if (func)
		func();
	REVERT;
	return(1 >= argc);
}
Пример #15
0
int file_input_get(char **in_ptr)
{
	char	*ptr;
	int	rd_len, ret_len, s1;
	mval	val;

	ESTABLISH_RET(mupip_load_ch, 0);
	buff1_ptr = buff1_end = buff1;
	ret_len = 0;
	for (;;)
	{
		/* do untimed reads */
		op_read(&val, NO_M_TIMEOUT);
		rd_len = val.str.len;
		if ((0 == rd_len) && io_curr_device.in->dollar.zeof)
		{
			REVERT;
			if (io_curr_device.in->dollar.x)
				rts_error(VARLSTCNT(1) ERR_PREMATEOF);
			return -1;
		}
		ret_len += rd_len;
		if (SIZEOF(buff1) < ret_len)
		{
			REVERT;
			return -1;
		}
		memcpy(buff1_end, val.str.addr, rd_len);
		buff1_end = buff1_end + rd_len;
		if ( !(io_curr_device.in->dollar.x) )
		{
			*in_ptr = buff1_ptr;
			REVERT;
			return ret_len;
		}
	}
}
Пример #16
0
/*
 * This will rundown a replication instance journal (and receiver) pool.
 *	Input Parameter:
 *		replpool_id of the instance. Instance file name must be null terminated in replpool_id.
 * Returns :
 *	TRUE,  if successful.
 *	FALSE, otherwise.
 */
boolean_t mu_rndwn_repl_instance(replpool_identifier *replpool_id, boolean_t immediate, boolean_t rndwn_both_pools,
					boolean_t *jnlpool_sem_created)
{
	boolean_t		jnlpool_stat = SS_NORMAL, recvpool_stat = SS_NORMAL, decr_cnt, sem_created = FALSE, ipc_rmvd;
	char			*instfilename;
	unsigned char		ipcs_buff[MAX_IPCS_ID_BUF], *ipcs_ptr;
	gd_region		*r_save;
	repl_inst_hdr		repl_instance;
	static	gd_region	*reg = NULL;
	struct semid_ds		semstat;
	struct shmid_ds		shmstat;
	unix_db_info		*udi;
	int			save_errno, sem_id, shm_id, status;
	sgmnt_addrs		*repl_csa;
	boolean_t		was_crit;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	if (NULL == reg)
	{
		r_save = gv_cur_region;
		mu_gv_cur_reg_init();
		reg = gv_cur_region;
		gv_cur_region = r_save;
	}
	*jnlpool_sem_created = FALSE;
	/* Assert that the layout of replpool_identifier is identical for all versions going forward as the function
	 * "validate_replpool_shm_entry" (used by the argumentless mupip rundown aka "mupip rundown") relies on this.
	 * This assert is placed here (instead of there) because the automated tests exercise this logic much more
	 * than the argumentless code. If any of these asserts fail, "validate_replpool_shm_entry" needs to change
	 * to handle the old and new layouts.
	 *
	 *	Structure ----> replpool_identifier <----    size 312 [0x0138]
	 *
	 *		offset = 0000 [0x0000]      size = 0012 [0x000c]    ----> replpool_identifier.label
	 *		offset = 0012 [0x000c]      size = 0001 [0x0001]    ----> replpool_identifier.pool_type
	 *		offset = 0013 [0x000d]      size = 0036 [0x0024]    ----> replpool_identifier.now_running
	 *		offset = 0052 [0x0034]      size = 0004 [0x0004]    ----> replpool_identifier.repl_pool_key_filler
	 *		offset = 0056 [0x0038]      size = 0256 [0x0100]    ----> replpool_identifier.instfilename
	 */
	assert(0 == OFFSETOF(replpool_identifier, label[0]));
	assert(12 == SIZEOF(((replpool_identifier *)NULL)->label));
	assert(12 == OFFSETOF(replpool_identifier, pool_type));
	assert(1 == SIZEOF(((replpool_identifier *)NULL)->pool_type));
	assert(13 == OFFSETOF(replpool_identifier, now_running[0]));
	assert(36 == SIZEOF(((replpool_identifier *)NULL)->now_running));
	assert(56 == OFFSETOF(replpool_identifier, instfilename[0]));
	assert(256 == SIZEOF(((replpool_identifier *)NULL)->instfilename));
	/* End asserts */
	jnlpool.jnlpool_dummy_reg = reg;
	recvpool.recvpool_dummy_reg = reg;
	instfilename = replpool_id->instfilename;
	reg->dyn.addr->fname_len = strlen(instfilename);
	assert(0 == instfilename[reg->dyn.addr->fname_len]);
	memcpy((char *)reg->dyn.addr->fname, instfilename, reg->dyn.addr->fname_len + 1);
	udi = FILE_INFO(reg);
	udi->fn = (char *)reg->dyn.addr->fname;
	/* Lock replication instance using ftok semaphore so that no other replication process can startup until we are done with
	 * rundown
	 */
	if (!ftok_sem_get(reg, TRUE, REPLPOOL_ID, immediate))
		return FALSE;
	ESTABLISH_RET(mu_rndwn_repl_instance_ch, FALSE);
	repl_inst_read(instfilename, (off_t)0, (sm_uc_ptr_t)&repl_instance, SIZEOF(repl_inst_hdr));
	assert(rndwn_both_pools || JNLPOOL_SEGMENT == replpool_id->pool_type || RECVPOOL_SEGMENT == replpool_id->pool_type);
	if (rndwn_both_pools || (JNLPOOL_SEGMENT == replpool_id->pool_type))
	{	/* --------------------------
		 * First rundown Journal pool
		 * --------------------------
		 */
		shm_id = repl_instance.jnlpool_shmid;
		if (SS_NORMAL == (jnlpool_stat = mu_replpool_grab_sem(&repl_instance, JNLPOOL_SEGMENT, &sem_created, immediate)))
		{
			/* Got JNL_POOL_ACCESS_SEM and incremented SRC_SRV_COUNT_SEM */
			assert(holds_sem[SOURCE][JNL_POOL_ACCESS_SEM]);
			assert(holds_sem[SOURCE][SRC_SERV_COUNT_SEM]);
			sem_id = repl_instance.jnlpool_semid;
			if ((INVALID_SHMID == shm_id) || (-1 == shmctl(shm_id, IPC_STAT, &shmstat))
				|| (shmstat.shm_ctime != repl_instance.jnlpool_shmid_ctime))
			{
				repl_instance.jnlpool_shmid = shm_id = INVALID_SHMID;
				repl_instance.jnlpool_shmid_ctime = 0;
			}
			assert((INVALID_SHMID != shm_id) || ((NULL == jnlpool.jnlpool_ctl) && (NULL == jnlpool_ctl)));
			ipc_rmvd = TRUE;
			if (INVALID_SHMID != shm_id)
			{
				replpool_id->pool_type = JNLPOOL_SEGMENT;
				jnlpool_stat = mu_rndwn_replpool(replpool_id, &repl_instance, shm_id, &ipc_rmvd);
				ipcs_ptr = i2asc((uchar_ptr_t)ipcs_buff, shm_id);
				*ipcs_ptr = '\0';
				if (rndwn_both_pools && ((SS_NORMAL != jnlpool_stat) || ipc_rmvd))
					gtm_putmsg(VARLSTCNT(6) (jnlpool_stat ? ERR_MUJPOOLRNDWNFL : ERR_MUJPOOLRNDWNSUC),
						4, LEN_AND_STR(ipcs_buff), LEN_AND_STR(instfilename));
			}
			assert(ipc_rmvd || (NULL != jnlpool_ctl));
			assert((NULL == jnlpool.jnlpool_ctl) || (SS_NORMAL == jnlpool_stat) || jgbl.onlnrlbk);
			assert((INVALID_SHMID != repl_instance.jnlpool_shmid) || (0 == repl_instance.jnlpool_shmid_ctime));
			assert((INVALID_SHMID == repl_instance.jnlpool_shmid) || (0 != repl_instance.jnlpool_shmid_ctime));
			assert(INVALID_SEMID != sem_id);
			if (!mur_options.rollback)
			{	/* Invoked by MUPIP RUNDOWN in which case the semaphores needs to be removed. But, remove the
				 * semaphore ONLY if we created it here OR the journal pool was successfully removed.
				 */
				if (NULL == jnlpool_ctl)
				{
					if (((sem_created || (SS_NORMAL == jnlpool_stat))
						&& (SS_NORMAL == mu_replpool_release_sem(&repl_instance, JNLPOOL_SEGMENT, TRUE))))
					{	/* Now that semaphores are removed, reset fields in file header */
						if (!sem_created)
						{	/* If sem_id was created by mu_replpool_grab_sem then do NOT report the
							 * MURPOOLRNDWNSUC message as it indicates that the semaphore was orphaned
							 * and we removed it when in fact there was no orphaned semaphore and we
							 * created it as part of mu_replpool_grab_sem to get standalone access to
							 * rundown the receiver pool (which may or may not exist)
							 */
							ipcs_ptr = i2asc((uchar_ptr_t)ipcs_buff, sem_id);
							*ipcs_ptr = '\0';
							gtm_putmsg(VARLSTCNT(9) ERR_MUJPOOLRNDWNSUC, 4, LEN_AND_STR(ipcs_buff),
								LEN_AND_STR(instfilename), ERR_SEMREMOVED, 1, sem_id);
						}
						repl_inst_jnlpool_reset();
					}
				} else
				{	/* Anticipatory Freeze scheme is turned ON. So, release just the JNL_POOL_ACCESS_SEM. The
					 * semaphore will be released/removed in the caller (mupip_rundown)
					 */
					assert(ANTICIPATORY_FREEZE_AVAILABLE);
					assertpro(SS_NORMAL == (status = rel_sem(SOURCE, JNL_POOL_ACCESS_SEM)));
					assert(!holds_sem[SOURCE][JNL_POOL_ACCESS_SEM]);
					/* Since we are not resetting the semaphore IDs in the file header, we need to write out
					 * the semaphore IDs in the instance file (if we created them).
					 */
					if (sem_created)
						repl_inst_write(instfilename, (off_t)0, (sm_uc_ptr_t)&repl_instance,
									SIZEOF(repl_inst_hdr));
				}
				/* If semaphore is not created and the journal pool rundown failed (due to attached processes),
				 * rundown process continues to holds the journal pool access control semaphore. This way, we hold
				 * the semaphore on behalf of the source server (now no longer alive) to prevent mu_rndwn_sem_all
				 * (invoked later) from cleaning up this orphaned semaphore (which causes REPLREQROLLBACK if the
				 * source server is restarted). But, since the semaphore is not released (until the rundown process
				 * dies), holds_sem[SOURCE][JNL_POOL_ACCESS_SEM] continues to remain TRUE. This causes asserts in
				 * ftok_sem_get if mu_rndwn_repl_instance is invoked for a different journal/receive pool. To
				 * workaround it, set holds_sem[SOURCE][JNL_POOL_ACCESS_SEM] to FALSE. This is an interim solution
				 * until we record such semaphores in an ignore-list (or some such) and change mu_rndwn_sem_all to
				 * skip the ones that are present in the ignore list.
				 */
				holds_sem[SOURCE][JNL_POOL_ACCESS_SEM] = FALSE;
			}
		} else if (rndwn_both_pools && (INVALID_SHMID != shm_id))
		{
			ipcs_ptr = i2asc((uchar_ptr_t)ipcs_buff, shm_id);
			*ipcs_ptr = '\0';
			if (rndwn_both_pools)
				gtm_putmsg(VARLSTCNT(6) ERR_MUJPOOLRNDWNFL, 4, LEN_AND_STR(ipcs_buff),
					LEN_AND_STR(instfilename));
		}
		*jnlpool_sem_created = sem_created;
	}
	if (((SS_NORMAL == jnlpool_stat) || !jgbl.mur_rollback) &&
		(rndwn_both_pools || (RECVPOOL_SEGMENT == replpool_id->pool_type)))
	{	/* --------------------------
		 * Now rundown Receivpool
		 * --------------------------
		 * Note: RECVPOOL is rundown ONLY if the JNLPOOL rundown was successful. This way, we don't end up
		 * creating new semaphores for the RECVPOOL if ROLLBACK is not going to start anyways because of the failed
		 * JNLPOOL rundown. The only exception is MUPIP RUNDOWN command in which case we try running down the
		 * RECVPOOL even if the JNLPOOL rundown failed.
		 */
		shm_id = repl_instance.recvpool_shmid;
		if (SS_NORMAL == (recvpool_stat = mu_replpool_grab_sem(&repl_instance, RECVPOOL_SEGMENT, &sem_created, immediate)))
		{
			sem_id = repl_instance.recvpool_semid;
			if ((INVALID_SHMID == shm_id) || (-1 == shmctl(shm_id, IPC_STAT, &shmstat))
				|| (shmstat.shm_ctime != repl_instance.recvpool_shmid_ctime))
			{
				repl_instance.recvpool_shmid = shm_id = INVALID_SHMID;
				repl_instance.recvpool_shmid_ctime = 0;
			}
			ipc_rmvd = TRUE;
			if (INVALID_SHMID != shm_id)
			{
				replpool_id->pool_type = RECVPOOL_SEGMENT;
				recvpool_stat = mu_rndwn_replpool(replpool_id, &repl_instance, shm_id, &ipc_rmvd);
				ipcs_ptr = i2asc((uchar_ptr_t)ipcs_buff, shm_id);
				*ipcs_ptr = '\0';
				if (rndwn_both_pools && ((SS_NORMAL != recvpool_stat) || ipc_rmvd))
					gtm_putmsg(VARLSTCNT(6) (recvpool_stat ? ERR_MURPOOLRNDWNFL : ERR_MURPOOLRNDWNSUC),
						4, LEN_AND_STR(ipcs_buff), LEN_AND_STR(instfilename));
			}
			assert((TRUE == ipc_rmvd) || (SS_NORMAL != recvpool_stat) || jgbl.onlnrlbk);
			assert((INVALID_SHMID != repl_instance.recvpool_shmid) || (0 == repl_instance.recvpool_shmid_ctime));
			assert((INVALID_SHMID == repl_instance.recvpool_shmid) || (0 != repl_instance.recvpool_shmid_ctime));
			assert(INVALID_SEMID != sem_id);
			if (!mur_options.rollback)
			{	/* Invoked by MUPIP RUNDOWN in which case the semaphores needs to be removed. But, remove the
				 * semaphore ONLY if we created it here OR the receive pool was successfully removed.
				 */
				if ((sem_created || (SS_NORMAL == recvpool_stat))
					&& (SS_NORMAL == mu_replpool_release_sem(&repl_instance, RECVPOOL_SEGMENT, TRUE)))
				{	/* Now that semaphores are removed, reset fields in file header */
					if (!sem_created)
					{	/* if sem_id was "created" by mu_replpool_grab_sem then do NOT report the
						 * MURPOOLRNDWNSUC message as it indicates that the semaphore was orphaned and we
						 * removed it when in fact there was no orphaned semaphore and we "created" it as
						 * part of mu_replpool_grab_sem to get standalone access to rundown the receiver
						 * pool (which may or may not exist)
						 */
						ipcs_ptr = i2asc((uchar_ptr_t)ipcs_buff, sem_id);
						*ipcs_ptr = '\0';
						gtm_putmsg(VARLSTCNT(9) ERR_MURPOOLRNDWNSUC, 4, LEN_AND_STR(ipcs_buff),
							LEN_AND_STR(instfilename), ERR_SEMREMOVED, 1, sem_id);
					}
					if (NULL != jnlpool_ctl)
					{	/* Journal pool is not yet removed. So, grab lock before resetting semid/shmid
						 * fields in the file header as the function expects the caller to hold crit
						 * if the journal pool is available
						 */
						repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;
						assert(!repl_csa->now_crit);
						assert(!repl_csa->hold_onto_crit);
						was_crit = repl_csa->now_crit;
						/* Since we do grab_lock, below, we need to do a per-process initialization. Also,
						 * start heartbeat so that grab_lock can issue MUTEXLCKALERT and get C-stacks if
						 * waiting for crit
						 */
						START_HEARTBEAT_IF_NEEDED;
						mutex_per_process_init();
						if (!was_crit)
							grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY);
					}
					repl_inst_recvpool_reset();
					if ((NULL != jnlpool_ctl) && !was_crit)
						rel_lock(jnlpool.jnlpool_dummy_reg);
				}
				/* If semaphore is not created and the receive pool rundown failed (due to attached processes),
				 * rundown process continues to holds the receive pool access control semaphore. This way, we hold
				 * the semaphore on behalf of the receiver server (now no longer alive) to prevent mu_rndwn_sem_all
				 * (invoked later) from cleaning up this orphaned semaphore (which causes REPLREQROLLBACK if the
				 * receiver is restarted). But, since the semaphore is not released (until the rundown process
				 * dies), holds_sem[RECV][RECV_POOL_ACCESS_SEM] continues to remain TRUE. This causes asserts in
				 * ftok_sem_get if mu_rndwn_repl_instance is invoked for a different journal/receive pool. To
				 * workaround it, set holds_sem[SOURCE][RECV_POOL_ACCESS_SEM] to FALSE. This is an interim solution
				 * until we record such semaphores in an ignore-list (or some such) and change mu_rndwn_sem_all to
				 * skip the ones that are present in the ignore list.
				 */
				assert((sem_created || (SS_NORMAL == recvpool_stat)) || holds_sem[RECV][RECV_POOL_ACCESS_SEM]);
				DEBUG_ONLY(set_sem_set_recvr(sem_id));
			}
		} else if (rndwn_both_pools && (INVALID_SHMID != shm_id))
		{
			ipcs_ptr = i2asc((uchar_ptr_t)ipcs_buff, shm_id);
			*ipcs_ptr = '\0';
			if (rndwn_both_pools)
				gtm_putmsg(VARLSTCNT(6) ERR_MURPOOLRNDWNFL, 4, LEN_AND_STR(ipcs_buff),
					LEN_AND_STR(instfilename));
		}
	}
	assert(jgbl.onlnrlbk || ANTICIPATORY_FREEZE_AVAILABLE || (NULL == jnlpool.repl_inst_filehdr));
	if (mur_options.rollback && (SS_NORMAL == jnlpool_stat) && (SS_NORMAL == recvpool_stat))
	{
		assert(jgbl.onlnrlbk || ANTICIPATORY_FREEZE_AVAILABLE || ((INVALID_SHMID == repl_instance.jnlpool_shmid)
			&& (INVALID_SHMID == repl_instance.recvpool_shmid)));
		/* Initialize jnlpool.repl_inst_filehdr as it is used later by gtmrecv_fetchresync() */
		decr_cnt = FALSE;
		if (NULL == jnlpool.repl_inst_filehdr)
		{	/* Possible if there is NO journal pool in the first place. In this case, malloc the structure here and
			 * copy the file header from repl_instance structure.
			 */
			jnlpool.repl_inst_filehdr = (repl_inst_hdr_ptr_t)malloc(SIZEOF(repl_inst_hdr));
			memcpy(jnlpool.repl_inst_filehdr, &repl_instance, SIZEOF(repl_inst_hdr));
		} else
		{
			assert(repl_instance.jnlpool_semid == jnlpool.repl_inst_filehdr->jnlpool_semid);
			assert(repl_instance.jnlpool_semid_ctime == jnlpool.repl_inst_filehdr->jnlpool_semid_ctime);
			assert(repl_instance.jnlpool_shmid == jnlpool.repl_inst_filehdr->jnlpool_shmid);
			assert(repl_instance.jnlpool_shmid_ctime == jnlpool.repl_inst_filehdr->jnlpool_shmid_ctime);
			/* If the ONLINE ROLLBACK command is run on the primary when the source server is up and running,
			 * jnlpool.repl_inst_filehdr->recvpool_semid will be INVALID because there is NO receiver server
			 * running. However, ROLLBACK creates semaphores for both journal pool and receive pool and writes
			 * it to the instance file header. Copy this information to the file header copy in the jnlpool
			 * as well
			 */
			jnlpool.repl_inst_filehdr->recvpool_semid = repl_instance.recvpool_semid;
			jnlpool.repl_inst_filehdr->recvpool_semid_ctime = repl_instance.recvpool_semid_ctime;
		}
		/* Flush changes to the replication instance file header to disk */
		repl_inst_write(instfilename, (off_t)0, (sm_uc_ptr_t)&repl_instance, SIZEOF(repl_inst_hdr));
	} else /* for MUPIP RUNDOWN, semid fields in the file header are reset and is written in mu_replpool_release_sem() above */
		decr_cnt = (NULL == jnlpool_ctl); /* for anticipatory freeze, mupip_rundown releases the semaphore */
	REVERT;
	/* Release replication instance ftok semaphore lock */
	if (!ftok_sem_release(reg, decr_cnt, immediate)) /* Do not decrement the counter if ROLLBACK */
		return FALSE;
	return ((SS_NORMAL == jnlpool_stat) && (SS_NORMAL == recvpool_stat));
}
Пример #17
0
int omi_prc_ordr(omi_conn *cptr, char *xend, char *buff, char *bend)
{
	char		*bptr;
	int			 rv;
	omi_li		 len;
	mval		 vo, vd, vg;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	bptr = buff;
	/* Global Ref */
	OMI_LI_READ(&len, cptr->xptr);
	/* Condition handler for DBMS operations */
	ESTABLISH_RET(omi_dbms_ch,0);
	rv = omi_gvextnam(cptr, len.value, cptr->xptr);
	/* If true, there was an error finding the global reference in the DBMS */
	if (rv < 0)
	{
		REVERT;
		return rv;
	}
	cptr->xptr += len.value;

	/* Bounds checking */
	if (cptr->xptr > xend)
	{
		REVERT;
		return -OMI_ER_PR_INVMSGFMT;
	}

	/* We want to make sure there is plenty of space in the string pool for all three operations ($ORDER, $GET, $DATA) */
	if (cptr->exts & OMI_XTF_NEWOP)
		INVOKE_STP_GCOL(0);

	/* $ORDER */
	op_gvorder(&vo);
	/* $ORDER (buffer write) */
	OMI_SI_WRIT(vo.str.len, bptr);
	if (vo.str.len)
	{
		memcpy(bptr, vo.str.addr, vo.str.len);
		bptr += vo.str.len;
	}
	/* Bunching */
	if (cptr->exts & OMI_XTF_NEWOP)
	{
		if (vo.str.len)
		{
			if (!gv_currkey->prev)
			{
				if (*vo.str.addr != '^')
				{
					REVERT;
					return -OMI_ER_PR_INVGLOBREF;
				}
				vo.str.addr++;	vo.str.len--;
				GV_BIND_NAME_AND_ROOT_SEARCH(cptr->ga, &vo.str);
				vo.str.addr--;	vo.str.len++;
				TREF(gv_last_subsc_null) = FALSE;
			} else
			{
				if (gv_currkey->top != gv_altkey->top)
				{
					REVERT
					return -OMI_ER_DB_UNRECOVER;
				}
				memcpy(gv_currkey, gv_altkey, gv_altkey->end + SIZEOF(gv_key));
				TREF(gv_last_subsc_null) = FALSE;
			}

			/* $DATA */
			op_gvdata(&vd);
			if (!(vd.mvtype & MV_INT))
			{
				REVERT;
				return -OMI_ER_DB_UNRECOVER;
			}
			/* $GET */
			undef_inhibit = TRUE;
			rv = op_gvget(&vg);
			/* $DATA (buffer write) */
			OMI_SI_WRIT(vd.m[1] / MV_BIAS, bptr);
			/* $GET (buffer write) */
			OMI_SI_WRIT((rv ? 1 : 0), bptr);
			if (!rv || !vg.str.len)
				OMI_LI_WRIT(0, bptr);
			else
			{
				OMI_LI_WRIT(vg.str.len, bptr);
				memcpy(bptr, vg.str.addr, vg.str.len);
				bptr += vg.str.len;
			}
		} else
		{	/* Otherwise $ORDER returned a null */
Пример #18
0
int
rc_prc_setf(rc_q_hdr *qhdr)
{
    rc_set	*req, *rsp;
    short	 data_off, str_remain, *ptr;
    char	*cp1;
    int		 i;
    mval	 v;

    ESTABLISH_RET(rc_dbms_ch, RC_SUCCESS);
    if ((qhdr->a.erc.value = rc_fnd_file(&qhdr->r.xdsid)) != RC_SUCCESS)
    {
	REVERT;
#ifdef DEBUG
	gtcm_cpktdmp(qhdr,qhdr->a.len.value,"rc_fnd_file failed.");
#endif
	return -1;
    }
    rsp = req = (rc_set *)qhdr;
    v.mvtype = MV_STR;
    for (cp1 = req->key.key; *cp1; cp1++)
	;
    v.str.len = cp1 - req->key.key;
    v.str.addr = req->key.key;
	if (v.str.len > 8)	/* GT.M does not support global variables > 8 chars */
	{	qhdr->a.erc.value = RC_KEYTOOLONG;
		REVERT;
#ifdef DEBUG
	gtcm_cpktdmp(qhdr,qhdr->a.len.value,"RC_KEYTOOLONG.");
#endif
		return -1;
	}
    gv_bind_name(gd_header, &v.str);
    memcpy(gv_currkey->base, req->key.key, req->key.len.value);
    gv_currkey->end = req->key.len.value;
    gv_currkey->base[gv_currkey->end] = 0;
    for (i = gv_currkey->end - 2; i > 0; i--)
	if (!gv_currkey->base[i - 1])
	    break;
    gv_currkey->prev = i;

    ptr = (short*)(req->key.key + req->key.len.value);
    GET_SHORT(v.str.len, ptr);
    ptr++;
    GET_SHORT(data_off ,ptr);
    ptr++;
    GET_SHORT(str_remain ,ptr);
    ptr++;
    if (gv_currkey->end + 1 + v.str.len + sizeof(rec_hdr) > gv_cur_region->max_rec_size)
    {
	qhdr->a.erc.value = RC_KEYTOOLONG;
#ifdef DEBUG
	gtcm_cpktdmp(qhdr,qhdr->a.len.value,"RC_KEYTOOLONG.");
#endif
    }
    else  /* the total record will fit into a block */
    {
	if (rc_set_fragment = data_off) /* just send fragment */
	{
	    v.str.len = v.str.len - data_off - str_remain;
	    v.str.addr = (char*)ptr;
	}
	else			/* first fragment, put whole record, with zero filler */
	{
	    v.str.addr = (char*)malloc(v.str.len);
	    memset(v.str.addr, 0, v.str.len);
	    memcpy(v.str.addr + data_off, ptr, v.str.len - data_off - str_remain);
	}
	v.mvtype = MV_STR;
	gvcst_put(&v);

	if (rc_set_fragment)
	    rc_set_fragment = 0;
	else
	    free(v.str.addr);
    }

    REVERT;
    return ((qhdr->a.erc.value == RC_SUCCESS) ? 0 : -1);

}
Пример #19
0
int
omi_prc_qry(omi_conn *cptr, char *xend, char *buff, char *bend)
{
    char	*bptr, *eptr;
    int		 rv;
    omi_li	 len;
    mval	 v;
    uns_char	*bgn1, *bgn2, *sbsp;
    char	*grp;
    int		 grl;

    bptr = buff;

    /*  Global Ref */
    OMI_LI_READ(&len, cptr->xptr);
    /*  Condition handler for DBMS operations */
    ESTABLISH_RET(omi_dbms_ch,0);
    rv = omi_gvextnam(cptr, len.value, cptr->xptr);
    /*  If true, there was an error finding the global reference in the DBMS */
    if (rv < 0) {
        REVERT;
        return rv;
    }
    eptr        = cptr->xptr;
    cptr->xptr += len.value;

    /*  Bounds checking */
    if (cptr->xptr > xend) {
        REVERT;
        return -OMI_ER_PR_INVMSGFMT;
    }

    op_gvquery(&v);

    REVERT;

    if (v.str.len == 0) {
        OMI_LI_WRIT(0, bptr);
        return bptr - buff;
    }

    /*  Put a global reference into the reply */
    bgn1    = (uns_char *)bptr;
    bptr   += OMI_LI_SIZ;

    /*  Environment (we give back the request environment) */
    OMI_LI_READ(&len, eptr);
    OMI_LI_WRIT(len.value, bptr);
    (void) memcpy(bptr, eptr, len.value);
    bptr   += len.value;

    /*  Global name */
    bgn2    = (uns_char *)bptr++;
    *bptr++ = '^';
    grp     = (char *)gv_altkey->base;
    grl     = strlen(grp);
    OMI_SI_WRIT(grl + 1, bgn2);
    (void) strcpy(bptr, grp);
    bptr   += grl;

    /*  Subscripts */
    for (grp += grl + 1; *grp; grp += strlen(grp) + 1) {
        bgn2   = (uns_char *)bptr++;
        sbsp   = gvsub2str((uchar_ptr_t)grp, (uchar_ptr_t)bptr, FALSE);
        grl    = sbsp - (uns_char *)bptr;
        OMI_SI_WRIT(grl, bgn2);
        bptr  += grl;
        sbsp  += grl + 1;
    }

    /*  Length of the global reference */
    grl = (uns_char *)bptr - bgn1;
    OMI_LI_WRIT(grl - OMI_LI_SIZ, bgn1);

    return bptr - buff;

}
Пример #20
0
short rc_fnd_file(rc_xdsid *xdsid)
{
	gv_namehead	*g;
	short		dsid, node;
	gd_binding	*map;
	char		buff[1024], *cp, *cp1;
	mstr		fpath1, fpath2;
	mval		v;
	int		i, keysize;
	int             len, node2;

	GET_SHORT(dsid, &xdsid->dsid.value);
	GET_SHORT(node, &xdsid->node.value);
	if (!dsid_list)
	{
		/*	open special database, set up entry */
		dsid_list = (rc_dsid_list *)malloc(SIZEOF(rc_dsid_list));
		dsid_list->dsid = RC_NSPACE_DSID;
		dsid_list->next = NULL;
		fpath1.addr = RC_NSPACE_PATH;
		fpath1.len = SIZEOF(RC_NSPACE_PATH);
		if (SS_NORMAL != TRANS_LOG_NAME(&fpath1, &fpath2, buff, SIZEOF(buff), do_sendmsg_on_log2long))
		{
			char msg[256];
			SPRINTF(msg, "Invalid DB filename, \"%s\"", fpath1.addr);
			gtcm_rep_err(msg, errno);
			return RC_BADFILESPEC;
		}
		if (fpath2.len > MAX_FN_LEN)
			return RC_BADFILESPEC;
		dsid_list->fname = (char *)malloc(fpath2.len + 1);
		memcpy(dsid_list->fname, fpath2.addr, fpath2.len);
		*((char*)(dsid_list->fname + fpath2.len)) = 0;
		gv_cur_region = (gd_region *)malloc(SIZEOF(gd_region));
		memset(gv_cur_region, 0, SIZEOF(gd_region));
		gv_cur_region->dyn.addr = (gd_segment *)malloc(SIZEOF(gd_segment));
		memset(gv_cur_region->dyn.addr, 0, SIZEOF(gd_segment));
		memcpy(gv_cur_region->dyn.addr->fname, fpath2.addr, fpath2.len);
		gv_cur_region->dyn.addr->fname_len = fpath2.len;
		gv_cur_region->dyn.addr->acc_meth = dba_bg;
		ESTABLISH_RET(rc_fnd_file_ch1, RC_SUCCESS);
		gvcst_init(gv_cur_region);
		REVERT;
		change_reg();
		/* check to see if this DB has the reserved bytes field set
		 * correctly.  Global pages must always have some extra unused
		 * space left in them (RC_RESERVED bytes) so that the page
		 * will fit into the client buffer when unpacked by the
		 * client.
		 */
		if (cs_data->reserved_bytes < RC_RESERVED)
		{
			OMI_DBG((omi_debug,
			"Unable to access database file:  \"%s\"\nReserved_bytes field in the file header is too small for GT.CM\n",
			fpath2.addr));
			free(dsid_list->fname);
			dsid_list->fname = NULL;
			free(dsid_list);
			dsid_list = NULL;
			free(gv_cur_region->dyn.addr);
			gv_cur_region->dyn.addr = NULL;
			free(gv_cur_region);
			gv_cur_region = NULL;
			return RC_FILEACCESS;
		}
		gv_keysize = DBKEYSIZE(gv_cur_region->max_key_size);
		GVKEY_INIT(gv_currkey, gv_keysize);
		GVKEY_INIT(gv_altkey, gv_keysize);
		cs_addrs->dir_tree = (gv_namehead *)malloc(SIZEOF(gv_namehead) + 2 * SIZEOF(gv_key) + 3 * (gv_keysize - 1));
		g = cs_addrs->dir_tree;
		g->first_rec = (gv_key*)(g->clue.base + gv_keysize);
		g->last_rec = (gv_key*)(g->first_rec->base + gv_keysize);
		g->clue.top = g->last_rec->top = g->first_rec->top = gv_keysize;
		g->clue.prev = g->clue.end = 0;
		g->root = DIR_ROOT;
		dsid_list->gda = (gd_addr*)malloc(SIZEOF(gd_addr) + 3 * SIZEOF(gd_binding));
		dsid_list->gda->n_maps = 3;
		dsid_list->gda->n_regions = 1;
		dsid_list->gda->n_segments = 1;
		dsid_list->gda->maps = (gd_binding*)((char*)dsid_list->gda + SIZEOF(gd_addr));
		dsid_list->gda->max_rec_size = gv_cur_region->max_rec_size;
		map = dsid_list->gda->maps;
		map ++;
		memset(map->name, 0, SIZEOF(map->name));
		map->name[0] = '%';
		map->reg.addr = gv_cur_region;
		map++;
		map->reg.addr = gv_cur_region;
		memset(map->name, -1, SIZEOF(map->name));
		dsid_list->gda->tab_ptr = (hash_table_mname *)malloc(SIZEOF(hash_table_mname));
		init_hashtab_mname(dsid_list->gda->tab_ptr, 0, HASHTAB_NO_COMPACT, HASHTAB_NO_SPARE_TABLE);
		change_reg();
		if (rc_overflow->top < cs_addrs->hdr->blk_size)
		{
			if (rc_overflow->buff)
				free(rc_overflow->buff);
			rc_overflow->top = cs_addrs->hdr->blk_size;
			rc_overflow->buff = (char*)malloc(rc_overflow->top);
			if (rc_overflow_size < rc_overflow->top)
				rc_overflow_size = rc_overflow->top;
		}
	}
	for (fdi_ptr = dsid_list; fdi_ptr && (fdi_ptr->dsid != dsid); fdi_ptr = fdi_ptr->next)
		;
	if (!fdi_ptr)
	{	/*	need to open new database, add to list, set fdi_ptr */
		gd_header = dsid_list->gda;
		gv_currkey->end = 0;
		v.mvtype = MV_STR;
		v.str.len = RC_NSPACE_GLOB_LEN-1;
		v.str.addr = RC_NSPACE_GLOB;
		GV_BIND_NAME_AND_ROOT_SEARCH(gd_header, &v.str);
		if (!gv_target->root)	/* No namespace global */
			return RC_UNDEFNAMSPC;
		v.mvtype = MV_STR;
		v.str.len = SIZEOF(RC_NSPACE_DSI_SUB)-1;
		v.str.addr = RC_NSPACE_DSI_SUB;
		mval2subsc(&v,gv_currkey);
		node2 = node;
		MV_FORCE_MVAL(&v,node2);
		mval2subsc(&v,gv_currkey);
		i = dsid / 256;
		MV_FORCE_MVAL(&v,i);
		mval2subsc(&v,gv_currkey);
		if (gvcst_get(&v))
			return RC_UNDEFNAMSPC;
		for (cp = v.str.addr, i = 1; i < RC_FILESPEC_PIECE; i++)
			for (; *cp++ != RC_FILESPEC_DELIM; )
				;
		for (cp1 = cp; *cp1++ != RC_FILESPEC_DELIM; )
			;
		cp1--;
		len = (int)(cp1 - cp);
		if (len > MAX_FN_LEN)
			return RC_BADFILESPEC;
		fdi_ptr = (rc_dsid_list *)malloc(SIZEOF(rc_dsid_list));
		fdi_ptr->fname = (char *)malloc(len+1);
		fdi_ptr->dsid = dsid;
		memcpy(fdi_ptr->fname, cp, len);
		*(fdi_ptr->fname + (len)) = 0;
		gv_cur_region = (gd_region *)malloc(SIZEOF(gd_region));
		memset(gv_cur_region, 0, SIZEOF(gd_region));
		gv_cur_region->dyn.addr = (gd_segment *)malloc(SIZEOF(gd_segment));
		memset(gv_cur_region->dyn.addr, 0, SIZEOF(gd_segment));
		memcpy(gv_cur_region->dyn.addr->fname, cp, len);
		gv_cur_region->dyn.addr->fname_len = len;
		gv_cur_region->dyn.addr->acc_meth = dba_bg;
		ESTABLISH_RET(rc_fnd_file_ch2, RC_SUCCESS);
		gvcst_init(gv_cur_region);
		REVERT;
		change_reg();
		/* check to see if this DB has the reserved bytes field set
		 * correctly.  Global pages must always have some extra unused
		 * space left in them (RC_RESERVED bytes) so that the page
		 * will fit into the client buffer when unpacked by the
		 * client.
		 */
		if (cs_data->reserved_bytes < RC_RESERVED)
		{
			OMI_DBG((omi_debug,
			"Unable to access database file:  \"%s\"\nReserved_bytes field in the file header is too small for GT.CM\n",
			fdi_ptr->fname));
			free(dsid_list->fname);
			dsid_list->fname = NULL;
			free(dsid_list);
			dsid_list = NULL;
			free(gv_cur_region->dyn.addr);
			gv_cur_region->dyn.addr = NULL;
			free(gv_cur_region);
			gv_cur_region = NULL;
			return RC_FILEACCESS;
		}
		assert(!cs_addrs->hold_onto_crit);	/* this ensures we can safely do unconditional grab_crit and rel_crit */
		grab_crit(gv_cur_region);
		cs_data->rc_srv_cnt++;
		if (!cs_data->dsid)
		{
			cs_data->dsid = dsid;
			cs_data->rc_node = node;
		} else if (cs_data->dsid != dsid || cs_data->rc_node != node)
		{
			cs_data->rc_srv_cnt--;
			rel_crit(gv_cur_region);
			OMI_DBG((omi_debug, "Dataset ID/RC node mismatch"));
			OMI_DBG((omi_debug, "DB file:  \"%s\"\n", dsid_list->fname));
			OMI_DBG((omi_debug, "Stored DSID:  %d\tRC Node:  %d\n", cs_data->dsid, cs_data->rc_node));
			OMI_DBG((omi_debug, "RC Rq DSID:  %d\tRC Node:  %d\n", dsid,node));
			free(fdi_ptr->fname);
			fdi_ptr->fname = NULL;
			free(fdi_ptr);
			fdi_ptr = NULL;
			free(gv_cur_region->dyn.addr);
			gv_cur_region->dyn.addr = NULL;
			free(gv_cur_region);
			gv_cur_region = NULL;
			return RC_FILEACCESS;
		}
		rel_crit(gv_cur_region);
		keysize = DBKEYSIZE(gv_cur_region->max_key_size);
		GVKEYSIZE_INCREASE_IF_NEEDED(keysize);
		cs_addrs->dir_tree = (gv_namehead *)malloc(SIZEOF(gv_namehead) + 2 * SIZEOF(gv_key) + 3 * (keysize - 1));
		g = cs_addrs->dir_tree;
		g->first_rec = (gv_key*)(g->clue.base + keysize);
		g->last_rec = (gv_key*)(g->first_rec->base + keysize);
		g->clue.top = g->last_rec->top = g->first_rec->top = keysize;
		g->clue.prev = g->clue.end = 0;
		g->root = DIR_ROOT;
		fdi_ptr->gda = (gd_addr*)malloc(SIZEOF(gd_addr) + 3 * SIZEOF(gd_binding));
		fdi_ptr->gda->n_maps = 3;
		fdi_ptr->gda->n_regions = 1;
		fdi_ptr->gda->n_segments = 1;
		fdi_ptr->gda->maps = (gd_binding*)((char*)fdi_ptr->gda + SIZEOF(gd_addr));
		fdi_ptr->gda->max_rec_size = gv_cur_region->max_rec_size;
		map = fdi_ptr->gda->maps;
		map ++;
		memset(map->name, 0, SIZEOF(map->name));
		map->name[0] = '%';
		map->reg.addr = gv_cur_region;
		map++;
		map->reg.addr = gv_cur_region;
		memset(map->name, -1, SIZEOF(map->name));
		fdi_ptr->gda->tab_ptr = (hash_table_mname *)malloc(SIZEOF(hash_table_mname));
		init_hashtab_mname(fdi_ptr->gda->tab_ptr, 0, HASHTAB_NO_COMPACT, HASHTAB_NO_SPARE_TABLE);
		fdi_ptr->next = dsid_list->next;
		dsid_list->next = fdi_ptr;
	}
	gv_cur_region = fdi_ptr->gda->maps[1].reg.addr;
	change_reg();
	if (rc_overflow->top < cs_addrs->hdr->blk_size)
	{
		if (rc_overflow->buff)
			free(rc_overflow->buff);
		rc_overflow->top = cs_addrs->hdr->blk_size;
		rc_overflow->buff = (char*)malloc(rc_overflow->top);
		if (rc_overflow_size < rc_overflow->top)
			rc_overflow_size = rc_overflow->top;
	}
	if (!rc_overflow -> top)
	{
		rc_overflow -> top = rc_overflow_size;
		rc_overflow->buff = (char *)malloc(rc_overflow->top);
	}
	gd_header = fdi_ptr->gda;
	return RC_SUCCESS;
}
Пример #21
0
int
omi_prc_def(omi_conn *cptr, char *xend, char *buff, char *bend)
{
    GBLREF bool	 undef_inhibit;

    char	*bptr;
    omi_li	 len;
    int		 rv;
    mval	 vo, vd, vg;

    bptr = buff;

/*  Global Ref */
    OMI_LI_READ(&len, cptr->xptr);
/*  Set up a condition handler */
    ESTABLISH_RET(omi_dbms_ch,0);
    rv = omi_gvextnam(cptr, len.value, cptr->xptr);
/*  If true, there was an error finding the global reference in the DBMS */
    if (rv < 0)
    {
	REVERT;
	return rv;
    }
    cptr->xptr += len.value;

/*  Bounds checking */
    if (cptr->xptr > xend)
    {
	REVERT;
	return -OMI_ER_PR_INVMSGFMT;
    }

/*  We want to make sure there is plenty of space in the string pool
 *  for all three operations ($ORDER, $GET, $DATA) */
    if (cptr->exts & OMI_XTF_NEWOP)
	stp_gcol(0);

/*  $DATA */
    op_gvdata(&vd);
    if (!(vd.mvtype & MV_INT))
    {
	REVERT;
	return -OMI_ER_DB_UNRECOVER;
    }

    if (cptr->exts & OMI_XTF_NEWOP)
    {
/*	$GET */
	undef_inhibit = TRUE;
	rv = op_gvget(&vg);
/*	$ORDER */
	op_gvorder(&vo);
	OMI_SI_WRIT(vo.str.len, bptr);
	if (vo.str.len)
	{
	    memcpy(bptr, vo.str.addr, vo.str.len);
	    bptr += vo.str.len;
	}
    }

/*  $DATA (buffer write) */
    OMI_SI_WRIT(vd.m[1] / MV_BIAS, bptr);

    if (cptr->exts & OMI_XTF_NEWOP)
    {
/*	$GET (buffer write) */
	OMI_SI_WRIT((rv ? 1 : 0), bptr);
	if (!rv || !vg.str.len)
	    OMI_LI_WRIT(0, bptr);
	else
	{
	    OMI_LI_WRIT(vg.str.len, bptr);
	    memcpy(bptr, vg.str.addr, vg.str.len);
	    bptr += vg.str.len;
	}
    }

    REVERT;

    return (int)(bptr - buff);

}
Пример #22
0
int gtmsource()
{
	int			status, log_init_status, waitpid_res, save_errno;
	char			print_msg[1024], tmpmsg[1024];
	gd_region		*reg, *region_top;
	sgmnt_addrs		*csa, *repl_csa;
	boolean_t		all_files_open, isalive;
	pid_t			pid, ppid, procgp;
	seq_num			read_jnl_seqno, jnl_seqno;
	unix_db_info		*udi;
	gtmsource_local_ptr_t	gtmsource_local;
	boolean_t		this_side_std_null_coll;
	int			null_fd, rc;

	memset((uchar_ptr_t)&jnlpool, 0, SIZEOF(jnlpool_addrs));
	call_on_signal = gtmsource_sigstop;
	ESTABLISH_RET(gtmsource_ch, SS_NORMAL);
	if (-1 == gtmsource_get_opt())
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUPCLIERR);
	if (gtmsource_options.shut_down)
	{	/* Wait till shutdown time nears even before going to "jnlpool_init". This is because the latter will return
		 * with the ftok semaphore and access semaphore held and we do not want to be holding those locks (while
		 * waiting for the user specified timeout to expire) as that will affect new GTM processes and/or other
		 * MUPIP REPLIC commands that need these locks for their function.
		 */
		if (0 < gtmsource_options.shutdown_time)
		{
			repl_log(stdout, TRUE, TRUE, "Waiting for %d seconds before signalling shutdown\n",
												gtmsource_options.shutdown_time);
			LONG_SLEEP(gtmsource_options.shutdown_time);
		} else
			repl_log(stdout, TRUE, TRUE, "Signalling shutdown immediate\n");
	} else if (gtmsource_options.start)
	{
		repl_log(stdout, TRUE, TRUE, "Initiating START of source server for secondary instance [%s]\n",
			gtmsource_options.secondary_instname);
	}
	if (gtmsource_options.activate && (ROOTPRIMARY_SPECIFIED == gtmsource_options.rootprimary))
	{	/* MUPIP REPLIC -SOURCE -ACTIVATE -UPDOK has been specified. We need to open the gld and db regions now
		 * in case this is a secondary -> primary transition. This is so we can later switch journal files in all
		 * journaled regions when the transition actually happens inside "gtmsource_rootprimary_init". But since
		 * we have not yet done a "jnlpool_init", we dont know if updates are disabled in it or not. Although we
		 * need to do the gld/db open only if updates are currently disabled in the jnlpool, we do this always
		 * because once we do a jnlpool_init, we will come back with the ftok on the jnlpool held and that has
		 * issues with later db open since we will try to hold the db ftok as part of db open and the ftok logic
		 * currently has assumptions that a process holds only one ftok at any point in time.
		 */
		assert(NULL == gd_header);
		gvinit();
		all_files_open = region_init(FALSE);
		if (!all_files_open)
		{
			gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOTALLDBOPN);
			gtmsource_exit(ABNORMAL_SHUTDOWN);
		}
	}
	jnlpool_init(GTMSOURCE, gtmsource_options.start, &is_jnlpool_creator);
	/* is_jnlpool_creator == TRUE ==> this process created the journal pool
	 * is_jnlpool_creator == FALSE ==> journal pool already existed and this process simply attached to it.
	 */
	if (gtmsource_options.shut_down)
		gtmsource_exit(gtmsource_shutdown(FALSE, NORMAL_SHUTDOWN) - NORMAL_SHUTDOWN);
	else if (gtmsource_options.activate)
		gtmsource_exit(gtmsource_mode_change(GTMSOURCE_MODE_ACTIVE_REQUESTED) - NORMAL_SHUTDOWN);
	else if (gtmsource_options.deactivate)
		gtmsource_exit(gtmsource_mode_change(GTMSOURCE_MODE_PASSIVE_REQUESTED) - NORMAL_SHUTDOWN);
	else if (gtmsource_options.checkhealth)
		gtmsource_exit(gtmsource_checkhealth() - NORMAL_SHUTDOWN);
	else if (gtmsource_options.changelog)
		 gtmsource_exit(gtmsource_changelog() - NORMAL_SHUTDOWN);
	else if (gtmsource_options.showbacklog)
		gtmsource_exit(gtmsource_showbacklog() - NORMAL_SHUTDOWN);
	else if (gtmsource_options.stopsourcefilter)
		gtmsource_exit(gtmsource_stopfilter() - NORMAL_SHUTDOWN);
	else if (gtmsource_options.jnlpool)
		gtmsource_exit(gtmsource_jnlpool() - NORMAL_SHUTDOWN);
	else if (gtmsource_options.losttncomplete)
		gtmsource_exit(gtmsource_losttncomplete() - NORMAL_SHUTDOWN);
	else if (gtmsource_options.needrestart)
		gtmsource_exit(gtmsource_needrestart() - NORMAL_SHUTDOWN);
	else if (gtmsource_options.showfreeze)
		gtmsource_exit(gtmsource_showfreeze() - NORMAL_SHUTDOWN);
	else if (gtmsource_options.setfreeze)
		gtmsource_exit(gtmsource_setfreeze() - NORMAL_SHUTDOWN);
	else if (!gtmsource_options.start)
	{
		assert(CLI_PRESENT == cli_present("STATSLOG"));
		gtmsource_exit(gtmsource_statslog() - NORMAL_SHUTDOWN);
	}
	assert(gtmsource_options.start);
#	ifndef REPL_DEBUG_NOBACKGROUND
	/* Set "child_server_running" to FALSE before forking off child. Wait for it to be set to TRUE by the child. */
	gtmsource_local = jnlpool.gtmsource_local;
	gtmsource_local->child_server_running = FALSE;
	FORK(pid);
	if (0 > pid)
	{
		save_errno = errno;
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0,
			ERR_TEXT, 2, RTS_ERROR_LITERAL("Could not fork source server"), save_errno);
	} else if (0 < pid)
	{	/* Parent. Wait until child sets "child_server_running" to FALSE. That is an indication that the child
		 * source server has completed its initialization phase and is all set so the parent command can return.
		 */
		while (isalive = is_proc_alive(pid, 0))	/* note : intended assignment */
		{
			if (gtmsource_local->child_server_running)
				break;
			/* To take care of reassignment of PIDs, the while condition should be && with the condition
			 * (PPID of pid == process_id)
			 */
			SHORT_SLEEP(GTMSOURCE_WAIT_FOR_SRV_START);
			WAITPID(pid, &status, WNOHANG, waitpid_res); /* Release defunct child if dead */
		}
		if (isalive)
		{	/* Child process is alive and started with no issues */
			if (0 != (save_errno = rel_sem(SOURCE, JNL_POOL_ACCESS_SEM)))
				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0,
					ERR_TEXT, 2, RTS_ERROR_LITERAL("Error in rel_sem"), save_errno);
			ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
		} else
		{	/* Child source server process errored out at startup and is no longer alive.
			 * If we were the one who created the journal pool, let us clean it up.
			 */
			repl_log(stdout, TRUE, TRUE, "Source server startup failed. See source server log file\n");
			if (is_jnlpool_creator)
				status = gtmsource_shutdown(TRUE, NORMAL_SHUTDOWN);
		}
		/* If the parent is killed (or crashes) between the fork and exit, checkhealth may not detect that startup
		 * is in progress - parent forks and dies, the system will release sem 0 and 1, checkhealth might test the
		 * value of sem 1 before the child grabs sem 1.
		 */
		gtmsource_exit(isalive ? SRV_ALIVE : SRV_ERR);
	}
	/* Point stdin to /dev/null */
	OPENFILE("/dev/null", O_RDONLY, null_fd);
	if (0 > null_fd)
		rts_error_csa(CSA_ARG(NULL) ERR_REPLERR, RTS_ERROR_LITERAL("Failed to open /dev/null for read"), errno, 0);
	FCNTL3(null_fd, F_DUPFD, 0, rc);
	if (0 > rc)
		rts_error_csa(CSA_ARG(NULL) ERR_REPLERR, RTS_ERROR_LITERAL("Failed to set stdin to /dev/null"), errno, 0);
	CLOSEFILE(null_fd, rc);
	if (0 > rc)
		rts_error_csa(CSA_ARG(NULL) ERR_REPLERR, RTS_ERROR_LITERAL("Failed to close /dev/null"), errno, 0);
	/* The parent process (source server startup command) will be holding the ftok semaphore and jnlpool access semaphore
	 * at this point. The variables that indicate this would have been copied over to the child during the fork. This will
	 * make the child think it is actually holding them as well when actually it is not. Reset those variables in the child
	 * to ensure they do not misrepresent the holder of those semaphores.
	 */
	ftok_sem_reg = NULL;
	udi = FILE_INFO(jnlpool.jnlpool_dummy_reg);
	assert(udi->grabbed_ftok_sem);
	udi->grabbed_ftok_sem = FALSE;
	assert(holds_sem[SOURCE][JNL_POOL_ACCESS_SEM]);
	holds_sem[SOURCE][JNL_POOL_ACCESS_SEM] = FALSE;
	assert(!holds_sem[SOURCE][SRC_SERV_COUNT_SEM]);
	/* Start child source server initialization */
	is_src_server = TRUE;
	OPERATOR_LOG_MSG;
	process_id = getpid();
	/* Reinvoke secshr related initialization with the child's pid */
	INVOKE_INIT_SECSHR_ADDRS;
	/* Initialize mutex socket, memory semaphore etc. before any "grab_lock" is done by this process on the journal pool.
	 * Note that the initialization would already have been done by the parent receiver startup command but we need to
	 * redo the initialization with the child process id.
	 */
	assert(mutex_per_process_init_pid && (mutex_per_process_init_pid != process_id));
	mutex_per_process_init();
	START_HEARTBEAT_IF_NEEDED;
	ppid = getppid();
	log_init_status = repl_log_init(REPL_GENERAL_LOG, &gtmsource_log_fd, gtmsource_options.log_file);
	assert(SS_NORMAL == log_init_status);
	repl_log_fd2fp(&gtmsource_log_fp, gtmsource_log_fd);
	if (-1 == (procgp = setsid()))
		send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
				RTS_ERROR_LITERAL("Source server error in setsid"), errno);
#	endif /* REPL_DEBUG_NOBACKGROUND */
	if (ZLIB_CMPLVL_NONE != gtm_zlib_cmp_level)
		gtm_zlib_init();	/* Open zlib shared library for compression/decompression */
	REPL_DPRINT1("Setting up regions\n");
	gvinit();

	/* We use the same code dse uses to open all regions but we must make sure they are all open before proceeding. */
	all_files_open = region_init(FALSE);
	if (!all_files_open)
	{
		gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOTALLDBOPN);
		gtmsource_exit(ABNORMAL_SHUTDOWN);
	}
	/* Determine primary side null subscripts collation order */
	/* Also check whether all regions have same null collation order */
	this_side_std_null_coll = -1;
	for (reg = gd_header->regions, region_top = gd_header->regions + gd_header->n_regions; reg < region_top; reg++)
	{
		csa = &FILE_INFO(reg)->s_addrs;
		if (this_side_std_null_coll != csa->hdr->std_null_coll)
		{
			if (-1 == this_side_std_null_coll)
				this_side_std_null_coll = csa->hdr->std_null_coll;
			else
			{
				gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NULLCOLLDIFF);
				gtmsource_exit(ABNORMAL_SHUTDOWN);
			}
		}
		if (!REPL_ALLOWED(csa) && JNL_ALLOWED(csa))
		{
			gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_REPLOFFJNLON, 2, DB_LEN_STR(reg));
			gtmsource_exit(ABNORMAL_SHUTDOWN);
		}
		if (reg->read_only && REPL_ALLOWED(csa))
		{
			gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
				   RTS_ERROR_LITERAL("Source Server does not have write permissions to one or "
					             "more database files that are replicated"));
			gtmsource_exit(ABNORMAL_SHUTDOWN);
		}
	}
	/* Initialize source server alive/dead state related fields in "gtmsource_local" before the ftok semaphore is released */
	gtmsource_local->gtmsource_pid = process_id;
	gtmsource_local->gtmsource_state = GTMSOURCE_START;
	if (is_jnlpool_creator)
	{
		DEBUG_ONLY(jnlpool.jnlpool_ctl->jnlpool_creator_pid = process_id);
		gtmsource_seqno_init(this_side_std_null_coll);
		if (ROOTPRIMARY_SPECIFIED == gtmsource_options.rootprimary)
		{	/* Created the journal pool as a root primary. Append a history record to the replication instance file.
			 * Invoke the function "gtmsource_rootprimary_init" to do that.
			 */
			gtmsource_rootprimary_init(jnlpool.jnlpool_ctl->jnl_seqno);
		}
	}
	/* after this point we can no longer have the case where all the regions are unreplicated/non-journaled. */
#	ifndef REPL_DEBUG_NOBACKGROUND
	/* It is necessary for every process that is using the ftok semaphore to increment the counter by 1. This is used
	 * by the last process that shuts down to delete the ftok semaphore when it notices the counter to be 0.
	 * Note that the parent source server startup command would have done an increment of the ftok counter semaphore
	 * for the replication instance file. But the source server process (the child) that comes here would not have done
	 * that. Do that while the parent is still holding on to the ftok semaphore waiting for our okay.
	 */
	if (!ftok_sem_incrcnt(jnlpool.jnlpool_dummy_reg))
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JNLPOOLSETUP);
	/* Increment the source server count semaphore */
	status = incr_sem(SOURCE, SRC_SERV_COUNT_SEM);
	if (0 != status)
	{
		save_errno = errno;
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
			RTS_ERROR_LITERAL("Counter semaphore increment failure in child source server"), save_errno);
	}
#	else
	if (0 != (save_errno = rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM)))
	{
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
			RTS_ERROR_LITERAL("Error in rel_sem_immediate"), save_errno);
	}
#	endif /* REPL_DEBUG_NOBACKGROUND */

	gtmsource_srv_count++;
	gtmsource_local->child_server_running = TRUE;	/* At this point, the parent startup command will stop waiting for child */
	gtm_event_log_init();
	/* Log source server startup command line first */
	SPRINTF(tmpmsg, "%s %s\n", cli_lex_in_ptr->argv[0], cli_lex_in_ptr->in_str);
	repl_log(gtmsource_log_fp, TRUE, TRUE, tmpmsg);

	SPRINTF(tmpmsg, "GTM Replication Source Server with Pid [%d] started for Secondary Instance [%s]",
		process_id, gtmsource_local->secondary_instname);
	sgtm_putmsg(print_msg, VARLSTCNT(4) ERR_REPLINFO, 2, LEN_AND_STR(tmpmsg));
	repl_log(gtmsource_log_fp, TRUE, TRUE, print_msg);
	if (is_jnlpool_creator)
	{
		repl_log(gtmsource_log_fp, TRUE, TRUE, "Created jnlpool with shmid = [%d] and semid = [%d]\n",
			jnlpool.repl_inst_filehdr->jnlpool_shmid, jnlpool.repl_inst_filehdr->jnlpool_semid);
	} else
		repl_log(gtmsource_log_fp, TRUE, TRUE, "Attached to existing jnlpool with shmid = [%d] and semid = [%d]\n",
			jnlpool.repl_inst_filehdr->jnlpool_shmid, jnlpool.repl_inst_filehdr->jnlpool_semid);
	gtm_event_log(GTM_EVENT_LOG_ARGC, "MUPIP", "REPLINFO", print_msg);
#	ifdef GTM_TLS
	if (REPL_TLS_REQUESTED)
	{
		repl_do_tls_init(gtmsource_log_fp);
		assert(REPL_TLS_REQUESTED || PLAINTEXT_FALLBACK);
	}
#	endif
	if (jnlpool.jnlpool_ctl->freeze)
	{
		last_seen_freeze_flag = jnlpool.jnlpool_ctl->freeze;
		sgtm_putmsg(print_msg, VARLSTCNT(3) ERR_REPLINSTFROZEN, 1, jnlpool.repl_inst_filehdr->inst_info.this_instname);
		repl_log(gtmsource_log_fp, TRUE, FALSE, print_msg);
		sgtm_putmsg(print_msg, VARLSTCNT(3) ERR_REPLINSTFREEZECOMMENT, 1, jnlpool.jnlpool_ctl->freeze_comment);
		repl_log(gtmsource_log_fp, TRUE, TRUE, print_msg);
	}
	gtmsource_local->jnlfileonly = gtmsource_options.jnlfileonly;
	do
	{ 	/* If mode is passive, go to sleep. Wakeup every now and then and check to see if I have to become active. */
		gtmsource_state = gtmsource_local->gtmsource_state = GTMSOURCE_START;
		if ((gtmsource_local->mode == GTMSOURCE_MODE_PASSIVE) && (gtmsource_local->shutdown == NO_SHUTDOWN))
		{
			gtmsource_poll_actions(FALSE);
			SHORT_SLEEP(GTMSOURCE_WAIT_FOR_MODE_CHANGE);
			continue;
		}
		if (GTMSOURCE_MODE_PASSIVE == gtmsource_local->mode)
		{	/* Shutdown initiated */
			assert(gtmsource_local->shutdown == SHUTDOWN);
			sgtm_putmsg(print_msg, VARLSTCNT(4) ERR_REPLINFO, 2,
				    RTS_ERROR_LITERAL("GTM Replication Source Server Shutdown signalled"));
			repl_log(gtmsource_log_fp, TRUE, TRUE, print_msg);
			gtm_event_log(GTM_EVENT_LOG_ARGC, "MUPIP", "REPLINFO", print_msg);
			break;
		}
		gtmsource_poll_actions(FALSE);
		if (GTMSOURCE_CHANGING_MODE == gtmsource_state)
			continue;
		if (GTMSOURCE_MODE_ACTIVE_REQUESTED == gtmsource_local->mode)
			gtmsource_local->mode = GTMSOURCE_MODE_ACTIVE;
		SPRINTF(tmpmsg, "GTM Replication Source Server now in ACTIVE mode using port %d", gtmsource_local->secondary_port);
		sgtm_putmsg(print_msg, VARLSTCNT(4) ERR_REPLINFO, 2, LEN_AND_STR(tmpmsg));
		repl_log(gtmsource_log_fp, TRUE, TRUE, print_msg);
		gtm_event_log(GTM_EVENT_LOG_ARGC, "MUPIP", "REPLINFO", print_msg);
		DEBUG_ONLY(repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;)
		assert(!repl_csa->hold_onto_crit);	/* so it is ok to invoke "grab_lock" and "rel_lock" unconditionally */
		grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK);
		if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state)
		{
			repl_log(gtmsource_log_fp, TRUE, TRUE, "Starting afresh due to ONLINE ROLLBACK\n");
			repl_log(gtmsource_log_fp, TRUE, TRUE, "REPL INFO - Current Jnlpool Seqno : %llu\n",
					jnlpool.jnlpool_ctl->jnl_seqno);
			continue;
		}
		QWASSIGN(gtmsource_local->read_addr, jnlpool.jnlpool_ctl->write_addr);
		gtmsource_local->read = jnlpool.jnlpool_ctl->write;
		gtmsource_local->read_state = gtmsource_local->jnlfileonly ? READ_FILE : READ_POOL;
		read_jnl_seqno = gtmsource_local->read_jnl_seqno;
		assert(read_jnl_seqno <= jnlpool.jnlpool_ctl->jnl_seqno);
		if (read_jnl_seqno < jnlpool.jnlpool_ctl->jnl_seqno)
		{
			gtmsource_local->read_state = READ_FILE;
			QWASSIGN(gtmsource_save_read_jnl_seqno, jnlpool.jnlpool_ctl->jnl_seqno);
			gtmsource_pool2file_transition = TRUE; /* so that we read the latest gener jnl files */
		}
		rel_lock(jnlpool.jnlpool_dummy_reg);
		if (SS_NORMAL != (status = gtmsource_alloc_tcombuff()))
			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
				  RTS_ERROR_LITERAL("Error allocating initial tcom buffer space. Malloc error"), status);
		gtmsource_filter = NO_FILTER;
		if ('\0' != gtmsource_local->filter_cmd[0])
		{
			if (SS_NORMAL == (status = repl_filter_init(gtmsource_local->filter_cmd)))
				gtmsource_filter |= EXTERNAL_FILTER;
			else
				gtmsource_exit(ABNORMAL_SHUTDOWN);
		}
		gtmsource_process();
		/* gtmsource_process returns only when mode needs to be changed to PASSIVE */
		assert(gtmsource_state == GTMSOURCE_CHANGING_MODE);
		gtmsource_ctl_close();
		gtmsource_free_msgbuff();
		gtmsource_free_tcombuff();
		gtmsource_free_filter_buff();
		gtmsource_stop_heartbeat();
		if (FD_INVALID != gtmsource_sock_fd)
			repl_close(&gtmsource_sock_fd);
		if (gtmsource_filter & EXTERNAL_FILTER)
			repl_stop_filter();
	} while (TRUE);
Пример #23
0
int gtm_trigger_complink(gv_trigger_t *trigdsc, boolean_t dolink)
{
	char		rtnname[GTM_PATH_MAX + 1], rtnname_template[GTM_PATH_MAX + 1];
	char		objname[GTM_PATH_MAX + 1];
	char		zcomp_parms[(GTM_PATH_MAX * 2) + SIZEOF(mident_fixed) + SIZEOF(OBJECT_PARM) + SIZEOF(NAMEOFRTN_PARM)];
	mstr		save_zsource;
	int		rtnfd, rc, lenrtnname, lenobjname, len, alphnum_len, retry, save_errno;
	char		*mident_suffix_p1, *mident_suffix_p2, *mident_suffix_top, *namesub1, *namesub2, *zcomp_parms_ptr;
	mval		zlfile, zcompprm;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	DBGTRIGR_ONLY(memcpy(rtnname, trigdsc->rtn_desc.rt_name.addr, trigdsc->rtn_desc.rt_name.len));
	DBGTRIGR_ONLY(rtnname[trigdsc->rtn_desc.rt_name.len] = 0);
	DBGTRIGR((stderr, "gtm_trigger_complink: (Re)compiling trigger %s\n", rtnname));
	ESTABLISH_RET(gtm_trigger_complink_ch, ((0 == error_condition) ? TREF(dollar_zcstatus) : error_condition ));
	 /* Verify there are 2 available chars for uniqueness */
	assert((MAX_MIDENT_LEN - TRIGGER_NAME_RESERVED_SPACE) >= (trigdsc->rtn_desc.rt_name.len));
	assert(NULL == trigdsc->rtn_desc.rt_adr);
	gtm_trigger_comp_prev_run_time = run_time;
	run_time = TRUE;	/* Required by compiler */
	/* Verify the routine name set by MUPIP TRIGGER and read by gvtr_db_read_hasht() is not in use */
	if (NULL != find_rtn_hdr(&trigdsc->rtn_desc.rt_name))
	{	/* Ooops .. need name to be more unique.. */
		/* Though variable definitions are conventionally done at the function entry, the reason alphanumeric_table
		 * definition is done here is to minimize the time taken to initialize the below table in the most common case
		 * (i.e. no trigger name collisions).
		 */
		char 		alphanumeric_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
							'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
							'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
							't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
							'8', '9', '\0'};
		alphnum_len = STR_LIT_LEN(alphanumeric_table);
		namesub1 = trigdsc->rtn_desc.rt_name.addr + trigdsc->rtn_desc.rt_name.len++;
		/* If WBTEST_HELPOUT_TRIGNAMEUNIQ is defined, set alphnum_len to 1. This way, we make the maximum
		 * possible combinations for the uniqe trigger names to be 3 which is significantly lesser than
		 * the actual number of combinations (62x62 = 3844). For eg., if ^a is a global having triggers defined
		 * in 4 global directories, then the possible unique trigger names are a#1# ; a#1#A ; a#1#AA.
		 */
		GTM_WHITE_BOX_TEST(WBTEST_HELPOUT_TRIGNAMEUNIQ, alphnum_len, 1);
		mident_suffix_top = (char *)alphanumeric_table + alphnum_len;
		/* Phase 1. See if any single character can add uniqueness */
		for (mident_suffix_p1 = (char *)alphanumeric_table; mident_suffix_p1 < mident_suffix_top; mident_suffix_p1++)
		{
			*namesub1 = *mident_suffix_p1;
			if (NULL == find_rtn_hdr(&trigdsc->rtn_desc.rt_name))
				break;
		}
		if (mident_suffix_p1 == mident_suffix_top)
		{	/* Phase 2. Phase 1 could not find uniqueness .. Find it with 2 char variations */
			namesub2 = trigdsc->rtn_desc.rt_name.addr + trigdsc->rtn_desc.rt_name.len++;
			for (mident_suffix_p1 = (char *)alphanumeric_table; mident_suffix_p1 < mident_suffix_top;
			     mident_suffix_p1++)
			{	/* First char loop */
				for (mident_suffix_p2 = (char *)alphanumeric_table; mident_suffix_p2 < mident_suffix_top;
				     mident_suffix_p2++)
				{	/* 2nd char loop */
					*namesub1 = *mident_suffix_p1;
					*namesub2 = *mident_suffix_p2;
					if (NULL == find_rtn_hdr(&trigdsc->rtn_desc.rt_name))
					{
						mident_suffix_p1 = mident_suffix_top + 1;	/* Break out of both loops */
						break;
					}
				}
			}
			if (mident_suffix_p1 == mident_suffix_top)
			{	/* Phase 3: Punt */
				assert(WBTEST_HELPOUT_TRIGNAMEUNIQ == gtm_white_box_test_case_number);
				rts_error(VARLSTCNT(5) ERR_TRIGNAMEUNIQ, 3, trigdsc->rtn_desc.rt_name.len - 2,
					  trigdsc->rtn_desc.rt_name.addr, alphnum_len * alphnum_len);
			}
		}
	}
	/* Write trigger execute string out to temporary file and compile it */
	assert(MAX_XECUTE_LEN >= trigdsc->xecute_str.str.len);
	rc = SNPRINTF(rtnname_template, GTM_PATH_MAX, "%s/trgtmpXXXXXX", DEFAULT_GTM_TMP);
	assert(0 < rc);					/* Note rc is return code aka length - we expect a non-zero length */
	assert(GTM_PATH_MAX >= rc);
	/* The mkstemp() routine is known to bogus-fail for no apparent reason at all especially on AIX 6.1. In the event
	 * this shortcoming plagues other platforms as well, we add a low-cost retry wrapper.
	 */
	retry = MAX_MKSTEMP_RETRIES;
	do
	{
		strcpy(rtnname, rtnname_template);
		rtnfd = mkstemp(rtnname);
	} while ((-1 == rtnfd) && (EEXIST == errno) && (0 < --retry));
	if (-1 == rtnfd)
	{
		save_errno = errno;
		assert(FALSE);
		rts_error(VARLSTCNT(12) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("mkstemp()"), CALLFROM,
			  ERR_TEXT, 2, RTS_ERROR_TEXT(rtnname), save_errno);
	}
	assert(0 < rtnfd);	/* Verify file descriptor */
	rc = 0;
#	ifdef GEN_TRIGCOMPFAIL_ERROR
	{	/* Used ONLY to generate an error in a trigger compile by adding some junk in a previous line */
		DOWRITERC(rtnfd, ERROR_CAUSING_JUNK, strlen(ERROR_CAUSING_JUNK), rc); /* BYPASSOK */
		if (0 != rc)
		{
			UNLINK(rtnname);
			rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("write()"), CALLFROM, rc);
		}
	}
#	endif
	DOWRITERC(rtnfd, trigdsc->xecute_str.str.addr, trigdsc->xecute_str.str.len, rc);
	if (0 != rc)
	{
		UNLINK(rtnname);
		rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("write()"), CALLFROM, rc);
	}
	if (NULL == memchr(trigdsc->xecute_str.str.addr, '\n', trigdsc->xecute_str.str.len))
	{
		DOWRITERC(rtnfd, NEWLINE, strlen(NEWLINE), rc);			/* BYPASSOK */
		if (0 != rc)
		{
			UNLINK(rtnname);
			rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("write()"), CALLFROM, rc);
		}
	}
	CLOSEFILE(rtnfd, rc);
	if (0 != rc)
	{
		UNLINK(rtnname);
		rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("close()"), CALLFROM, rc);
	}
	assert(MAX_MIDENT_LEN > trigdsc->rtn_desc.rt_name.len);
	zcomp_parms_ptr = zcomp_parms;
	lenrtnname = STRLEN(rtnname);
	MEMCPY_LIT(zcomp_parms_ptr, NAMEOFRTN_PARM);
	zcomp_parms_ptr += STRLEN(NAMEOFRTN_PARM);
	memcpy(zcomp_parms_ptr, trigdsc->rtn_desc.rt_name.addr, trigdsc->rtn_desc.rt_name.len);
	zcomp_parms_ptr += trigdsc->rtn_desc.rt_name.len;
	MEMCPY_LIT(zcomp_parms_ptr, OBJECT_PARM);
	zcomp_parms_ptr += STRLEN(OBJECT_PARM);
	strcpy(objname, rtnname);		/* Make copy of rtnname to become object name */
	strcat(objname, OBJECT_FTYPE);		/* Turn into object file reference */
	lenobjname = lenrtnname + STRLEN(OBJECT_FTYPE);
	memcpy(zcomp_parms_ptr, objname, lenobjname);
	zcomp_parms_ptr += lenobjname;
	*zcomp_parms_ptr++ = ' ';
	memcpy(zcomp_parms_ptr, rtnname, lenrtnname);
	zcomp_parms_ptr += lenrtnname;
	*zcomp_parms_ptr = '\0';		/* Null tail */
	len = INTCAST(zcomp_parms_ptr - zcomp_parms);
	assert((SIZEOF(zcomp_parms) - 1) > len);	/* Verify no overflow */
	zcompprm.mvtype = MV_STR;
	zcompprm.str.addr = zcomp_parms;
	zcompprm.str.len = len;
	/* Backup dollar_zsource so trigger doesn't show */
	PUSH_MV_STENT(MVST_MSAV);
	mv_chain->mv_st_cont.mvs_msav.v = dollar_zsource;
	mv_chain->mv_st_cont.mvs_msav.addr = &dollar_zsource;
	TREF(trigger_compile) = TRUE;		/* Set flag so compiler knows this is a special trigger compile */
	op_zcompile(&zcompprm, FALSE);	/* Compile but don't require a .m file extension */
	TREF(trigger_compile) = FALSE;	/* compile_source_file() establishes handler so always returns */
	if (0 != TREF(dollar_zcstatus))
	{	/* Someone err'd.. */
		run_time = gtm_trigger_comp_prev_run_time;
		REVERT;
		UNLINK(objname);	/* Remove files before return error */
		UNLINK(rtnname);
		return ERR_TRIGCOMPFAIL;
	}
	if (dolink)
	{	/* Link is optional as MUPIP TRIGGER doesn't need link */
		zlfile.mvtype = MV_STR;
		zlfile.str.addr = objname;
		zlfile.str.len = lenobjname;
		/* Specifying literal_null for a second arg (as opposed to NULL or 0) allows us to specify
		 * linking the object file (no compilation or looking for source). The 2nd arg is parms for
		 * recompilation and is non-null in an explicit zlink which we need to emulate.
		 */
#		ifdef GEN_TRIGLINKFAIL_ERROR
		UNLINK(objname);				/* delete object before it can be used */
#		endif
		op_zlink(&zlfile, (mval *)&literal_null);	/* need cast due to "extern const" attributes */
		/* No return here if link fails for some reason */
		trigdsc->rtn_desc.rt_adr = find_rtn_hdr(&trigdsc->rtn_desc.rt_name);
		if (NULL == trigdsc->rtn_desc.rt_adr)
			GTMASSERT;	/* Can't find routine we just put there? Catastrophic if happens */
		/* Replace the randomly generated source name with the constant "GTM Trigger" */
		trigdsc->rtn_desc.rt_adr->src_full_name.addr = GTM_TRIGGER_SOURCE_NAME;
		trigdsc->rtn_desc.rt_adr->src_full_name.len = STRLEN(GTM_TRIGGER_SOURCE_NAME);
		trigdsc->rtn_desc.rt_adr->trigr_handle = trigdsc;       /* Back pointer to trig def */
	}
	if (MVST_MSAV == mv_chain->mv_st_type && &dollar_zsource == mv_chain->mv_st_cont.mvs_msav.addr)
	{       /* Top mv_stent is one we pushed on there - restore dollar_zsource and get rid of it */
		dollar_zsource = mv_chain->mv_st_cont.mvs_msav.v;
		POP_MV_STENT();
	} else
		assert(FALSE); 	/* This mv_stent should be the one we just pushed */
	/* Remove temporary files created */
	UNLINK(objname);	/* Delete the object file first since rtnname is the unique key */
	UNLINK(rtnname);	/* Delete the source file */
	run_time = gtm_trigger_comp_prev_run_time;
	REVERT;
	return 0;
}
Пример #24
0
STATICFNDEF boolean_t trigger_trgfile_tpwrap_helper(char *trigger_filename, uint4 trigger_filename_len, boolean_t noprompt,
						    boolean_t lcl_implicit_tpwrap)
{
	boolean_t		all_triggers_error;
	uint4			i;
	io_pair			io_save_device;
	io_pair			io_trigfile_device;
	int			len;
	int4			record_num;
	boolean_t		trigger_status;
	enum cdb_sc		cdb_status;
	uint4			trig_stats[NUM_STATS];
	char			*trigger_rec;
	char			*values[NUM_SUBS];
	unsigned short		value_len[NUM_SUBS];

	all_triggers_error = FALSE;
	if (lcl_implicit_tpwrap)
		ESTABLISH_RET(trigger_tpwrap_ch, TRIG_FAILURE);	/* Return through here is a failure */
	io_save_device = io_curr_device;
	file_input_init(trigger_filename, trigger_filename_len);
	if (mupip_error_occurred)
		TRIG_ERROR_RETURN;
	io_trigfile_device = io_curr_device;
	record_num = 0;
	for (i = 0; NUM_STATS > i; i++)
		trig_stats[i] = 0;
	while ((0 == io_curr_device.in->dollar.zeof) && (0 <= (len = file_input_get(&trigger_rec))))
	{
		io_curr_device = io_save_device;
		record_num++;
		if ((0 != len) && (COMMENT_LITERAL != trigger_rec[0]))
			util_out_print_gtmio("File !AD, Line !UL: ", NOFLUSH, trigger_filename_len, trigger_filename, record_num);
		trigger_status = trigger_update_rec(trigger_rec, (uint4)len, noprompt, trig_stats, &io_trigfile_device,
						    &record_num);
		all_triggers_error |= (TRIG_FAILURE == trigger_status);
		io_curr_device = io_trigfile_device;
	}
	if ((-1 == len) && (!io_curr_device.in->dollar.zeof))
	{
		io_curr_device = io_save_device;
		util_out_print_gtmio("File !AD, Line !UL: Line too long", FLUSH, trigger_filename_len, trigger_filename,
			++record_num);
	}
	file_input_close();
	io_curr_device = io_save_device;
	if (all_triggers_error)
	{
		util_out_print_gtmio("=========================================", FLUSH);
		util_out_print_gtmio("!UL trigger file entries matched existing triggers", FLUSH, trig_stats[STATS_UNCHANGED]);
		util_out_print_gtmio("!UL trigger file entries have errors", FLUSH, trig_stats[STATS_ERROR]);
		util_out_print_gtmio("!UL trigger file entries have no errors", FLUSH,
				     trig_stats[STATS_ADDED] + trig_stats[STATS_DELETED] + trig_stats[STATS_MODIFIED]);
		util_out_print_gtmio("=========================================", FLUSH);
		TRIG_ERROR_RETURN;
	}
	if (lcl_implicit_tpwrap)
	{
		GVTR_OP_TCOMMIT(cdb_status);
		if (cdb_sc_normal != cdb_status)
			t_retry(cdb_status);	/* won't return */
		REVERT;
	}
	if ((0 == trig_stats[STATS_ERROR])
		&& (0 != (trig_stats[STATS_ADDED] + trig_stats[STATS_DELETED] + trig_stats[STATS_UNCHANGED]
			  + trig_stats[STATS_MODIFIED])))
	{
		util_out_print_gtmio("=========================================", FLUSH);
		util_out_print_gtmio("!UL triggers added", FLUSH, trig_stats[STATS_ADDED]);
		util_out_print_gtmio("!UL triggers deleted", FLUSH, trig_stats[STATS_DELETED]);
		util_out_print_gtmio("!UL trigger file entries not changed", FLUSH, trig_stats[STATS_UNCHANGED]);
		util_out_print_gtmio("!UL triggers modified", FLUSH, trig_stats[STATS_MODIFIED]);
		util_out_print_gtmio("=========================================", FLUSH);
	} else if (0 != trig_stats[STATS_ERROR])
	{
		util_out_print_gtmio("=========================================", FLUSH);
		util_out_print_gtmio("!UL trigger file entries matched existing triggers", FLUSH, trig_stats[STATS_UNCHANGED]);
		util_out_print_gtmio("!UL trigger file entries have errors", FLUSH, trig_stats[STATS_ERROR]);
		util_out_print_gtmio("!UL trigger file entries have no errors", FLUSH,
			       trig_stats[STATS_ADDED] + trig_stats[STATS_DELETED] + trig_stats[STATS_MODIFIED]);
		util_out_print_gtmio("=========================================", FLUSH);
	}
	return TRIG_SUCCESS;
}
Пример #25
0
/* On OSF/1 (Digital Unix), pointers are 64 bits wide; the only exception to this is C programs for which one may
 * specify compiler and link editor options in order to use (and allocate) 32-bit pointers.  However, since C is
 * the only exception and, in particular because the operating system does not support such an exception, the argv
 * array passed to the main program is an array of 64-bit pointers.  Thus the C program needs to declare argv[]
 * as an array of 64-bit pointers and needs to do the same for any pointer it sets to an element of argv[].
 */
int main(int argc, char_ptr_t argv[])
{
    omi_conn	 *cptr, conn;
    int		  i;
    char	  buff[OMI_BUFSIZ];
    DCL_THREADGBL_ACCESS;

    GTM_THREADGBL_INIT;
    set_blocksig();
    gtm_env_init(); /* read in all environment variables before calling any function particularly malloc (from err_init below)*/
/*  Open the packet log file for playback */
    if (argc == 1)
	conn.fd = fileno(stdin);
    else if (argc == 2) {
	if (INV_FD_P((conn.fd = open(argv[argc - 1], O_RDONLY))))
	{
	    PRINTF("%s: open(\"%s\"): %s\n", argv[0], argv[argc - 1],
		   STRERROR(errno));
	    exit(-1);
	}
    }
    else {
	PRINTF("%s: bad command line arguments\n\t%s [ filename ]\n",
	       argv[0], argv[0]);
	exit(-1);
    }

/*  Initialize everything but the network */
    err_init(gtcm_exit_ch);
    omi_errno = OMI_ER_NO_ERROR;
    ESTABLISH_RET(omi_dbms_ch, -1);	/* any return value to signify error return */
    gtcm_init(argc, argv);
#ifdef GTCM_RC
    rc_create_cpt();
#endif
    REVERT;
    if (omi_errno != OMI_ER_NO_ERROR)
	exit(omi_errno);
/*  Initialize the connection structure */
    conn.next   = (omi_conn *)0;
    conn.bsiz   = OMI_BUFSIZ;
    conn.bptr   = conn.buff   = buff;
    conn.xptr   = (char *)0;
    conn.blen   = 0;
    conn.exts   = 0;
    conn.state  = OMI_ST_DISC;
    conn.ga     = (ga_struct *)0;	/* struct gd_addr_struct */
    conn.of     = (oof_struct *)0;	/* struct rc_oflow */
    conn.pklog  = FD_INVALID;
/*  Initialize the statistics */
    conn.stats.bytes_recv = 0;
    conn.stats.bytes_send = 0;
    conn.stats.start      = time((time_t *)0);
    for (i = 0; i < OMI_OP_MAX; i++)
	conn.stats.xact[i] = 0;
    for (i = 0; i < OMI_ER_MAX; i++)
	conn.stats.errs[i] = 0;

    for (;;)
	if (omi_srvc_xact(&conn) < 0)
	    break;

    PRINTF("%ld seconds connect time\n", time((time_t)0) - conn.stats.start);
    PRINTF("%d OMI transactions\n", omi_nxact);
    PRINTF("%d OMI errors\n", omi_nerrs);
#ifdef GTCM_RC
    PRINTF("%d RC transactions\n", rc_nxact);
    PRINTF("%d RC errors\n", rc_nerrs);
#endif /* defined(GTCM_RC) */
    PRINTF("%d bytes recv'd\n", conn.stats.bytes_recv);
    PRINTF("%d bytes sent\n", conn.stats.bytes_send);

    gtcm_exit();

    return 0;

}
Пример #26
0
int op_fnzsearch(mval *file, mint indx, mval *ret)
{
	struct stat	statbuf;
	int		stat_res;
	parse_blk	pblk;
	plength		*plen, pret;
	char		buf1[MAX_FBUFF + 1]; /* buffer to hold translated name */
	mval		sub;
	mstr		tn;
	lv_val		*ind_tmp;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	ESTABLISH_RET(fnzsrch_ch, -1);
	TREF(fnzsearch_nullsubs_sav) = TREF(lv_null_subs);
	TREF(lv_null_subs) = LVNULLSUBS_OK;	/* $ZSearch processing depends on this */
	MV_FORCE_STR(file);
	if (file->str.len > MAX_FBUFF)
		rts_error(VARLSTCNT(4) ERR_INVSTRLEN, 2, file->str.len, MAX_FBUFF);
	MV_FORCE_MVAL(((mval *)TADR(fnzsearch_sub_mval)), indx);
	TREF(fnzsearch_lv_vars) = op_srchindx(VARLSTCNT(2) TREF(zsearch_var), (mval *)TADR(fnzsearch_sub_mval));
	if (TREF(fnzsearch_lv_vars))
	{
		assert((TREF(fnzsearch_lv_vars))->v.mvtype & MV_STR);
		if ((file->str.len != (TREF(fnzsearch_lv_vars))->v.str.len)
			|| memcmp(file->str.addr, (TREF(fnzsearch_lv_vars))->v.str.addr, file->str.len))
		{
			op_kill(TREF(fnzsearch_lv_vars));
			TREF(fnzsearch_lv_vars) = NULL;
		}
	}
	if (TREF(fnzsearch_lv_vars))
	{
		for (;;)
		{
			pret.p.pint = pop_top(TREF(fnzsearch_lv_vars), ret);	/* get next element off the top */
			if (!ret->str.len)
				break;
			memcpy(buf1, ret->str.addr, ret->str.len);
			buf1[ret->str.len] = 0;
			STAT_FILE(buf1, &statbuf, stat_res);
			if (-1 == stat_res)
			{
				if (errno == ENOENT)
					continue;
				rts_error(VARLSTCNT(1) errno);
			}
			break;
		}
	} else
	{
		memset(&pblk, 0, SIZEOF(pblk));
		pblk.buffer = buf1;
		pblk.buff_size = MAX_FBUFF;
		if (!(parse_file(&file->str, &pblk) & 1))
		{
			ret->mvtype = MV_STR;
			ret->str.len = 0;
		} else
		{
			assert(!TREF(fnzsearch_lv_vars));
			buf1[pblk.b_esl] = 0;
			/* establish new search context */
			TREF(fnzsearch_lv_vars) = op_putindx(VARLSTCNT(2) TREF(zsearch_var), TADR(fnzsearch_sub_mval));
			(TREF(fnzsearch_lv_vars))->v = *file;	/* zsearch_var(indx)=original spec */
			if (!(pblk.fnb & F_WILD))
			{
				sub.mvtype = MV_STR;
				sub.str.len = pblk.b_esl;
				sub.str.addr =  buf1;
				s2pool(&sub.str);
				ind_tmp = op_putindx(VARLSTCNT(2) TREF(fnzsearch_lv_vars), &sub);
				ind_tmp->v.mvtype = MV_STR; ind_tmp->v.str.len = 0;
				plen = (plength *)&ind_tmp->v.m[1];
				plen->p.pblk.b_esl = pblk.b_esl;
				plen->p.pblk.b_dir = pblk.b_dir;
				plen->p.pblk.b_name = pblk.b_name;
				plen->p.pblk.b_ext = pblk.b_ext;
			} else
				dir_srch(&pblk);
			for (;;)
			{
				pret.p.pint = pop_top(TREF(fnzsearch_lv_vars), ret);	/* get next element off the top */
				if (!ret->str.len)
					break;
				memcpy(buf1, ret->str.addr, ret->str.len);
				buf1[ret->str.len] = 0;
				STAT_FILE(buf1, &statbuf, stat_res);
				if (-1 == stat_res)
				{
					if (errno == ENOENT)
						continue;
					rts_error(VARLSTCNT(1) errno);
				}
				break;
			}
		}
	}
	assert((0 == ret->str.len) || (pret.p.pblk.b_esl == ret->str.len));
	TREF(lv_null_subs) = TREF(fnzsearch_nullsubs_sav);
	REVERT;
	return pret.p.pint;
}
Пример #27
0
uint4 jnl_file_extend(jnl_private_control *jpc, uint4 total_jnl_rec_size)
{
	file_control		*fc;
	boolean_t		need_extend;
	jnl_buffer_ptr_t     	jb;
	jnl_create_info 	jnl_info;
	jnl_file_header		*header;
	unsigned char		hdr_buff[REAL_JNL_HDR_LEN + MAX_IO_BLOCK_SIZE];
	uint4			new_alq;
	sgmnt_addrs		*csa;
	sgmnt_data_ptr_t	csd;
	char			prev_jnl_fn[JNL_NAME_SIZE];
	uint4			jnl_status = 0, status;
	int			new_blocks, warn_blocks, result;
	gtm_uint64_t		avail_blocks;
	uint4			aligned_tot_jrec_size, count;
	uint4			jnl_fs_block_size, read_write_size;
	DCL_THREADGBL_ACCESS;

	switch(jpc->region->dyn.addr->acc_meth)
	{
	case dba_mm:
	case dba_bg:
		csa = &FILE_INFO(jpc->region)->s_addrs;
		break;
	default:
		GTMASSERT;
	}
	csd = csa->hdr;
	assert(csa == cs_addrs && csd == cs_data);
	assert(csa->now_crit || (csd->clustered && (CCST_CLOSED == csa->nl->ccp_state)));
	assert(&FILE_INFO(jpc->region)->s_addrs == csa);
	assert(csa->jnl_state == csd->jnl_state);
	assertpro(JNL_ENABLED(csa) && (NOJNL != jpc->channel) && (!JNL_FILE_SWITCHED(jpc)));
		/* crit and messing with the journal file - how could it have vanished? */
	if (!csd->jnl_deq || (csd->jnl_alq + csd->jnl_deq > csd->autoswitchlimit))
	{
		assert(DIVIDE_ROUND_UP(total_jnl_rec_size, DISK_BLOCK_SIZE) <= csd->jnl_alq);
		assert(csd->jnl_alq == csd->autoswitchlimit);
		new_blocks = csd->jnl_alq;
	} else
		/* May cause extension of  csd->jnl_deq * n blocks where n > 0 */
		new_blocks = ROUND_UP(DIVIDE_ROUND_UP(total_jnl_rec_size, DISK_BLOCK_SIZE), csd->jnl_deq);
	jpc->status = SS_NORMAL;
	jb = jpc->jnl_buff;
	assert(0 <= new_blocks);
	DEBUG_ONLY(count = 0);
	for (need_extend = (0 != new_blocks); need_extend; )
	{
		DEBUG_ONLY(count++);
		/* usually we will do the loop just once where we do the file extension.
		 * rarely we might need to do an autoswitch instead after which again rarely
		 * 	we might need to do an extension on the new journal to fit in the transaction's	journal requirements.
		 * therefore we should do this loop a maximum of twice. hence the assert below.
		 */
		assert(count <= 2);
		need_extend = FALSE;
		if (SS_NORMAL == (status = disk_block_available(jpc->channel, &avail_blocks, TRUE)))
		{
			warn_blocks = (csd->jnl_alq + csd->jnl_deq > csd->autoswitchlimit)
					? ((csd->jnl_deq > csd->autoswitchlimit) ? csd->jnl_deq : csd->autoswitchlimit)
					: new_blocks;

			if ((warn_blocks * EXTEND_WARNING_FACTOR) > avail_blocks)
			{
				if (new_blocks > avail_blocks)
				{	/* If we cannot satisfy the request, it is an error, unless the anticipatory freeze
					 * scheme is in effect in which case, we will assume space is available even if
					 * it is not and go ahead with writes to the disk. If the writes fail with ENOSPC
					 * we will freeze the instance and wait for space to become available and keep
					 * retrying the writes. Therefore, we make the NOSPACEEXT a warning in this case.
					 */
					SETUP_THREADGBL_ACCESS;
					if (!ANTICIPATORY_FREEZE_ENABLED(csa))
					{
						send_msg(VARLSTCNT(6) ERR_NOSPACEEXT, 4,
							JNL_LEN_STR(csd), new_blocks, avail_blocks);
						new_blocks = 0;
						jpc->status = SS_NORMAL;
						break;
					} else
						send_msg(VARLSTCNT(6) MAKE_MSG_WARNING(ERR_NOSPACEEXT), 4,
							JNL_LEN_STR(csd), new_blocks, avail_blocks);
				} else
					send_msg(VARLSTCNT(5) ERR_DSKSPACEFLOW, 3, JNL_LEN_STR(csd), (avail_blocks - warn_blocks));
			}
		} else
			send_msg(VARLSTCNT(5) ERR_JNLFILEXTERR, 2, JNL_LEN_STR(csd), status);
		new_alq = jb->filesize + new_blocks;
		/* ensure current journal file size is well within autoswitchlimit --> design constraint */
		assert(csd->autoswitchlimit >= jb->filesize);
		if (csd->autoswitchlimit < (jb->filesize + (EXTEND_WARNING_FACTOR * new_blocks)))	/* close to max */
			send_msg(VARLSTCNT(5) ERR_JNLSPACELOW, 3, JNL_LEN_STR(csd), csd->autoswitchlimit - jb->filesize);
		if (csd->autoswitchlimit < new_alq)
		{	/* Reached max, need to autoswitch */
			/* Ensure new journal file can hold the entire current transaction's journal record requirements */
			assert(csd->autoswitchlimit >= MAX_REQD_JNL_FILE_SIZE(total_jnl_rec_size));
			memset(&jnl_info, 0, SIZEOF(jnl_info));
			jnl_info.prev_jnl = &prev_jnl_fn[0];
			set_jnl_info(gv_cur_region, &jnl_info);
			assert(JNL_ENABLED(csa) && (NOJNL != jpc->channel) && !(JNL_FILE_SWITCHED(jpc)));
			jnl_status = jnl_ensure_open();
			if (0 == jnl_status)
			{	/* flush the cache and jnl-buffer-contents to current journal file before
				 * switching to a new journal. Set a global variable in_jnl_file_autoswitch
				 * so jnl_write can know not to do the padding check. But because this is a global
				 * variable, we also need to make sure it is reset in case of errors during the
				 * autoswitch (or else calls to jnl_write after we are out of the autoswitch logic
				 * will continue to incorrectly not do the padding check. Hence a condition handler.
				 */
				assert(!in_jnl_file_autoswitch);
				in_jnl_file_autoswitch = TRUE;
				/* Also make sure time is not changed. This way if "jnl_write" as part of writing a
				 * journal record invokes jnl_file_extend, when the autoswitch is done and writing
				 * of the parent jnl_write resumes, we want it to continue with the same timestamp
				 * and not have to reset its time (non-trivial task) to reflect any changes since then.
				 */
				assert(!jgbl.save_dont_reset_gbl_jrec_time);
				jgbl.save_dont_reset_gbl_jrec_time = jgbl.dont_reset_gbl_jrec_time;
				jgbl.dont_reset_gbl_jrec_time = TRUE;
				/* Establish a condition handler so we reset a few global variables that have
				 * temporarily been modified in case of errors inside wcs_flu/jnl_file_close.
				 */
				ESTABLISH_RET(jnl_file_autoswitch_ch, EXIT_ERR);
				/* It is possible we still have not written a PINI record in this journal file
				 * (e.g. mupip extend saw the need to do jnl_file_extend inside jnl_write while
				 * trying to write a PINI record). Write a PINI record in that case before closing
				 * the journal file that way the EOF record will have a non-zero pini_addr.
				 */
				if (0 == jpc->pini_addr)
					jnl_put_jrt_pini(csa);
				wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH | WCSFLU_SPEEDUP_NOBEFORE);
				jnl_file_close(gv_cur_region, TRUE, TRUE);
				REVERT;
				in_jnl_file_autoswitch = FALSE;
				jgbl.dont_reset_gbl_jrec_time = jgbl.save_dont_reset_gbl_jrec_time;
				DEBUG_ONLY(jgbl.save_dont_reset_gbl_jrec_time = FALSE);
				assert((dba_mm == cs_data->acc_meth) || (csd == cs_data));
				csd = cs_data;	/* In MM, wcs_flu() can remap an extended DB, so reset csd to be sure */
			} else
			{
				if (SS_NORMAL != jpc->status)
					rts_error(VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region),
						jpc->status);
				else
					rts_error(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region));
			}
			assert(!jgbl.forw_phase_recovery || (NULL != jgbl.mur_pini_addr_reset_fnptr));
			assert(jgbl.forw_phase_recovery || (NULL == jgbl.mur_pini_addr_reset_fnptr));
			if (NULL != jgbl.mur_pini_addr_reset_fnptr)
				(*jgbl.mur_pini_addr_reset_fnptr)(csa);
			assert(!jnl_info.no_rename);
			assert(!jnl_info.no_prev_link);
			if (EXIT_NRM == cre_jnl_file(&jnl_info))
			{
				assert(0 == memcmp(csd->jnl_file_name, jnl_info.jnl, jnl_info.jnl_len));
				assert(csd->jnl_file_name[jnl_info.jnl_len] == '\0');
				assert(csd->jnl_file_len == jnl_info.jnl_len);
				assert(csd->jnl_buffer_size == jnl_info.buffer);
				assert(csd->jnl_alq == jnl_info.alloc);
				assert(csd->jnl_deq == jnl_info.extend);
				assert(csd->jnl_before_image == jnl_info.before_images);
				csd->jnl_checksum = jnl_info.checksum;
				csd->jnl_eovtn = csd->trans_hist.curr_tn;
				send_msg(VARLSTCNT(4) ERR_NEWJNLFILECREAT, 2, JNL_LEN_STR(csd));
				fc = gv_cur_region->dyn.addr->file_cntl;
				fc->op = FC_WRITE;
				fc->op_buff = (sm_uc_ptr_t)csd;
				fc->op_len = SGMNT_HDR_LEN;
				fc->op_pos = 1;
				status = dbfilop(fc);
				if (SS_NORMAL != status)
					send_msg(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), status);
				assert(JNL_ENABLED(csa));
				/* call jnl_ensure_open instead of jnl_file_open to make sure jpc->pini_addr is set to 0 */
				jnl_status = jnl_ensure_open();	/* sets jpc->status */
				if (0 != jnl_status)
				{
					if (jpc->status)
						rts_error(VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region),
							jpc->status);
					else
						rts_error(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region));
				}
				assert(jb->filesize == csd->jnl_alq);
				if (csd->jnl_alq + csd->jnl_deq <= csd->autoswitchlimit)
				{
					aligned_tot_jrec_size = ALIGNED_ROUND_UP(MAX_REQD_JNL_FILE_SIZE(total_jnl_rec_size),
											csd->jnl_alq, csd->jnl_deq);
					if (aligned_tot_jrec_size > csd->jnl_alq)
					{	/* need to extend more than initial allocation in the new journal file
						 * to accommodate the current transaction.
						 */
						new_blocks = aligned_tot_jrec_size - csd->jnl_alq;
						assert(new_blocks);
						assert(0 == new_blocks % csd->jnl_deq);
						need_extend = TRUE;
					}
				}
			} else
			{
				send_msg(VARLSTCNT(4) ERR_JNLNOCREATE, 2, JNL_LEN_STR(csd));
				jpc->status = ERR_JNLNOCREATE;
				new_blocks = -1;
			}
		} else
		{
			assert(!need_extend);	/* ensure we won't go through the for loop again */
			/* Virtually extend currently used journal file */
			jnl_fs_block_size = jb->fs_block_size;
			header = (jnl_file_header *)(ROUND_UP2((uintszofptr_t)hdr_buff, jnl_fs_block_size));
			read_write_size = ROUND_UP2(REAL_JNL_HDR_LEN, jnl_fs_block_size);
			assert((unsigned char *)header + read_write_size <= ARRAYTOP(hdr_buff));
			DO_FILE_READ(jpc->channel, 0, header, read_write_size, jpc->status, jpc->status2);
			if (SS_NORMAL != jpc->status)
			{
				assert(FALSE);
				rts_error(VARLSTCNT(5) ERR_JNLRDERR, 2, JNL_LEN_STR(csd), jpc->status);
			}
			assert((header->virtual_size + new_blocks) == new_alq);
			jb->filesize = new_alq;	/* Actually this is virtual file size blocks */
			header->virtual_size = new_alq;
			JNL_DO_FILE_WRITE(csa, csd->jnl_file_name, jpc->channel, 0,
					header, read_write_size, jpc->status, jpc->status2);
			if (SS_NORMAL != jpc->status)
			{
				assert(FALSE);
				rts_error(VARLSTCNT(5) ERR_JNLWRERR, 2, JNL_LEN_STR(csd), jpc->status);
			}
		}
		if (0 >= new_blocks)
			break;
	}
	if (0 < new_blocks)
	{
		INCR_GVSTATS_COUNTER(csa, csa->nl, n_jnl_extends, 1);
		return EXIT_NRM;
	}
	jpc->status = ERR_JNLREADEOF;
	jnl_file_lost(jpc, ERR_JNLEXTEND);
       	return EXIT_ERR;
}
Пример #28
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			semval, status, save_errno, nattch;
	char			*instfilename, pool_type;
	sm_uc_ptr_t		start_addr;
	struct shmid_ds		shm_buf;
	unix_db_info		*udi;
	sgmnt_addrs		*csa;
	boolean_t		anticipatory_freeze_available, force_attach;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	assert(INVALID_SHMID != shm_id);
	instfilename = replpool_id->instfilename;
	pool_type = replpool_id->pool_type;
	assert((JNLPOOL_SEGMENT == pool_type) || (RECVPOOL_SEGMENT == pool_type));
	anticipatory_freeze_available = ANTICIPATORY_FREEZE_AVAILABLE;
	force_attach = (jgbl.onlnrlbk || (!jgbl.mur_rollback && !argumentless_rundown && anticipatory_freeze_available));
	if (-1 == shmctl(shm_id, IPC_STAT, &shm_buf))
	{
		save_errno = errno;
		ISSUE_REPLPOOLINST_AND_RETURN(save_errno, shm_id, instfilename, "shmctl()");
	}
	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_AND_RETURN(save_errno, shm_id, instfilename, "shmat()");
	}
	ESTABLISH_RET(mu_rndwn_replpool_ch, -1);
	/* 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_AND_RETURN(start_addr, shm_id, instfilename);
	}
	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_AND_RETURN(start_addr, shm_id, instfilename);
	}
	/* Assert that if we haven't yet attached to the journal pool yet, we have the corresponding global vars set to NULL */
	assert((JNLPOOL_SEGMENT != pool_type) || ((NULL == jnlpool.jnlpool_ctl) && (NULL == jnlpool_ctl)));
	if (JNLPOOL_SEGMENT == pool_type)
	{	/* Initialize variables to simulate a "jnlpool_init". This is required by "repl_inst_flush_jnlpool" called below */
		jnlpool_ctl = 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 = (mutex_struct_ptr_t)((sm_uc_ptr_t)jnlpool.jnlpool_ctl + JNLPOOL_CTL_SIZE);
		csa->nl = (node_local_ptr_t)((sm_uc_ptr_t)csa->critical + 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;
			repl_inst_flush_jnlpool(FALSE, !anticipatory_freeze_available);
			assert(!jnlpool.repl_inst_filehdr->crash || anticipatory_freeze_available);
			/* 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 (!anticipatory_freeze_available)
			{ 	/* 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.jnlpool_ctl = NULL;
				jnlpool_ctl = NULL;
				jnlpool.gtmsrc_lcl_array = NULL;
				jnlpool.gtmsource_local_array = NULL;
				jnlpool.jnldata_base = NULL;
				jnlpool.repl_inst_filehdr = NULL;
			}
		} /* else we are ONLINE ROLLBACK. repl_inst_flush_jnlpool will be done later after gvcst_init in mur_open_files */
	}
	if ((0 == nattch) && (!anticipatory_freeze_available || (RECVPOOL_SEGMENT == pool_type)))
	{
		if (-1 == shmdt((caddr_t)start_addr))
		{
			save_errno = errno;
			ISSUE_REPLPOOLINST_AND_RETURN(save_errno, shm_id, instfilename, "shmdt()");
		}
		if (0 != shm_rmid(shm_id))
		{
			save_errno = errno;
			ISSUE_REPLPOOLINST_AND_RETURN(save_errno, shm_id, instfilename, "shm_rmid()");
		}
		if (JNLPOOL_SEGMENT == pool_type)
		{
			repl_inst_filehdr->jnlpool_shmid = INVALID_SHMID;
			repl_inst_filehdr->jnlpool_shmid_ctime = 0;
			assert((NULL == jnlpool.jnlpool_ctl) && (NULL == jnlpool_ctl));
			*ipc_rmvd = TRUE;
		} else
		{
			repl_inst_filehdr->recvpool_shmid = INVALID_SHMID;
			repl_inst_filehdr->recvpool_shmid_ctime = 0;
			*ipc_rmvd = TRUE;
		}
	} else
	{	/* Else 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. Do not remove and/or reset the fields in the file header
	   	 */
		assert((JNLPOOL_SEGMENT != pool_type) || ((NULL != jnlpool.jnlpool_ctl) && (NULL != jnlpool_ctl)));
		if (JNLPOOL_SEGMENT == pool_type)
			*ipc_rmvd = FALSE;
		if (RECVPOOL_SEGMENT == pool_type)
			*ipc_rmvd = FALSE;
	}
	REVERT;
	return 0;
}
Пример #29
0
int rc_prc_lock(rc_q_hdr *qhdr)
{
	rc_req_lock	*req;
	rc_sbkey	*sbk;
	short		i, len, pid_len;
	mval		lock, ext;
	mlk_pvtblk	**prior, *mp, *x;
	rc_lknam	*fl;
	unsigned char	action;
	bool		blocked;
	char		key_buff[KEY_BUFF_SIZE], *lkname;
	unsigned char	buff[12], *cp;
	short		subcnt;
	int		in_pid, locks_done, temp;

	ESTABLISH_RET(rc_dbms_ch, RC_SUCCESS);
	/*  Clean up dead locks in private list */
	for (prior = &mlk_pvt_root; *prior; )
	{	if (!(*prior)->granted || !(*prior)->nodptr || (*prior)->nodptr->owner != omi_pid)
			mlk_pvtblk_delete(prior);
		else
		{	(*prior)->trans = 0;
			prior = &(*prior)->next;
		}
	}

	req = (rc_req_lock *)qhdr;
	in_pid = ((qhdr->r.pid1.value << 16) | qhdr->r.pid2.value);
	cp = i2asc(buff,in_pid);
	pid_len = cp - buff;
	lks_this_cmd = 0;
	if (req->hdr.r.fmd.value & RC_MODE_CLEARLOCK)
	{	/*  Loop through all the locks, unlocking ones that belong to this client */
		for (prior = &mlk_pvt_root; *prior; )
		{	if ((*prior)->nodptr->auxowner == rc_auxown
					&& pid_len == (*prior)->value[(*prior)->total_length]
					&& !memcmp(&(*prior)->value[(*prior)->total_length+1],
					buff,pid_len))
 			{	mlk_unlock(*prior);
				mlk_pvtblk_delete(prior);
			}else
				prior = &(*prior)->next;
		}
		action = LOCKED;
	} else if (req->hdr.r.fmd.value & RC_MODE_DECRLOCK)
	{	sbk = &req->dlocks[0].sb_key;
		fl = req->dlocks;

		/*  Loop through all requested locks */
		for ( i = 0; i < req->nlocks.value; i++)
		{
			if ((char *) fl - (char *) req + sbk->len.value + 1 > req->hdr.r.len.value)
			{	/* we are beyond the end of this packet and still have
				 * lock requests to process.  Bad packet.
				 */
				qhdr->a.erc.value = RC_BADXBUF;
				REVERT;
#ifdef DEBUG
				gtcm_cpktdmp((char *)qhdr,qhdr->a.len.value,"Bad Rq: Invalid nLockNames value.");
#endif
				return -1;
			}

			if ((temp = rc_frmt_lck(key_buff, KEY_BUFF_SIZE, (unsigned char *)sbk->key, sbk->len.value, &subcnt)) < 0)
			{
			        temp = -temp;
			        qhdr->a.erc.value = temp;
				REVERT;

#ifdef DEBUG
				if (temp == RC_KEYTOOLONG)
				       gtcm_cpktdmp((char *)qhdr,qhdr->a.len.value,"RC_KEYTOOLONG.");
				else
				       gtcm_cpktdmp((char *)qhdr,qhdr->a.len.value,"Invalid lock request.");
#endif
				return -1;
			}
			temp += subcnt;

			/*  Loop through all owned locks looking for requested one */
			for (prior = &mlk_pvt_root; *prior; )
			{	if ((*prior)->nodptr->auxowner == rc_auxown
						&& temp == (*prior)->total_length
						&& !memcmp(&(*prior)->value[0],key_buff,temp)
						&& pid_len == (*prior)->value[(*prior)->total_length]
						&& !memcmp(&(*prior)->value[(*prior)->total_length+1],
						buff,pid_len))
	 			{	(*prior)->level -= 1;
					if (!(*prior)->level)
					{	mlk_unlock(*prior);
						mlk_pvtblk_delete(prior);
					}
				}else
					prior = &(*prior)->next;
			}
		fl = (rc_lknam*)((char *)fl + sbk->len.value - 1 + SIZEOF(rc_lknam));
		sbk = &fl->sb_key;

		}
		qhdr->a.erc.value = RC_SUCCESS;
		REVERT;
		return 0;
	} else
		action = INCREMENTAL;
	lock.mvtype = ext.mvtype = MV_STR;
	lkname = (char*)req->dlocks[0].sb_key.key;
	sbk = &req->dlocks[0].sb_key;
	fl = req->dlocks;
	for ( i = 0; i < req->nlocks.value; i++)
	{
		if ((char *) fl - (char *) req + sbk->len.value + 1 > req->hdr.r.len.value)
		{	/* we are beyond the end of this packet and still have
			 * lock requests to process.  Bad packet.
			 */
			qhdr->a.erc.value = RC_BADXBUF;
			REVERT;
#ifdef DEBUG
			gtcm_cpktdmp((char *)qhdr,qhdr->a.len.value,"Bad Rq: Invalid nLockNames value.");
#endif
			return -1;
		}

		if ((qhdr->a.erc.value = rc_fnd_file(&fl->xdsid)) != RC_SUCCESS)
		    {
			REVERT;
#ifdef DEBUG
	gtcm_cpktdmp((char *)qhdr,qhdr->a.len.value,"rc_fnd_file failed.");
#endif
			return -1;
		    }

		if ((temp = rc_frmt_lck(key_buff, KEY_BUFF_SIZE, (unsigned char *)sbk->key, sbk->len.value, &subcnt)) < 0)
		{
			temp = -temp;
			qhdr->a.erc.value = temp;
			REVERT;
#ifdef DEBUG
			if (temp == RC_KEYTOOLONG)
				gtcm_cpktdmp((char *)qhdr,qhdr->a.len.value,"RC_KEYTOOLONG.");
			else
				gtcm_cpktdmp((char *)qhdr,qhdr->a.len.value,"Invalid lock request.");
#endif
			return -1;
		}
		temp += subcnt;
		mp = (mlk_pvtblk*)malloc(SIZEOF(mlk_pvtblk) + temp + pid_len + 1);
		memset(mp, 0, SIZEOF(mlk_pvtblk) - 1);
		mp->subscript_cnt = subcnt;
		mp->total_length = temp;
		memcpy(mp->value, key_buff, mp->total_length);
		mp->region = gv_cur_region;
		mp->ctlptr = (mlk_ctldata*)cs_addrs->lock_addrs[0];
		mp->value[mp->total_length] = pid_len;
		memcpy(&mp->value[mp->total_length + 1], buff, pid_len);
		if (!mlk_pvtblk_insert(mp))
		{	if (!(mp->value[mp->total_length] == mlk_pvt_root->value[mlk_pvt_root->total_length]
				&& !memcmp(&mp->value[mp->total_length + 1], &mlk_pvt_root->value[mp->total_length + 1],
				mp->total_length + 1)))
			{	free(mp);	/* Server owns lock on behalf of a different agent/client pair */
				REVERT;
				qhdr->a.erc.value = RC_LOCKCONFLICT;
				return 0;	/* Return lock not granted */
			}
			free(mp);
		} else if (mp != mlk_pvt_root)
		{	REVERT;
			qhdr->a.erc.value = RC_GLOBERRUNSPEC;
#ifdef DEBUG
	gtcm_cpktdmp((char *)qhdr,qhdr->a.len.value,"RC_GLOBERRUNSPEC.");
#endif
			return -1;/* error */

		}
		fl = (rc_lknam*)((char *)fl + sbk->len.value - 1 + SIZEOF(rc_lknam));
		sbk = &fl->sb_key;
	}
	blocked = FALSE;
	lckclr();
	for (x = mlk_pvt_root, locks_done = 0; locks_done < lks_this_cmd; x = x->next)
	{
	        locks_done++;
		/* If lock is obtained */
		if (!mlk_lock(x,rc_auxown,TRUE))
		{
			x->granted = TRUE;
			if (action == INCREMENTAL)
				x->level += x->translev;
			else
				x->level = 1;
		} else
		{
			blocked = TRUE;
			break;
		}
	}
	if (blocked)	/* need to back out all locks */
	{
		for (x = mlk_pvt_root, i = 0;
			i < locks_done ; x = x->next, i++)
		{
			mlk_bckout(x, action);
		}
		qhdr->a.erc.value = RC_LOCKCONFLICT;
	} else
		qhdr->a.erc.value = RC_SUCCESS;
	REVERT;
	return 0;
}