/* 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; }
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 */ }
/* 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; }
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; } } }
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); }
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; }
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; }
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;
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); }
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; }
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; }
/* * 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 */ }
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); }
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; } } }
/* * 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)); }
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 */
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); }
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; }
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; }
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); }
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, >msource_log_fd, gtmsource_options.log_file); assert(SS_NORMAL == log_init_status); repl_log_fd2fp(>msource_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(>msource_sock_fd); if (gtmsource_filter & EXTERNAL_FILTER) repl_stop_filter(); } while (TRUE);
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; }
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; }
/* 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; }
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; }
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; }
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; }
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; }