STATICFNDEF void times_usec(ext_tms *curr) { int res; struct rusage usage; struct timespec elp_time; res = getrusage(RUSAGE_SELF, &usage); if (res == -1) MPROF_RTS_ERROR((VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("getrusage"), CALLFROM, errno)); curr->tms_utime = (usage.ru_utime.tv_sec * (gtm_uint64_t)1000000) + usage.ru_utime.tv_usec; curr->tms_stime = (usage.ru_stime.tv_sec * (gtm_uint64_t)1000000) + usage.ru_stime.tv_usec; /* also start recording the elapsed time */ while (TRUE) { res = clock_gettime(use_realtime_flag ? CLOCK_REALTIME : CLOCK_MONOTONIC, &elp_time); if (res == -1) { if ((EINVAL == errno) && !use_realtime_flag) { use_realtime_flag = TRUE; continue; } else MPROF_RTS_ERROR((VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("clock_gettime"), CALLFROM, errno)); } break; } curr->tms_etime = (elp_time.tv_sec * (gtm_uint64_t)1000000) + (elp_time.tv_nsec / 1000); return; }
STATICFNDEF void times_usec(ext_tms *curr) { int res; struct rusage usage; struct timespec elp_time; res = getrusage(RUSAGE_SELF, &usage); if (-1 == res) MPROF_RTS_ERROR((CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("getrusage"), CALLFROM, errno)); # ifdef __osf__ /* On Tru64 getrusage sometimes fails to increment the seconds value when the microseconds wrap around at 1M. If we detect * this, we make a second call to getrusage if so. A more complete check would be to also verify whether the new seconds * value is less than the previous one, but we anyway have an assert in UPDATE_TIME that would catch that, and our testing * on Tru64 has not shown that type of faulty behavior. */ if (((usage.ru_utime.tv_sec == last_usage.ru_utime.tv_sec) && (usage.ru_utime.tv_usec < last_usage.ru_utime.tv_usec)) || ((usage.ru_stime.tv_sec == last_usage.ru_stime.tv_sec) && (usage.ru_stime.tv_usec < last_usage.ru_stime.tv_usec))) { DEBUG_ONLY(last_usage = usage); res = getrusage(RUSAGE_SELF, &usage); if (-1 == res) MPROF_RTS_ERROR((CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("getrusage"), CALLFROM, errno)); /* In debug also ensure that a subsequent call to getrusage restored the seconds value. */ assert((usage.ru_utime.tv_sec > last_usage.ru_utime.tv_sec) || (usage.ru_stime.tv_sec > last_usage.ru_stime.tv_sec)); } last_usage = usage; # endif curr->tms_utime = (usage.ru_utime.tv_sec * (gtm_uint64_t)1000000) + usage.ru_utime.tv_usec; curr->tms_stime = (usage.ru_stime.tv_sec * (gtm_uint64_t)1000000) + usage.ru_stime.tv_usec; /* Also start recording the elapsed time. */ while (TRUE) { res = clock_gettime(use_realtime_flag ? CLOCK_REALTIME : CLOCK_MONOTONIC, &elp_time); if (res == -1) { if ((EINVAL == errno) && !use_realtime_flag) { use_realtime_flag = TRUE; continue; } else MPROF_RTS_ERROR((CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("clock_gettime"), CALLFROM, errno)); } break; } curr->tms_etime = (elp_time.tv_sec * (gtm_uint64_t)1000000) + (elp_time.tv_nsec / 1000); return; }
void gtcm_open_cmerrlog(void) { int len; mstr lfn1, lfn2; char lfn_path[MAX_TRANS_NAME_LEN + 1]; char new_lfn_path[MAX_TRANS_NAME_LEN + 1]; int new_len; uint4 ustatus; int4 rval; FILE *new_file; error_def(ERR_TEXT); if (0 != (len = STRLEN(gtcm_gnp_server_log))) { lfn1.addr = gtcm_gnp_server_log; lfn1.len = len; } else { lfn1.addr = GTCM_GNP_CMERR_FN; lfn1.len = sizeof(GTCM_GNP_CMERR_FN) - 1; } rval = TRANS_LOG_NAME(&lfn1, &lfn2, lfn_path, sizeof(lfn_path), do_sendmsg_on_log2long); if (rval == SS_NORMAL || rval == SS_NOLOGNAM) { lfn_path[lfn2.len] = 0; rename_file_if_exists(lfn_path, lfn2.len, new_lfn_path, &new_len, &ustatus); new_file = Fopen(lfn_path, "a"); if (NULL != new_file) { gtcm_errfile = TRUE; if (gtcm_errfs) fclose(gtcm_errfs); gtcm_errfs = new_file; if (dup2(fileno(gtcm_errfs), 1) < 0) { rts_error(VARLSTCNT(5) ERR_TEXT, 2, LEN_AND_LIT("Error on dup2 of stdout"), errno); } if (dup2(fileno(gtcm_errfs), 2) < 0) { rts_error(VARLSTCNT(5) ERR_TEXT, 2, LEN_AND_LIT("Error on dup2 of stderr"), errno); } } else fprintf(stderr, "Unable to open %s : %s\n", lfn_path, STRERROR(errno)); } else fprintf(stderr, "Unable to resolve %s : return value = %d\n", GTCM_GNP_CMERR_FN, rval); gtcm_firsterr = FALSE; }
/* returns FALSE if gv_currkey is undefined in the server end and undef_inhibit is turned OFF */ void gvcmx_increment(mval *increment, mval *result) { unsigned char buff[MAX_ZWR_KEY_SZ], *end; mval tmpmval; error_def(ERR_UNIMPLOP); error_def(ERR_TEXT); error_def(ERR_GVIS); if (!((link_info *)gv_cur_region->dyn.addr->cm_blk->usr)->server_supports_dollar_incr) { assert(dba_cm == gv_cur_region->dyn.addr->acc_meth); /* we should've covered all other access methods elsewhere */ end = format_targ_key(buff, MAX_ZWR_KEY_SZ, gv_currkey, TRUE); rts_error(VARLSTCNT(14) ERR_UNIMPLOP, 0, ERR_TEXT, 2, LEN_AND_LIT("GT.CM server does not support $INCREMENT operation"), ERR_GVIS, 2, end - buff, buff, ERR_TEXT, 2, REG_LEN_STR(gv_cur_region)); } /* gvcmz_doop() currently accepts only one argument. * It serves as an input argument for SET. * It serves as an output argument for GET etc. * $INCR is unique in that it needs to pass the increment as input and expects the post-increment as output. * * In order to accomplish this without changing the gvcmz_doop() interface, we overload the one argument to * serve two purposes. It will be an input argument until the send of the message to the server and will * then serve as an output argument after the response from the server. ("result" is used for this purpose) * i.e. * to serve as increment for client --> server message * to serve as post-increment value for server --> client message */ assert(MV_IS_NUMERIC(increment)); /* op_gvincr would have forced it to be a NUMERIC */ MV_FORCE_STR(increment); /* convert it to a string before sending it to gvcmz_doop */ *result = *increment; gvcmz_doop(CMMS_Q_INCREMENT, CMMS_R_INCREMENT, result); }
void dollar_system_init(struct startup_vector *svec) { uint4 status; mstr val, tn; char buf[MAX_TRANS_NAME_LEN]; error_def(ERR_TRNLOGFAIL); dollar_system.mvtype = MV_STR; dollar_system.str.addr = (char *)stringpool.free; dollar_system.str.len = STR_LIT_LEN("47,"); memcpy(stringpool.free, "47,", dollar_system.str.len); stringpool.free += dollar_system.str.len; val.addr = SYSID; val.len = STR_LIT_LEN(SYSID); if (SS_NORMAL == (status = trans_log_name(&val, &tn, buf))) { dollar_system.str.len += tn.len; memcpy(stringpool.free, tn.addr, tn.len); stringpool.free += tn.len; } else if (SS_NOLOGNAM == status) { dollar_system.str.len += svec->sysid_ptr->len; memcpy(stringpool.free, svec->sysid_ptr->addr, svec->sysid_ptr->len); stringpool.free += dollar_system.str.len; } else rts_error(VARLSTCNT(5) ERR_TRNLOGFAIL, 2, LEN_AND_LIT(SYSID), status); assert(stringpool.free < stringpool.top); /* it's process initialization after all */ return; }
/* Lookup an external function. Return function address if success, NULL otherwise. * package_handle - DLL handle returned by fgn_getpak * entry_name - symbol name to be looked up * msgtype - message severity of the errors reported if any. * Note: If msgtype is SUCCESS, errors are not issued. It is useful if the callers are not * interested in message report and not willing to have condition handler overhead (eg. zro_search). */ fgnfnc fgn_getrtn(void_ptr_t package_handle, mstr *entry_name, int msgtype) { void_ptr_t sym_addr; char_ptr_t dummy_err_str; void *short_sym_addr; char err_str[MAX_ERRSTR_LEN]; /* needed as util_out_print doesn't handle 64bit pointers */ error_def(ERR_DLLNORTN); error_def(ERR_TEXT); if (!(sym_addr = dlsym(package_handle, entry_name->addr))) { if (SUCCESS != msgtype) { assert(!(msgtype & ~SEV_MSK)); COPY_DLLERR_MSG; rts_error(VARLSTCNT(8) MAKE_MSG_TYPE(ERR_DLLNORTN, msgtype), 2, LEN_AND_STR(entry_name->addr), ERR_TEXT, 2, LEN_AND_STR(err_str)); } } else { /* Tru64 - dlsym() is bound to return short pointer because of ld -taso flag used for GT.M */ #ifdef __osf__ short_sym_addr = sym_addr; if (short_sym_addr != sym_addr) { sym_addr = NULL; /* always report an error irrespective of msgtype - since this code should never * have executed and/or the DLL might need to be rebuilt with 32-bit options */ rts_error(VARLSTCNT(8) ERR_DLLNORTN, 2, LEN_AND_STR(entry_name->addr), ERR_TEXT, 2, LEN_AND_LIT("Symbol is loaded above the lower 31-bit address space")); } #endif } return (fgnfnc)sym_addr; }
int gtmrecv_statslog(void) { #ifdef VMS rts_error(VARLSTCNT(6) ERR_UNIMPLOP, 0, ERR_TEXT, 2, LEN_AND_LIT("Statistics logging not supported on VMS")); #endif /* Grab the recvpool option write lock */ if (0 > grab_sem(RECV, RECV_SERV_OPTIONS_SEM)) { util_out_print("Error grabbing recvpool option write lock. Could not initiate stats log", TRUE); return (ABNORMAL_SHUTDOWN); } if (gtmrecv_options.statslog == recvpool.gtmrecv_local->statslog) { util_out_print("STATSLOG is already !AD. Not initiating change in stats log", TRUE, gtmrecv_options.statslog ? strlen("ON") : strlen("OFF"), gtmrecv_options.statslog ? "ON" : "OFF"); rel_sem_immediate(RECV, RECV_SERV_OPTIONS_SEM); return (ABNORMAL_SHUTDOWN); } if (!gtmrecv_options.statslog) { recvpool.gtmrecv_local->statslog = FALSE; util_out_print("STATSLOG turned OFF", TRUE); rel_sem_immediate(RECV, RECV_SERV_OPTIONS_SEM); return (NORMAL_SHUTDOWN); } recvpool.gtmrecv_local->statslog = TRUE; util_out_print("Stats log turned on", TRUE); rel_sem_immediate(RECV, RECV_SERV_OPTIONS_SEM); return (NORMAL_SHUTDOWN); }
STATICFNDEF int4 update_trigger_name_value(char *trig_name, int trig_name_len, int new_trig_index) { int len; char name_and_index[MAX_MIDENT_LEN + 1 + MAX_DIGITS_IN_INT]; int num_len; char *ptr; int4 result; mval trig_gbl; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert(!gv_cur_region->read_only); /* caller should have already checked this */ assert(cs_addrs->hasht_tree == gv_target); /* should have been set up by caller */ assert(gv_target->root); /* should have been ensured by caller */ /* $get(^#t("#TNAME",^#t(GVN,index,"#TRIGNAME"))) */ BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trig_name, trig_name_len - 1); if (!gvcst_get(&trig_gbl)) { /* There has to be a #TNAME entry */ if (CDB_STAGNATE > t_tries) t_retry(cdb_sc_triggermod); assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TRIGNAMBAD, 4, LEN_AND_LIT("\"#TNAME\""), trig_name_len - 1, trig_name); } ptr = trig_gbl.str.addr; len = MIN(trig_gbl.str.len, MAX_MIDENT_LEN); STRNLEN(ptr, len, len); ptr += len; if ((trig_gbl.str.len == len) || ('\0' != *ptr)) { if (CDB_STAGNATE > t_tries) t_retry(cdb_sc_triggermod); assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TRIGNAMBAD, 4, LEN_AND_LIT("\"#TNAME\""), trig_name_len - 1, trig_name); } memcpy(name_and_index, trig_gbl.str.addr, ++len); /* inline increment intended */ ptr = name_and_index + len; num_len = 0; I2A(ptr, num_len, new_trig_index); len += num_len; /* set ^#t("#TNAME",<trigname>)=gblname_$C(0)_new_trig_index */ SET_TRIGGER_GLOBAL_SUB_SUB_STR(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trig_name, trig_name_len - 1, name_and_index, len, result); return result; }
void gvcmy_open(gd_region *reg, parse_blk *nb) { error_def(ERR_UNIMPLOP); error_def(ERR_TEXT); rts_error(VARLSTCNT(6) ERR_UNIMPLOP, 0, ERR_TEXT, 2, LEN_AND_LIT("This utility does not support remote database operations")); }
/* mupfndfil.c * Description: * For a region find if the corresponding database is present. * Arguments: * reg: Region's pointer * filestr: Sent as allocated memory, if returned full path is needed in this mstr * Returns: TRUE if region's database file is found * FALSE, otherwise * Side Effects: * reg->dyn.addr->fname_len and reg->dyn.addr->fname are updated */ boolean_t mupfndfil(gd_region *reg, mstr *filestr) { char filename[MAX_FN_LEN]; mstr file, def, ret, *retptr; uint4 ustatus; switch(reg->dyn.addr->acc_meth) { case dba_mm: case dba_bg: break; # ifdef VMS case dba_usr: gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_NOUSERDB, 4, LEN_AND_LIT("specified function"), REG_LEN_STR(reg)); return FALSE; /* This is currently a VMS only possibility and has no corresponding test case */ # endif default: util_out_print("REGION !AD has an unrecognized access method.", TRUE, REG_LEN_STR(reg)); return FALSE; } file.addr = (char *)reg->dyn.addr->fname; file.len = reg->dyn.addr->fname_len; #if defined(UNIX) file.addr[file.len] = 0; if (is_raw_dev(file.addr)) { def.addr = DEF_NODBEXT; def.len = SIZEOF(DEF_NODBEXT) - 1; } else { def.addr = DEF_DBEXT; /* UNIX need to pass "*.dat" but reg->dyn.addr->defext has "DAT" */ def.len = SIZEOF(DEF_DBEXT) - 1; } #elif defined(VMS) def.addr = (char *)reg->dyn.addr->defext; def.len = SIZEOF(reg->dyn.addr->defext); #endif if (NULL == filestr) { ret.len = SIZEOF(filename); ret.addr = filename; retptr = &ret; } else retptr = filestr; if (FILE_PRESENT != gtm_file_stat(&file, &def, retptr, FALSE, &ustatus)) { if (!jgbl.mupip_journal) { /* Do not print error messages in case of call from mur_open_files(). * Currently we use "jgbl.mupip_journal" to identify a call from mupip_recover code */ util_out_print("REGION !AD's file !AD cannot be found.", TRUE, REG_LEN_STR(reg), LEN_AND_STR(file.addr)); gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ustatus); } return FALSE; } reg->dyn.addr->fname_len = retptr->len; memcpy(reg->dyn.addr->fname, retptr->addr, retptr->len + 1); return TRUE; }
STATICFNDEF void times_usec(struct tms *curr) { int res; struct rusage usage; res = getrusage(RUSAGE_SELF, &usage); if (res == -1) rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("getrusage"), CALLFROM, errno); curr->tms_utime = (usage.ru_utime.tv_sec * 1000000) + usage.ru_utime.tv_usec; curr->tms_stime = (usage.ru_stime.tv_sec * 1000000) + usage.ru_stime.tv_usec; return; }
STATICFNDEF int4 update_trigger_name_value(int trigvn_len, char *trig_name, int trig_name_len, int new_trig_index) { sgmnt_addrs *csa; mname_entry gvent; gv_namehead *hasht_tree; int len; char name_and_index[MAX_MIDENT_LEN + 1 + MAX_DIGITS_IN_INT]; char new_trig_name[MAX_TRIGNAME_LEN + 1]; int num_len; char *ptr; int4 result; char save_currkey[SIZEOF(gv_key) + DBKEYSIZE(MAX_KEY_SZ)]; gv_key *save_gv_currkey; gd_region *save_gv_cur_region; gv_namehead *save_gv_target; sgm_info *save_sgm_info_ptr; mval trig_gbl; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if (MAX_AUTO_TRIGNAME_LEN < trigvn_len) return PUT_SUCCESS; SAVE_TRIGGER_REGION_INFO; SWITCH_TO_DEFAULT_REGION; if (gv_cur_region->read_only) rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(gv_cur_region)); assert(0 != gv_target->root); /* $get(^#t("#TNAME",^#t(GVN,index,"#TRIGNAME")) */ BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trig_name, trig_name_len - 1); if (!gvcst_get(&trig_gbl)) { /* There has to be a #TNAME entry */ if (CDB_STAGNATE > t_tries) t_retry(cdb_sc_triggermod); else { assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TRIGNAMBAD, 4, LEN_AND_LIT("\"#TNAME\""), trig_name_len - 1, trig_name); } } len = STRLEN(trig_gbl.str.addr) + 1; assert(MAX_MIDENT_LEN >= len); memcpy(name_and_index, trig_gbl.str.addr, len); ptr = name_and_index + len; num_len = 0; I2A(ptr, num_len, new_trig_index); len += num_len; /* set ^#t(GVN,index,"#TRIGNAME")=trig_name $C(0) new_trig_index */ SET_TRIGGER_GLOBAL_SUB_SUB_STR(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trig_name, trig_name_len - 1, name_and_index, len, result); RESTORE_TRIGGER_REGION_INFO; return result; }
STATICFNDEF void get_cputime (struct tms *curr) { int4 cpu_time_used; int status; int jpi_code = JPI$_CPUTIM; if ((status = lib$getjpi(&jpi_code, &process_id, 0, &cpu_time_used, 0, 0)) != SS$_NORMAL) rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("LIB$GETJPI"), CALLFROM, status); curr->tms_utime = cpu_time_used; curr->tms_stime = 0; return; }
STATICFNDEF void get_cputime (ext_tms *curr) { int4 cpu_time_used; int status; int jpi_code = JPI$_CPUTIM; if ((status = lib$getjpi(&jpi_code, &process_id, 0, &cpu_time_used, 0, 0)) != SS$_NORMAL) MPROF_RTS_ERROR((CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("LIB$GETJPI"), CALLFROM, status)); curr->tms_utime = cpu_time_used; curr->tms_stime = 0; return; }
STATICFNDEF void child_times_usec(void) { int res; struct rusage usage; res = getrusage(RUSAGE_CHILDREN, &usage); if (res == -1) MPROF_RTS_ERROR((CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("getrusage"), CALLFROM, errno)); child_user = (usage.ru_utime.tv_sec * (gtm_uint64_t)1000000) + usage.ru_utime.tv_usec; child_system = (usage.ru_stime.tv_sec * (gtm_uint64_t)1000000) + usage.ru_stime.tv_usec; return; }
/* Returns 0 (SS_NORMAL) on success. Non-zero on failure */ uint4 mur_jctl_from_next_gen(reg_ctl_list *rctl) { jnl_ctl_list *jctl, *temp_jctl; uint4 status; status = gtm_pthread_init_key(rctl->gd); if (0 != status) return status; if (!rctl->jfh_recov_interrupted) return SS_NORMAL; assert(rctl->jctl_apply_pblk == rctl->jctl_head); jctl = rctl->jctl_apply_pblk; /* journal file that has the turn around point of interrupted recovery */ assert(rctl->jctl == jctl); assert(NULL != rctl->jctl_alt_head); /* should have been set in mur_apply_pblk */ assert(NULL != jctl->jfh); assert(!jctl->jfh->recover_interrupted); for ( ; NULL != jctl->next_gen; jctl = jctl->next_gen) assert(!jctl->next_gen->jfh->recover_interrupted); while (0 != jctl->jfh->next_jnl_file_name_length) { /* create the linked list of journal files created by GT.M originally */ if (multi_thread_in_use) { /* exit thread if master process got signal (e.g. SIGTERM) to request exit */ PTHREAD_EXIT_IF_FORCED_EXIT; } temp_jctl = (jnl_ctl_list *)malloc(SIZEOF(jnl_ctl_list)); /* gtm_malloc is now thread safe */ memset(temp_jctl, 0, SIZEOF(jnl_ctl_list)); temp_jctl->jnl_fn_len = jctl->jfh->next_jnl_file_name_length; memcpy(temp_jctl->jnl_fn, jctl->jfh->next_jnl_file_name, jctl->jfh->next_jnl_file_name_length); if (SS_NORMAL != (status = mur_fopen(temp_jctl, rctl))) { free(temp_jctl); return status; } if (SS_NORMAL != (jctl->status = mur_fread_eof(temp_jctl, rctl))) { gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(9) ERR_JNLBADRECFMT, 3, temp_jctl->jnl_fn_len, temp_jctl->jnl_fn, temp_jctl->rec_offset, ERR_TEXT, 2, LEN_AND_LIT("mur_jctl_from_next_gen")); free(temp_jctl); return ERR_JNLBADRECFMT; } temp_jctl->prev_gen = jctl; temp_jctl->next_gen = NULL; jctl->next_gen = temp_jctl; jctl = temp_jctl; } rctl->jctl = jctl; assert(jctl->reg_ctl == rctl); return SS_NORMAL; }
int4 add_inter(int val, sm_int_ptr_t addr, sm_global_latch_ptr_t latch) { int4 cntrval, newcntrval, spins, maxspins, retries; boolean_t cswpsuccess; sm_int_ptr_t volatile cntrval_p; ++fast_lock_count; maxspins = num_additional_processors ? MAX_LOCK_SPINS(LOCK_SPINS, num_additional_processors) : 1; cntrval_p = addr; /* Need volatile context especially on Itanium */ for (retries = LOCK_TRIES - 1; 0 < retries; retries--) /* - 1 so do rel_quant 3 times first */ { /* seems like a legitinate spin which could take advantage of transactional memory */ for (spins = maxspins; 0 < spins; spins--) { cntrval = *cntrval_p; newcntrval = cntrval + val; /* This is (currently as of 08/2007) the only non-locking usage of compswap in GT.M. We are not passing compswap an actual sm_global_latch_ptr_t addr like its function would normally dictate. However, since the address of the field we want to deal with is the first int in the global_latch_t, we just pass our int address properly cast to the type that compswap is expecting. The assert below verifies that this assumption has not changed (SE 08/2007) */ assert(0 == OFFSETOF(global_latch_t, u.parts.latch_pid)); IA64_ONLY(cswpsuccess = compswap_unlock(RECAST(sm_global_latch_ptr_t)cntrval_p, cntrval, newcntrval)); NON_IA64_ONLY(cswpsuccess = compswap((sm_global_latch_ptr_t)cntrval_p, cntrval, newcntrval)); if (cswpsuccess) { --fast_lock_count; assert(0 <= fast_lock_count); return newcntrval; } } if (retries & 0x3) /* On all but every 4th pass, do a simple rel_quant */ rel_quant(); /* Release processor to holder of lock (hopefully) */ else { /* On every 4th pass, we bide for awhile */ wcs_sleep(LOCK_SLEEP); assert(0 == (LOCK_TRIES % 4)); /* assures there are 3 rel_quants prior to first wcs_sleep() */ } } --fast_lock_count; assert(FALSE); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DBCCERR, 2, LEN_AND_LIT("*unknown*"), ERR_ERRCALL, 3, CALLFROM); return 0; /* To keep the compiler quiet */ }
void gtmsource_seqno_init(void) { /* Find the start_jnl_seqno */ gd_region *reg, *region_top; seq_num local_read_jsn, local_jsn; sgmnt_addrs *csa; sgmnt_data_ptr_t csd; sm_uc_ptr_t gld_fn; /* Unix and VMS have different field names for now, but will both be soon changed to instname instead of gtmgbldir */ gld_fn = (sm_uc_ptr_t)jnlpool.jnlpool_ctl->jnlpool_id.gtmgbldir; QWASSIGN(jnlpool.jnlpool_ctl->start_jnl_seqno, seq_num_zero); QWASSIGN(local_read_jsn, seq_num_zero); QWASSIGN(local_jsn, seq_num_zero); region_top = gd_header->regions + gd_header->n_regions; for (reg = gd_header->regions; reg < region_top; reg++) { assert(reg->open); csa = &FILE_INFO(reg)->s_addrs; csd = csa->hdr; if (REPL_ALLOWED(csd)) { if (QWLT(local_read_jsn, csd->resync_seqno)) QWASSIGN(local_read_jsn, csd->resync_seqno); if (QWLT(local_jsn, csd->reg_seqno)) QWASSIGN(local_jsn, csd->reg_seqno); /* Copy gtmgbldir into the database shared memory. * Used later to avoid updates from a different gtmgbldir to this database. */ assert(SIZEOF(csa->nl->replinstfilename) == SIZEOF(jnlpool.jnlpool_ctl->jnlpool_id.gtmgbldir)); memcpy(csa->nl->replinstfilename, gld_fn, SIZEOF(csa->nl->replinstfilename)); } } if (QWEQ(local_jsn, seq_num_zero)) { /* No replicated region, or databases created with older version of GTM */ gtm_putmsg(VARLSTCNT(5) ERR_NOREPLCTDREG, 3, LEN_AND_LIT("global directory"), gld_fn); /* Error, has to shutdown all regions 'cos mupip needs exclusive access to turn replication on */ gtmsource_autoshutdown(); } QWASSIGN(jnlpool.jnlpool_ctl->start_jnl_seqno, local_jsn); QWASSIGN(jnlpool.jnlpool_ctl->jnl_seqno, local_jsn); QWASSIGN(jnlpool.gtmsource_local->read_jnl_seqno, local_read_jsn); }
void init_callin_functable(void) { unsigned char *env_top, *address_top; uint4 address_len; int save_errno; address_top = GTM64_ONLY(i2ascl)NON_GTM64_ONLY(i2asc)(gtmvectortable_address, (UINTPTR_T)(&callintogtm_vectortable[0])); *address_top = '\0'; address_len = (uint4)(address_top - >mvectortable_address[0]); env_top = >mvectortable_env[0]; MEMCPY_LIT(env_top, GTM_CALLIN_START_ENV); memcpy((env_top + strlen(GTM_CALLIN_START_ENV)), gtmvectortable_address, address_len); *(env_top + strlen(GTM_CALLIN_START_ENV) + address_len) = '\0'; if (PUTENV((char *)gtmvectortable_env)) { save_errno = errno; rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("putenv"), CALLFROM, save_errno); } }
/* This function sets the "ftok_counter_halted" field to TRUE in the instance file header and flushes it to disk. * Caller could be attached to the journal pool or not. If not, update file header directly. If yes, go through locks. */ void repl_inst_ftok_counter_halted(unix_db_info *udi, char *file_type, repl_inst_hdr *repl_instance) { assert(udi->grabbed_ftok_sem); /* this ensures we have a lock before we modify the instance file header */ if (NULL != jnlpool.repl_inst_filehdr) { assert(!jnlpool.repl_inst_filehdr->ftok_counter_halted); jnlpool.repl_inst_filehdr->ftok_counter_halted = TRUE; grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK); repl_inst_flush_filehdr(); rel_lock(jnlpool.jnlpool_dummy_reg); } else { assert(!repl_instance->ftok_counter_halted); repl_instance->ftok_counter_halted = TRUE; repl_inst_write(udi->fn, (off_t)0, (sm_uc_ptr_t)repl_instance, SIZEOF(repl_inst_hdr)); } /* Ignore any errors while flushing the "halted" value to the file header. The only consequence is other processes * will incur a performance overhead trying to unnecessarily bump the semaphore counter when it is already ERANGE. */ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_NOMORESEMCNT, 5, LEN_AND_LIT("ftok"), file_type, LEN_AND_STR(udi->fn)); }
void op_gvincr(mval *increment, mval *result) { unsigned char buff[MAX_ZWR_KEY_SZ], *end; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; /* If specified var name is global ^%Y*, the name is illegal to use in a SET or KILL command, only GETs are allowed */ if ((RESERVED_NAMESPACE_LEN <= gv_currkey->end) && (0 == MEMCMP_LIT(gv_currkey->base, RESERVED_NAMESPACE))) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_PCTYRESERVED); if (gv_cur_region->read_only) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBPRIVERR, 2, DB_LEN_STR(gv_cur_region)); if ((TREF(gv_last_subsc_null) || TREF(gv_some_subsc_null)) && (ALWAYS != gv_cur_region->null_subs)) sgnl_gvnulsubsc(); assert(gv_currkey->end + 1 <= gv_cur_region->max_key_size); MV_FORCE_NUM(increment); switch (gv_cur_region->dyn.addr->acc_meth) { case dba_bg: case dba_mm: gvcst_incr(increment, result); break; case dba_cm: gvcmx_increment(increment, result); break; case dba_usr: /* $INCR not supported for DDP/USR access method */ if (0 == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ, gv_currkey, TRUE))) end = &buff[MAX_ZWR_KEY_SZ - 1]; rts_error_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_UNIMPLOP, 0, ERR_TEXT, 2, LEN_AND_LIT("GTCM DDP server does not support $INCREMENT"), ERR_GVIS, 2, end - buff, buff, ERR_TEXT, 2, REG_LEN_STR(gv_cur_region)); break; default: assertpro(FALSE); } assert(MV_DEFINED(result)); }
void op_fnzconvert3(mval *src, mval* ichset, mval* ochset, mval* dst) { UConverter *from, *to; int dstlen; MV_FORCE_STR(src); if (!gtm_utf8_mode) { /* Unicode not enabled, report error rather than silently ignoring the conversion */ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_INVFCN, 0, ERR_TEXT, 2, LEN_AND_LIT("Three-argument form of $ZCONVERT() is not allowed in the current $ZCHSET")); } MV_FORCE_STR(ichset); MV_FORCE_STR(ochset); /* The only supported names are: "UTF-8", "UTF-16", "UTF-16LE" and "UTF-16BE */ if (NULL == (from = get_chset_desc(&ichset->str))) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_BADCHSET, 2, ichset->str.len, ichset->str.addr); if (NULL == (to = get_chset_desc(&ochset->str))) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_BADCHSET, 2, ochset->str.len, ochset->str.addr); dstlen = gtm_conv(from, to, &src->str, NULL, NULL); assert(-1 != dstlen); MV_INIT_STRING(dst, dstlen, stringpool.free); stringpool.free += dst->str.len; }
void bin_load(uint4 begin, uint4 end) { unsigned char *ptr, *cp1, *cp2, *btop, *gvkey_char_ptr, *tmp_ptr, *tmp_key_ptr, *c, *ctop; unsigned char hdr_lvl, src_buff[MAX_KEY_SZ + 1], dest_buff[MAX_ZWR_KEY_SZ], cmpc_str[MAX_KEY_SZ + 1], dup_key_str[MAX_KEY_SZ + 1]; unsigned char *end_buff; unsigned short rec_len, next_cmpc; int len; int current, last, length, max_blk_siz, max_key, status; uint4 iter, max_data_len, max_subsc_len, key_count; ssize_t rec_count, global_key_count, subsc_len,extr_std_null_coll; boolean_t need_xlation, new_gvn, utf8_extract; rec_hdr *rp, *next_rp; mval v, tmp_mval; mstr mstr_src, mstr_dest; collseq *extr_collseq, *db_collseq, *save_gv_target_collseq; coll_hdr extr_collhdr, db_collhdr; gv_key *tmp_gvkey = NULL; /* null-initialize at start, will be malloced later */ char std_null_coll[BIN_HEADER_NUMSZ + 1]; # ifdef GTM_CRYPT gtmcrypt_key_t *encr_key_handles; char *inbuf; int4 index; int req_dec_blk_size, init_status, crypt_status; muext_hash_hdr_ptr_t hash_array = NULL; # endif DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert(4 == SIZEOF(coll_hdr)); gvinit(); v.mvtype = MV_STR; len = file_input_bin_get((char **)&ptr); hdr_lvl = EXTR_HEADER_LEVEL(ptr); if (!(((('4' == hdr_lvl) || ('5' == hdr_lvl)) && (BIN_HEADER_SZ == len)) || (('4' > hdr_lvl) && (V3_BIN_HEADER_SZ == len)))) { rts_error(VARLSTCNT(1) ERR_LDBINFMT); mupip_exit(ERR_LDBINFMT); } /* expecting the level in a single character */ assert(' ' == *(ptr + SIZEOF(BIN_HEADER_LABEL) - 3)); if (0 != memcmp(ptr, BIN_HEADER_LABEL, SIZEOF(BIN_HEADER_LABEL) - 2) || ('2' > hdr_lvl) || *(BIN_HEADER_VERSION) < hdr_lvl) { /* ignore the level check */ rts_error(VARLSTCNT(1) ERR_LDBINFMT); mupip_exit(ERR_LDBINFMT); } /* check if extract was generated in UTF-8 mode */ utf8_extract = (0 == MEMCMP_LIT(&ptr[len - BIN_HEADER_LABELSZ], UTF8_NAME)) ? TRUE : FALSE; if ((utf8_extract && !gtm_utf8_mode) || (!utf8_extract && gtm_utf8_mode)) { /* extract CHSET doesn't match $ZCHSET */ if (utf8_extract) rts_error(VARLSTCNT(4) ERR_LOADINVCHSET, 2, LEN_AND_LIT("UTF-8")); else rts_error(VARLSTCNT(4) ERR_LOADINVCHSET, 2, LEN_AND_LIT("M")); mupip_exit(ERR_LDBINFMT); } if ('4' >= hdr_lvl) { /* Binary extracts in V50000-to-V52000 (label=4) and pre-V50000 (label=3) could have a '\0' byte (NULL byte) * in the middle of the string. Replace it with ' ' (space) like it would be in V52000 binary extracts and above. */ for (c = ptr, ctop = c + len; c < ctop; c++) { if ('\0' == *c) *c = ' '; } } util_out_print("Label = !AD\n", TRUE, len, ptr); new_gvn = FALSE; if (hdr_lvl > '3') { memcpy(std_null_coll, ptr + BIN_HEADER_NULLCOLLOFFSET, BIN_HEADER_NUMSZ); std_null_coll[BIN_HEADER_NUMSZ] = '\0'; extr_std_null_coll = STRTOUL(std_null_coll, NULL, 10); if (0 != extr_std_null_coll && 1!= extr_std_null_coll) { rts_error(VARLSTCNT(5) ERR_TEXT, 2, RTS_ERROR_TEXT("Corrupted null collation field in header"), ERR_LDBINFMT); mupip_exit(ERR_LDBINFMT); } } else extr_std_null_coll = 0; # ifdef GTM_CRYPT if ('5' <= hdr_lvl) { int i, num_indexes; len = file_input_bin_get((char **)&ptr); hash_array = (muext_hash_hdr *)malloc(len); /* store hashes of all the files used during extract into muext_hash_hdr structure */ memcpy((char *)hash_array, ptr, len); num_indexes = len / GTMCRYPT_HASH_LEN; encr_key_handles = (gtmcrypt_key_t *)malloc(SIZEOF(gtmcrypt_key_t) * num_indexes); INIT_PROC_ENCRYPTION(crypt_status); GC_BIN_LOAD_ERR(crypt_status); for (index = 0; index < num_indexes; index++) { if (0 == memcmp(hash_array[index].gtmcrypt_hash, EMPTY_GTMCRYPT_HASH, GTMCRYPT_HASH_LEN)) continue; GTMCRYPT_GETKEY(hash_array[index].gtmcrypt_hash, encr_key_handles[index], crypt_status); GC_BIN_LOAD_ERR(crypt_status); } } # endif if ('2' < hdr_lvl) { len = file_input_bin_get((char **)&ptr); if (SIZEOF(coll_hdr) != len) { rts_error(VARLSTCNT(5) ERR_TEXT, 2, RTS_ERROR_TEXT("Corrupt collation header"), ERR_LDBINFMT); mupip_exit(ERR_LDBINFMT); } extr_collhdr = *((coll_hdr *)(ptr)); new_gvn = TRUE; } else gtm_putmsg(VARLSTCNT(3) ERR_OLDBINEXTRACT, 1, hdr_lvl - '0'); if (begin < 2) begin = 2; for (iter = 2; iter < begin; iter++) { if (!(len = file_input_bin_get((char **)&ptr))) { gtm_putmsg(VARLSTCNT(3) ERR_LOADEOF, 1, begin); util_out_print("Error reading record number: !UL\n", TRUE, iter); mupip_error_occurred = TRUE; return; } else if (len == SIZEOF(coll_hdr)) { extr_collhdr = *((coll_hdr *)(ptr)); assert(hdr_lvl > '2'); iter--; } } assert(iter == begin); util_out_print("Beginning LOAD at record number: !UL\n", TRUE, begin); max_data_len = 0; max_subsc_len = 0; global_key_count = key_count = 0; rec_count = begin - 1; extr_collseq = db_collseq = NULL; need_xlation = FALSE; assert(NULL == tmp_gvkey); /* GVKEY_INIT macro relies on this */ GVKEY_INIT(tmp_gvkey, DBKEYSIZE(MAX_KEY_SZ)); /* tmp_gvkey will point to malloced memory after this */ for (; !mupip_DB_full ;) { if (++rec_count > end) break; next_cmpc = 0; mupip_error_occurred = FALSE; if (mu_ctrly_occurred) break; if (mu_ctrlc_occurred) { util_out_print("!AD:!_ Key cnt: !UL max subsc len: !UL max data len: !UL", TRUE, LEN_AND_LIT(gt_lit), key_count, max_subsc_len, max_data_len); util_out_print("Last LOAD record number: !UL", TRUE, key_count ? (rec_count - 1) : 0); mu_gvis(); util_out_print(0, TRUE); mu_ctrlc_occurred = FALSE; } /* reset the stringpool for every record in order to avoid garbage collection */ stringpool.free = stringpool.base; if (!(len = file_input_bin_get((char **)&ptr)) || mupip_error_occurred) break; else if (len == SIZEOF(coll_hdr)) { extr_collhdr = *((coll_hdr *)(ptr)); assert(hdr_lvl > '2'); new_gvn = TRUE; /* next record will contain a new gvn */ rec_count--; /* Decrement as this record does not count as a record for loading purposes */ continue; } rp = (rec_hdr*)(ptr); # ifdef GTM_CRYPT if ('5' <= hdr_lvl) { /* Getting index value from the extracted file. It indicates which database file this record belongs to */ GET_LONG(index, ptr); if (-1 != index) /* Indicates that the record is encrypted. */ { req_dec_blk_size = len - SIZEOF(int4); inbuf = (char *)(ptr + SIZEOF(int4)); GTMCRYPT_DECODE_FAST(encr_key_handles[index], inbuf, req_dec_blk_size, NULL, crypt_status); GC_BIN_LOAD_ERR(crypt_status); } rp = (rec_hdr*)(ptr + SIZEOF(int4)); } # endif btop = ptr + len; cp1 = (unsigned char*)(rp + 1); v.str.addr = (char*)cp1; while (*cp1++) ; v.str.len =INTCAST((char*)cp1 - v.str.addr - 1); if (('2' >= hdr_lvl) || new_gvn) { if ((HASHT_GBLNAME_LEN == v.str.len) && (0 == memcmp(v.str.addr, HASHT_GBLNAME, HASHT_GBLNAME_LEN))) continue; bin_call_db(BIN_BIND, (INTPTR_T)gd_header, (INTPTR_T)&v.str); max_key = gv_cur_region->max_key_size; db_collhdr.act = gv_target->act; db_collhdr.ver = gv_target->ver; db_collhdr.nct = gv_target->nct; } GET_USHORT(rec_len, &rp->rsiz); if (rp->cmpc != 0 || v.str.len > rec_len || mupip_error_occurred) { bin_call_db(ERR_COR, (INTPTR_T)rec_count, (INTPTR_T)global_key_count); mu_gvis(); util_out_print(0, TRUE); continue; } if (new_gvn) { global_key_count = 1; if ((db_collhdr.act != extr_collhdr.act || db_collhdr.ver != extr_collhdr.ver || db_collhdr.nct != extr_collhdr.nct || gv_cur_region->std_null_coll != extr_std_null_coll)) { if (extr_collhdr.act) { if (extr_collseq = ready_collseq((int)extr_collhdr.act)) { if (!do_verify(extr_collseq, extr_collhdr.act, extr_collhdr.ver)) { gtm_putmsg(VARLSTCNT(8) ERR_COLLTYPVERSION, 2, extr_collhdr.act, extr_collhdr.ver, ERR_GVIS, 2, gv_altkey->end - 1, gv_altkey->base); mupip_exit(ERR_COLLTYPVERSION); } } else { gtm_putmsg(VARLSTCNT(7) ERR_COLLATIONUNDEF, 1, extr_collhdr.act, ERR_GVIS, 2, gv_altkey->end - 1, gv_altkey->base); mupip_exit(ERR_COLLATIONUNDEF); } } if (db_collhdr.act) { if (db_collseq = ready_collseq((int)db_collhdr.act)) { if (!do_verify(db_collseq, db_collhdr.act, db_collhdr.ver)) { gtm_putmsg(VARLSTCNT(8) ERR_COLLTYPVERSION, 2, db_collhdr.act, db_collhdr.ver, ERR_GVIS, 2, gv_altkey->end - 1, gv_altkey->base); mupip_exit(ERR_COLLTYPVERSION); } } else { gtm_putmsg(VARLSTCNT(7) ERR_COLLATIONUNDEF, 1, db_collhdr.act, ERR_GVIS, 2, gv_altkey->end - 1, gv_altkey->base); mupip_exit(ERR_COLLATIONUNDEF); } } need_xlation = TRUE; } else need_xlation = FALSE; } new_gvn = FALSE; for (; rp < (rec_hdr*)btop; rp = (rec_hdr*)((unsigned char *)rp + rec_len)) { GET_USHORT(rec_len, &rp->rsiz); if (rec_len + (unsigned char *)rp > btop) { bin_call_db(ERR_COR, (INTPTR_T)rec_count, (INTPTR_T)global_key_count); mu_gvis(); util_out_print(0, TRUE); break; } cp1 = (unsigned char*)(rp + 1); cp2 = gv_currkey->base + rp->cmpc; current = 1; for (;;) { last = current; current = *cp2++ = *cp1++; if (0 == last && 0 == current) break; if (cp1 > (unsigned char *)rp + rec_len || cp2 > (unsigned char *)gv_currkey + gv_currkey->top) { bin_call_db(ERR_COR, (INTPTR_T)rec_count, (INTPTR_T)global_key_count); mu_gvis(); util_out_print(0, TRUE); break; } } if (mupip_error_occurred) break; gv_currkey->end = cp2 - gv_currkey->base - 1; if (need_xlation) { assert(hdr_lvl >= '3'); assert(extr_collhdr.act || db_collhdr.act || extr_collhdr.nct || db_collhdr.nct || extr_std_null_coll != gv_cur_region->std_null_coll); /* gv_currkey would have been modified/translated in the earlier put */ memcpy(gv_currkey->base, cmpc_str, next_cmpc); next_rp = (rec_hdr *)((unsigned char*)rp + rec_len); if ((unsigned char*)next_rp < btop) { next_cmpc = next_rp->cmpc; assert(next_cmpc <= gv_currkey->end); memcpy(cmpc_str, gv_currkey->base, next_cmpc); } else next_cmpc = 0; /* length of the key might change (due to nct variation), * so get a copy of the original key from the extract */ memcpy(dup_key_str, gv_currkey->base, gv_currkey->end + 1); gvkey_char_ptr = dup_key_str; while (*gvkey_char_ptr++) ; gv_currkey->prev = 0; gv_currkey->end = gvkey_char_ptr - dup_key_str; assert(gv_keysize <= tmp_gvkey->top); while (*gvkey_char_ptr) { /* get next subscript (in GT.M internal subsc format) */ subsc_len = 0; tmp_ptr = src_buff; while (*gvkey_char_ptr) *tmp_ptr++ = *gvkey_char_ptr++; subsc_len = tmp_ptr - src_buff; src_buff[subsc_len] = '\0'; if (extr_collseq) { /* undo the extract time collation */ TREF(transform) = TRUE; save_gv_target_collseq = gv_target->collseq; gv_target->collseq = extr_collseq; } else TREF(transform) = FALSE; /* convert the subscript to string format */ end_buff = gvsub2str(src_buff, dest_buff, FALSE); /* transform the string to the current subsc format */ TREF(transform) = TRUE; tmp_mval.mvtype = MV_STR; tmp_mval.str.addr = (char *)dest_buff; tmp_mval.str.len = INTCAST(end_buff - dest_buff); tmp_gvkey->prev = 0; tmp_gvkey->end = 0; if (extr_collseq) gv_target->collseq = save_gv_target_collseq; mval2subsc(&tmp_mval, tmp_gvkey); /* we now have the correctly transformed subscript */ tmp_key_ptr = gv_currkey->base + gv_currkey->end; memcpy(tmp_key_ptr, tmp_gvkey->base, tmp_gvkey->end + 1); gv_currkey->prev = gv_currkey->end; gv_currkey->end += tmp_gvkey->end; gvkey_char_ptr++; } if ( gv_cur_region->std_null_coll != extr_std_null_coll && gv_currkey->prev) { if (extr_std_null_coll == 0) { GTM2STDNULLCOLL(gv_currkey->base, gv_currkey->end); } else { STD2GTMNULLCOLL(gv_currkey->base, gv_currkey->end); } } } if (gv_currkey->end >= max_key) { bin_call_db(ERR_COR, (INTPTR_T)rec_count, (INTPTR_T)global_key_count); mu_gvis(); util_out_print(0, TRUE); continue; } if (max_subsc_len < (gv_currkey->end + 1)) max_subsc_len = gv_currkey->end + 1; v.str.addr = (char*)cp1; v.str.len =INTCAST(rec_len - (cp1 - (unsigned char *)rp)); if (max_data_len < v.str.len) max_data_len = v.str.len; bin_call_db(BIN_PUT, (INTPTR_T)&v, 0); if (mupip_error_occurred) { if (!mupip_DB_full) { bin_call_db(ERR_COR, (INTPTR_T)rec_count, (INTPTR_T)global_key_count); util_out_print(0, TRUE); } break; } key_count++; global_key_count++; } } GTMCRYPT_ONLY( if (NULL != hash_array) free(hash_array); )
int gtmrecv_start_helpers(int n_readers, int n_writers) { /* Set flag in recvpool telling the receiver server to start n_readers and n_writers helper processes. * Wait for receiver server to complete the process - completed successfully, or terminated with error */ upd_helper_ctl_ptr_t upd_helper_ctl; upd_helper_entry_ptr_t helper, helper_top; char err_str[BUFSIZ]; int avail_slots, started_readers, started_writers; error_def(ERR_REPLERR); error_def(ERR_REPLINFO); error_def(ERR_REPLWARN); assert(0 != n_readers || 0 != n_writers); upd_helper_ctl = recvpool.upd_helper_ctl; /* let's clean up dead helpers first so we get an accurate count of available slots */ upd_helper_ctl->reap_helpers = HELPER_REAP_NOWAIT; while (HELPER_REAP_NONE != upd_helper_ctl->reap_helpers && SRV_ALIVE == is_recv_srv_alive()) SHORT_SLEEP(GTMRECV_WAIT_FOR_UPD_SHUTDOWN); upd_helper_ctl->reap_helpers = HELPER_REAP_NONE; /* just in case recvr died */ /* count available slots so receiver doesn't have to */ for (avail_slots = 0, helper = upd_helper_ctl->helper_list, helper_top = helper + MAX_UPD_HELPERS; helper < helper_top; helper++) { if (0 == helper->helper_pid) { avail_slots++; helper->helper_pid_prev = 0; /* force out abnormally terminated helpers as well */ helper->helper_shutdown = NO_SHUTDOWN; /* clean state */ } } if (avail_slots < n_readers + n_writers) { SNPRINTF(err_str, SIZEOF(err_str), "%d helpers will exceed the maximum allowed (%d), limit the helpers to %d\n", n_readers + n_writers, MAX_UPD_HELPERS, avail_slots); gtm_putmsg(VARLSTCNT(4) ERR_REPLERR, 2, LEN_AND_STR(err_str)); return ABNORMAL_SHUTDOWN; } upd_helper_ctl->start_n_readers = n_readers; upd_helper_ctl->start_n_writers = n_writers; SHM_WRITE_MEMORY_BARRIER; upd_helper_ctl->start_helpers = TRUE; /* hey receiver, let's go, start 'em up */ while (upd_helper_ctl->start_helpers && SRV_ALIVE == is_recv_srv_alive()) SHORT_SLEEP(GTMRECV_WAIT_FOR_SRV_START); if (!upd_helper_ctl->start_helpers) { started_readers = upd_helper_ctl->start_n_readers; started_writers = upd_helper_ctl->start_n_writers; SNPRINTF(err_str, SIZEOF(err_str), "%s %d out of %d readers and %d out of %d writers started", ((started_readers + started_writers) == (n_readers + n_writers)) ? "All" : "Only", started_readers, n_readers, started_writers, n_writers); if ((started_readers + started_writers) == (n_readers + n_writers)) { gtm_putmsg(VARLSTCNT(4) ERR_REPLINFO, 2, LEN_AND_STR(err_str)); return NORMAL_SHUTDOWN; } gtm_putmsg(VARLSTCNT(4) ERR_REPLWARN, 2, LEN_AND_STR(err_str)); return ABNORMAL_SHUTDOWN; } gtm_putmsg(VARLSTCNT(4) ERR_REPLERR, 2, LEN_AND_LIT("Receiver server is not alive to start helpers. Start receiver server first")); return ABNORMAL_SHUTDOWN; }
void go_load(uint4 begin, uint4 end) { char *ptr; int len, fmt, keylength, keystate; uint4 iter, max_data_len, max_subsc_len, key_count, max_rec_size; mstr src, des; unsigned char *rec_buff, ch; boolean_t utf8_extract, format_error = FALSE, hasht_ignored = FALSE, hasht_gbl = FALSE; char *val_off; int val_len, val_off1, val_len1; boolean_t is_setextract; gvinit(); max_rec_size = DEFAULT_MAX_REC_SIZE; rec_buff = (unsigned char *)malloc(max_rec_size); fmt = MU_FMT_ZWR; /* by default, the extract format is ZWR (not GO) */ len = file_input_get(&ptr); if (mupip_error_occurred) { free(rec_buff); return; } if (len >= 0) { util_out_print("!AD", TRUE, len, ptr); utf8_extract = ((len >= STR_LIT_LEN(UTF8_NAME)) && (0 == MEMCMP_LIT(ptr + len - STR_LIT_LEN("UTF-8"), "UTF-8"))) ? TRUE : FALSE; if ((utf8_extract && !gtm_utf8_mode) || (!utf8_extract && gtm_utf8_mode)) { /* extract CHSET doesn't match $ZCHSET */ if (utf8_extract) gtm_putmsg(VARLSTCNT(4) ERR_LOADINVCHSET, 2, LEN_AND_LIT("UTF-8")); else gtm_putmsg(VARLSTCNT(4) ERR_LOADINVCHSET, 2, LEN_AND_LIT("M")); mupip_error_occurred = TRUE; free(rec_buff); return; } } else mupip_exit(ERR_LOADFILERR); len = file_input_get(&ptr); if (mupip_error_occurred) { free(rec_buff); return; } if (len >= 0) { util_out_print("!AD", TRUE, len, ptr); fmt = (0 == memcmp(ptr + len - STR_LIT_LEN("ZWR"), "ZWR", STR_LIT_LEN("ZWR"))) ? MU_FMT_ZWR : MU_FMT_GO; } else mupip_exit(ERR_LOADFILERR); if (begin < 3) begin = 3; for (iter = 3; iter < begin; iter++) { len = file_input_get(&ptr); if (len < 0) /* The IO device has signalled an end of file */ { gtm_putmsg(VARLSTCNT(3) ERR_LOADEOF, 1, begin); mupip_error_occurred = TRUE; } if (mupip_error_occurred) { util_out_print("Error reading record number: !UL\n", TRUE, iter); free(rec_buff); return; } } assert(iter == begin); util_out_print("Beginning LOAD at record number: !UL\n", TRUE, begin); max_data_len = 0; max_subsc_len = 0; key_count = 0; for (iter = begin - 1; ; ) { if (++iter > end) break; if (mu_ctrly_occurred) break; if (mu_ctrlc_occurred) { util_out_print("!AD:!_ Key cnt: !UL max subsc len: !UL max data len: !UL", TRUE, LEN_AND_LIT(gt_lit), key_count, max_subsc_len, max_data_len); util_out_print("Last LOAD record number: !UL", TRUE, key_count ? iter : 0); mu_gvis(); util_out_print(0, TRUE); mu_ctrlc_occurred = FALSE; } if (0 > (len = file_input_get(&ptr))) break; if (mupip_error_occurred) { mu_gvis(); break; } if ('\n' == *ptr) { if ('\n' == *(ptr+1)) break; ptr++; } if (0 == len) continue; if (MU_FMT_GO != fmt) { /* Determine if the ZWR has $extract format */ if ('$' == *ptr) { keylength = zwrkeyvallen(ptr, len, &val_off, &val_len, &val_off1, &val_len1); ptr = ptr + 4; /* Skip first 4 character '$','z','e','(' */ is_setextract = TRUE; } else { /* Determine the ZWR key length. -1 (SIZEOF(=)) is needed since ZWR allows '^x(1,2)='*/ keylength = zwrkeyvallen(ptr, len, &val_off, &val_len, NULL, NULL); is_setextract = FALSE; } ISSUE_TRIGDATAIGNORE_IF_NEEDED(keylength, ptr, hasht_gbl); if (hasht_gbl) { hasht_gbl = FALSE; continue; } go_call_db(GO_PUT_SUB, ptr, keylength, 0, 0); if (mupip_error_occurred) { mu_gvis(); util_out_print("Error loading record number: !UL\n", TRUE, iter); mupip_error_occurred = FALSE; continue; } assert(keylength < len - 1); if (max_subsc_len < (gv_currkey->end + 1)) max_subsc_len = gv_currkey->end + 1; src.len = val_len; src.addr = val_off; des.len = 0; if (src.len > max_rec_size) { max_rec_size = src.len; free(rec_buff); rec_buff = (unsigned char *)malloc(max_rec_size); } des.addr = (char *)rec_buff; if (FALSE == zwr2format(&src, &des)) { util_out_print("Format error in record number !8UL: !/!AD", TRUE, iter, src.len, src.addr); format_error = TRUE; continue; } if (max_data_len < des.len) max_data_len = des.len; (is_setextract) ? go_call_db(GO_SET_EXTRACT, des.addr, des.len, val_off1, val_len1) : go_call_db(GO_PUT_DATA, (char *)rec_buff, des.len, 0, 0); if (mupip_error_occurred) { mu_gvis(); util_out_print("Error loading record number: !UL\n", TRUE, iter); mupip_error_occurred = FALSE; continue; } key_count++; } else { ISSUE_TRIGDATAIGNORE_IF_NEEDED(len, ptr, hasht_gbl); if (hasht_gbl) { if (0 > (len = file_input_get(&ptr))) break; iter++; hasht_gbl = FALSE; continue; } go_call_db(GO_PUT_SUB, ptr, len, 0, 0); if (mupip_error_occurred) { mu_gvis(); util_out_print("Error loading record number: !UL\n", TRUE, iter); mupip_error_occurred = FALSE; continue; } if (max_subsc_len < (gv_currkey->end + 1)) max_subsc_len = gv_currkey->end + 1; if (++iter > end) { iter--; /* Decrement as didn't load key */ break; } if ((len = file_input_get(&ptr)) < 0) break; if (mupip_error_occurred) { mu_gvis(); util_out_print("Error loading record number: !UL\n", TRUE, iter); break; } stringpool.free = stringpool.base; if (max_data_len < len) max_data_len = len; go_call_db(GO_PUT_DATA, ptr, len, 0, 0); if (mupip_error_occurred) { mu_gvis(); util_out_print("Error loading record number: !UL\n", TRUE, iter); mupip_error_occurred = FALSE; continue; } key_count++; } } free(rec_buff); file_input_close(); if (mu_ctrly_occurred) { gtm_putmsg(VARLSTCNT(1) ERR_LOADCTRLY); mupip_exit(ERR_MUNOFINISH); } util_out_print("LOAD TOTAL!_!_Key Cnt: !UL Max Subsc Len: !UL Max Data Len: !UL",TRUE,key_count,max_subsc_len, max_data_len); util_out_print("Last LOAD record number: !UL\n", TRUE, key_count ? (iter - 1) : 0); if (format_error) mupip_exit(ERR_LOADFILERR); }
void lke_show(void) { bool locks, all = TRUE, wait = TRUE, interactive = FALSE, match = FALSE, memory = TRUE, nocrit = TRUE; boolean_t exact = FALSE, was_crit; int4 pid; size_t ls_len; int n; char regbuf[MAX_RN_LEN], nodebuf[32], one_lockbuf[MAX_KEY_SZ]; mlk_ctldata_ptr_t ctl; mstr reg, node, one_lock; int shr_sub_len = 0; float ls_free = 0; /* Free space in bottleneck subspace */ /* Get all command parameters */ reg.addr = regbuf; reg.len = SIZEOF(regbuf); node.addr = nodebuf; node.len = SIZEOF(nodebuf); one_lock.addr = one_lockbuf; one_lock.len = SIZEOF(one_lockbuf); if (lke_getcli(&all, &wait, &interactive, &pid, ®, &node, &one_lock, &memory, &nocrit, &exact) == 0) return; /* Search all regions specified on the command line */ for (gv_cur_region = gd_header->regions, n = 0; n != gd_header->n_regions; ++gv_cur_region, ++n) { /* If region matches and is open */ if ((reg.len == 0 || gv_cur_region->rname_len == reg.len && memcmp(gv_cur_region->rname, reg.addr, reg.len) == 0) && gv_cur_region->open) { match = TRUE; util_out_print("!/!AD!/", NOFLUSH, REG_LEN_STR(gv_cur_region)); /* If distributed database, the region is located on another node */ if (gv_cur_region->dyn.addr->acc_meth == dba_cm) { # if defined(LKE_WORKS_OK_WITH_CM) /* Obtain lock info from the remote node */ locks = gtcmtr_lke_showreq(gv_cur_region->dyn.addr->cm_blk, gv_cur_region->cmx_regnum, all, wait, pid, &node); # else gtm_putmsg(VARLSTCNT(10) ERR_UNIMPLOP, 0, ERR_TEXT, 2, LEN_AND_LIT("GT.CM region - locks must be displayed on the local node"), ERR_TEXT, 2, REG_LEN_STR(gv_cur_region)); continue; # endif } else if (gv_cur_region->dyn.addr->acc_meth == dba_bg || gv_cur_region->dyn.addr->acc_meth == dba_mm) { /* Local region */ cs_addrs = &FILE_INFO(gv_cur_region)->s_addrs; ls_len = (size_t)(cs_addrs->lock_addrs[1] - cs_addrs->lock_addrs[0]); ctl = (mlk_ctldata_ptr_t)malloc(ls_len); /* Prevent any modification of the lock space while we make a local copy of it */ if (cs_addrs->critical != NULL) crash_count = cs_addrs->critical->crashcnt; was_crit = cs_addrs->now_crit; if (!nocrit && !was_crit) grab_crit(gv_cur_region); longcpy((uchar_ptr_t)ctl, (uchar_ptr_t)cs_addrs->lock_addrs[0], ls_len); assert((ctl->max_blkcnt > 0) && (ctl->max_prccnt > 0) && ((ctl->subtop - ctl->subbase) > 0)); if (!nocrit && !was_crit) rel_crit(gv_cur_region); shr_sub_len = 0; locks = ctl->blkroot == 0 ? FALSE: lke_showtree(NULL, (mlk_shrblk_ptr_t)R2A(ctl->blkroot), all, wait, pid, one_lock, memory, &shr_sub_len); /* lock space usage consists of: control_block + nodes(locks) + processes + substrings */ /* any of those subspaces can be bottleneck. * Therefore we will report the subspace which is running out. */ ls_free = MIN(((float)ctl->blkcnt) / ctl->max_blkcnt, ((float)ctl->prccnt) / ctl->max_prccnt); ls_free = MIN(1-(((float)shr_sub_len) / (ctl->subtop - ctl->subbase)), ls_free); ls_free *= 100; /* Scale to [0-100] range. (couldn't do this inside util_out_print) */ if (ls_free < 1) /* No memory? Notify user. */ gtm_putmsg(VARLSTCNT(4) ERR_LOCKSPACEFULL, 2, DB_LEN_STR(gv_cur_region)); if (ls_free < 1 || memory) { if (ctl->subtop > ctl->subfree) gtm_putmsg(VARLSTCNT(10) ERR_LOCKSPACEINFO, 8, REG_LEN_STR(gv_cur_region), (ctl->max_prccnt - ctl->prccnt), ctl->max_prccnt, (ctl->max_blkcnt - ctl->blkcnt), ctl->max_blkcnt, LEN_AND_LIT(" not ")); else gtm_putmsg(VARLSTCNT(10) ERR_LOCKSPACEINFO, 8, REG_LEN_STR(gv_cur_region), (ctl->max_prccnt - ctl->prccnt), ctl->max_prccnt, (ctl->max_blkcnt - ctl->blkcnt), ctl->max_blkcnt, LEN_AND_LIT(" ")); } free(ctl); } else { gtm_putmsg(VARLSTCNT(2) ERR_BADREGION, 0); locks = TRUE; } if (!locks) { gtm_putmsg(VARLSTCNT(4) ERR_NOLOCKMATCH, 2, REG_LEN_STR(gv_cur_region)); } assert((ls_free <= 100) && (ls_free >= 0)); gtm_putmsg(VARLSTCNT(4) ERR_LOCKSPACEUSE, 2, ((int)ls_free), cs_addrs->hdr->lock_space_size/OS_PAGELET_SIZE); } } if (!match && reg.len != 0) rts_error(VARLSTCNT(4) ERR_NOREGION, 2, reg.len, reg.addr); }
callin_entry_list* citab_parse (void) { int parameter_count, i, fclose_res; uint4 inp_mask, out_mask, mask; mstr labref, callnam; enum gtm_types ret_tok, parameter_types[MAX_ACTUALS], pr; char str_buffer[MAX_TABLINE_LEN], *tbp, *end; FILE *ext_table_file_handle; callin_entry_list *entry_ptr = NULL, *save_entry_ptr = NULL; ext_table_file_name = GETENV(CALLIN_ENV_NAME); if (!ext_table_file_name) /* environment variable not set */ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CITABENV, 2, LEN_AND_STR(CALLIN_ENV_NAME)); ext_table_file_handle = Fopen(ext_table_file_name, "r"); if (!ext_table_file_handle) /* call-in table not found */ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(11) ERR_CITABOPN, 2, LEN_AND_STR(ext_table_file_name), ERR_SYSCALL, 5, LEN_AND_LIT("fopen"), CALLFROM, errno); ext_source_line_num = 0; while (read_table(LIT_AND_LEN(str_buffer), ext_table_file_handle)) { if (!*(tbp = exttab_scan_space(str_buffer))) continue; if (!(end = scan_ident(tbp))) ext_stx_error(ERR_CIRCALLNAME, ext_table_file_name); callnam.addr = tbp; callnam.len = INTCAST(end - tbp); tbp = exttab_scan_space(end); if (':' != *tbp++) ext_stx_error(ERR_COLON, ext_table_file_name); ret_tok = scan_keyword(&tbp); /* return type */ switch (ret_tok) /* return type valid ? */ { case gtm_void: case gtm_char_star: case gtm_int_star: case gtm_uint_star: case gtm_long_star: case gtm_ulong_star: case gtm_float_star: case gtm_double_star: case gtm_string_star: case gtm_jboolean: case gtm_jint: case gtm_jlong: case gtm_jfloat: case gtm_jdouble: case gtm_jstring: case gtm_jbyte_array: case gtm_jbig_decimal: break; default: ext_stx_error(ERR_CIRTNTYP, ext_table_file_name); } labref.addr = tbp; if ((end = scan_labelref(tbp))) labref.len = INTCAST(end - tbp); else ext_stx_error(ERR_CIENTNAME, ext_table_file_name); tbp = exttab_scan_space(end); inp_mask = out_mask = 0; for (parameter_count = 0; (*tbp && ')' != *tbp); parameter_count++) { if (MAX_ACTUALS <= parameter_count) ext_stx_error(ERR_CIMAXPARAM, ext_table_file_name); /* must have comma if this is not the first parameter, otherwise '(' */ if (((0 == parameter_count)?'(':',') != *tbp++) ext_stx_error(ERR_CIRPARMNAME, ext_table_file_name); tbp = exttab_scan_space(tbp); if ((0 == parameter_count) && (*tbp == ')')) /* special case () */ break; /* looking for an I, a O or an IO */ mask = (1 << parameter_count); inp_mask |= ('I' == *tbp) ? (tbp++, mask) : 0; out_mask |= ('O' == *tbp) ? (tbp++, mask) : 0; if ((!(inp_mask & mask) && !(out_mask & mask)) || (':' != *tbp++)) ext_stx_error(ERR_CIDIRECTIVE, ext_table_file_name); switch ((pr = scan_keyword(&tbp))) /* valid param type? */ { case gtm_int: case gtm_uint: case gtm_long: case gtm_ulong: case gtm_float: case gtm_double: if (out_mask & mask) ext_stx_error(ERR_CIPARTYPE, ext_table_file_name); /* fall-thru */ case gtm_char_star: case gtm_int_star: case gtm_uint_star: case gtm_long_star: case gtm_ulong_star: case gtm_float_star: case gtm_double_star: case gtm_string_star: case gtm_jboolean: case gtm_jint: case gtm_jlong: case gtm_jfloat: case gtm_jdouble: case gtm_jstring: case gtm_jbyte_array: case gtm_jbig_decimal: break; default: ext_stx_error(ERR_CIUNTYPE, ext_table_file_name); } parameter_types[parameter_count] = pr; tbp = exttab_scan_space(tbp); } if (!*tbp) ext_stx_error(ERR_CIRPARMNAME, ext_table_file_name); entry_ptr = get_memory(SIZEOF(callin_entry_list)); entry_ptr->next_entry = save_entry_ptr; save_entry_ptr = entry_ptr; entry_ptr->return_type = ret_tok; entry_ptr->argcnt = parameter_count; entry_ptr->input_mask = inp_mask; entry_ptr->output_mask = out_mask; entry_ptr->parms = get_memory(parameter_count * SIZEOF(entry_ptr->parms[0])); for (i = 0 ; i < parameter_count; i++) entry_ptr->parms[i] = parameter_types[i]; put_mstr(&labref, &entry_ptr->label_ref); put_mstr(&callnam, &entry_ptr->call_name); } FCLOSE(ext_table_file_handle, fclose_res); return entry_ptr; }
void iosocket_use(io_desc *iod, mval *pp) { unsigned char ch, len; int handled_len, handlea_len, handles_len; int4 length, width, new_len; d_socket_struct *dsocketptr; socket_struct *socketptr, newsocket; char handlea[MAX_HANDLE_LEN], handles[MAX_HANDLE_LEN], handled[MAX_HANDLE_LEN]; char addr[SA_MAXLITLEN], *errptr, sockaddr[SA_MAXLITLEN], temp_addr[SA_MAXLITLEN], ioerror; unsigned char delimiter_buffer[MAX_N_DELIMITER * (MAX_DELIM_LEN + 1)]; unsigned char zff_buffer[MAX_ZFF_LEN]; boolean_t attach_specified = FALSE, detach_specified = FALSE, connect_specified = FALSE, ioerror_specified = FALSE, listen_specified = FALSE, socket_specified = FALSE, delay_specified = FALSE, nodelay_specified = FALSE, bfsize_specified = FALSE, ibfsize_specified = FALSE, moreread_specified = FALSE, create_new_socket; int4 index, n_specified, zff_len, delimiter_len, moreread_timeout; int fil_type, nodelay, p_offset = 0; uint4 bfsize = DEFAULT_SOCKET_BUFFER_SIZE, ibfsize; char *tab; int save_errno; size_t d_socket_struct_len; mstr lcl_zff; assert(iod->state == dev_open); assert(iod->type == gtmsocket); dsocketptr = (d_socket_struct *)(iod->dev_sp); /* ---------------------------------- parse the command line ------------------------------------ */ n_specified = 0; zff_len = -1; /* indicates neither ZFF nor ZNOFF specified */ delimiter_len = -1; /* indicates neither DELIM nor NODELIM specified */ /* A read or wait was interrupted for this device. Allow only parmless use in $zinterrupt code for and interrupted device. */ if (iop_eol != *(pp->str.addr + p_offset)) { /* Parameters were specified */ if (dsocketptr->mupintr) { /* And if we are in $zinterrupt code this is not allowed */ if (dollar_zininterrupt) rts_error(VARLSTCNT(1) ERR_ZINTRECURSEIO); /* We are not in $zinterrupt code and this device was not resumed properly so clear its restartability. */ io_find_mvstent(iod, TRUE); dsocketptr->mupintr = FALSE; } } else if (dsocketptr->mupintr && !dollar_zininterrupt) { /* The interrupted read was not properly resumed so clear it now */ dsocketptr->mupintr = FALSE; dsocketptr->sock_save_state.who_saved = sockwhich_invalid; io_find_mvstent(iod, TRUE); } while (iop_eol != (ch = *(pp->str.addr + p_offset++))) { assert((params)ch < (params)n_iops); switch (ch) { case iop_exception: iod->error_handler.len = *(pp->str.addr + p_offset); iod->error_handler.addr = (char *)(pp->str.addr + p_offset + 1); s2pool(&iod->error_handler); break; case iop_filter: len = *(pp->str.addr + p_offset); tab = pp->str.addr + p_offset + 1; if ((fil_type = namelook(filter_index, filter_names, tab, len)) < 0) { rts_error(VARLSTCNT(1) ERR_TTINVFILTER); return; } switch (fil_type) { case 0: iod->write_filter |= CHAR_FILTER; break; case 1: iod->write_filter |= ESC1; break; case 2: iod->write_filter &= ~CHAR_FILTER; break; case 3: iod->write_filter &= ~ESC1; break; } break; case iop_nofilter: iod->write_filter = 0; break; case iop_attach: n_specified++; attach_specified = TRUE; handlea_len = (int)(*(pp->str.addr + p_offset)); memcpy(handlea, (char *)(pp->str.addr + p_offset + 1), handlea_len); break; case iop_detach: n_specified++; detach_specified = TRUE; handled_len = (int)(*(pp->str.addr + p_offset)); memcpy(handled, (char *)(pp->str.addr + p_offset + 1), handled_len); break; case iop_connect: n_specified++; connect_specified = TRUE; len = *(pp->str.addr + p_offset); if (len < SA_MAXLITLEN) { memcpy(sockaddr, (char *)(pp->str.addr + p_offset + 1), len); sockaddr[len] = '\0'; } else rts_error(VARLSTCNT(6) ERR_ADDRTOOLONG, 4, len, pp->str.addr + p_offset + 1, len, SA_MAXLITLEN); break; case iop_delimiter: n_specified++; delimiter_len = (int4)(unsigned char)*(pp->str.addr + p_offset); if (((MAX_DELIM_LEN + 1) * MAX_N_DELIMITER) >= delimiter_len) memcpy(delimiter_buffer, (pp->str.addr + p_offset + 1), delimiter_len); else rts_error(VARLSTCNT(1) ERR_DELIMSIZNA); break; case iop_nodelimiter: delimiter_len = 0; break; case iop_zdelay: delay_specified = TRUE; break; case iop_znodelay: nodelay_specified = TRUE; break; case iop_zbfsize: bfsize_specified = TRUE; GET_ULONG(bfsize, pp->str.addr + p_offset); if ((0 == bfsize) || (MAX_SOCKET_BUFFER_SIZE < bfsize)) rts_error(VARLSTCNT(3) ERR_ILLESOCKBFSIZE, 1, bfsize); break; case iop_zibfsize: ibfsize_specified = TRUE; GET_ULONG(ibfsize, pp->str.addr + p_offset); if ((0 == ibfsize) || (MAX_INTERNAL_SOCBUF_SIZE < ibfsize)) rts_error(VARLSTCNT(3) ERR_ILLESOCKBFSIZE, 1, ibfsize); break; case iop_ioerror: n_specified++; ioerror_specified = TRUE; ioerror = *(char *)(pp->str.addr + p_offset + 1); break; case iop_zlisten: n_specified++; listen_specified = TRUE; len = *(pp->str.addr + p_offset); if (len < SA_MAXLITLEN) { memcpy(sockaddr, (char *)(pp->str.addr + p_offset + 1), len); sockaddr[len] = '\0'; } else rts_error(VARLSTCNT(6) ERR_ADDRTOOLONG, 4, len, pp->str.addr + p_offset + 1, len, SA_MAXLITLEN); break; case iop_socket: n_specified++; socket_specified = TRUE; handles_len = (int)(*(pp->str.addr + p_offset)); memcpy(handles, (char *)(pp->str.addr + p_offset + 1), handles_len); break; case iop_ipchset: #if defined(KEEP_zOS_EBCDIC) || defined(VMS) if ((iconv_t)0 != iod->input_conv_cd) ICONV_CLOSE_CD(iod->input_conv_cd); SET_CODE_SET(iod->in_code_set, (char *)(pp->str.addr + p_offset + 1)); if (DEFAULT_CODE_SET != iod->in_code_set) ICONV_OPEN_CD(iod->input_conv_cd, INSIDE_CH_SET, (char *)(pp->str.addr + p_offset + 1)); #endif break; case iop_opchset: #if defined(KEEP_zOS_EBCDIC) || defined(VMS) if ((iconv_t)0 != iod->output_conv_cd) ICONV_CLOSE_CD(iod->output_conv_cd); SET_CODE_SET(iod->out_code_set, (char *)(pp->str.addr + p_offset + 1)); if (DEFAULT_CODE_SET != iod->out_code_set) ICONV_OPEN_CD(iod->output_conv_cd, (char *)(pp->str.addr + p_offset + 1), INSIDE_CH_SET); #endif break; case iop_zff: if (MAX_ZFF_LEN >= (zff_len = (int4)(unsigned char)*(pp->str.addr + p_offset))) memcpy(zff_buffer, (char *)(pp->str.addr + p_offset + 1), zff_len); else rts_error(VARLSTCNT(4) ERR_ZFF2MANY, 2, zff_len, MAX_ZFF_LEN); break; case iop_znoff: zff_len = 0; break; case iop_length: GET_LONG(length, pp->str.addr + p_offset); if (length < 0) rts_error(VARLSTCNT(1) ERR_DEVPARMNEG); iod->length = length; break; case iop_width: /* SOCKET WIDTH is handled the same way as TERMINAL WIDTH */ GET_LONG(width, pp->str.addr + p_offset); if (width < 0) rts_error(VARLSTCNT(1) ERR_DEVPARMNEG); if (0 == width) { iod->width = TCPDEF_WIDTH; iod->wrap = FALSE; } else { iod->width = width; iod->wrap = TRUE; } break; case iop_wrap: iod->wrap = TRUE; break; case iop_nowrap: iod->wrap = FALSE; break; case iop_morereadtime: /* Time in milliseconds socket read will wait for more data before returning */ GET_LONG(moreread_timeout, pp->str.addr + p_offset); if (-1 == moreread_timeout) moreread_timeout = DEFAULT_MOREREAD_TIMEOUT; else if (-1 > moreread_timeout) rts_error(VARLSTCNT(1) ERR_DEVPARMNEG); else if (MAX_MOREREAD_TIMEOUT < moreread_timeout) rts_error(VARLSTCNT(3) ERR_MRTMAXEXCEEDED, 1, MAX_MOREREAD_TIMEOUT); moreread_specified = TRUE; break; default: /* ignore deviceparm */ break; } p_offset += ((io_params_size[ch] == IOP_VAR_SIZE) ? (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]); } /* ------ return immediately if no flag, worth a check because it is mostly true ------------ */ if (1 == p_offset) return; /* ------------------------------ compatibility verification -------------------------------- */ if ((socket_specified) && ((n_specified > 2) || ((2 == n_specified) && (0 >= delimiter_len)))) { rts_error(VARLSTCNT(8) ERR_ACOMPTBINC, 6, LEN_AND_LIT("SOCKET"), LEN_AND_LIT("DELIMITER"), LEN_AND_LIT("USE")); return; } if (connect_specified && listen_specified) { rts_error(VARLSTCNT(8) ERR_ABNCOMPTINC, 6, LEN_AND_LIT("CONNECT"), LEN_AND_LIT("ZLISTEN"), LEN_AND_LIT("USE")); return; } if (delay_specified && nodelay_specified) { rts_error(VARLSTCNT(8) ERR_ABNCOMPTINC, 6, LEN_AND_LIT("DELAY"), LEN_AND_LIT("NODELAY"), LEN_AND_LIT("OPEN")); return; } /* ------------------ make a local copy of device structure to play with -------------------- */ d_socket_struct_len = SIZEOF(d_socket_struct) + (SIZEOF(socket_struct) * (gtm_max_sockets - 1)); memcpy(newdsocket, dsocketptr, d_socket_struct_len); /* --------------- handle the two special cases attach/detach first ------------------------- */ if (detach_specified) { if (1 < n_specified) { rts_error(VARLSTCNT(6) ERR_ANCOMPTINC, 4, LEN_AND_LIT("DETACH"), LEN_AND_LIT("USE")); return; } if (NULL == socket_pool) iosocket_poolinit(); iosocket_switch(handled, handled_len, newdsocket, socket_pool); memcpy(dsocketptr, newdsocket, d_socket_struct_len); if (0 > dsocketptr->current_socket) { io_curr_device.in = io_std_device.in; io_curr_device.out = io_std_device.out; } return; /* detach can only be specified by itself */ } if (attach_specified) { /* NOTE: A socket could be moved from one device to another using DETACH/ATTACH. A socket does not carry I[O]CHSET with * it while being moved. Such a socket will use the I[O]CHSET of the device it is ATTACHed to. If there is input still * buffered, this may cause unintentional consequences in the application if I[O]CHSET changes. GT.M does not detect * (or report) a change in I[O]CHSET due to DETACH/ATTACH. */ if (1 < n_specified) { rts_error(VARLSTCNT(6) ERR_ANCOMPTINC, 4, LEN_AND_LIT("ATTACH"), LEN_AND_LIT("USE")); return; } if (NULL == socket_pool) { rts_error(VARLSTCNT(4) ERR_SOCKNOTFND, 2, handlea_len, handlea); return; } iosocket_switch(handlea, handlea_len, socket_pool, newdsocket); memcpy(dsocketptr, newdsocket, d_socket_struct_len); return; /* attach can only be specified by itself */ } /* ------------ create/identify the socket to work on and make a local copy ----------------- */ if (create_new_socket = (listen_specified || connect_specified)) /* real "=" */ { /* allocate the structure for a new socket */ if (NULL == (socketptr = iosocket_create(sockaddr, bfsize, -1))) return; /* give the new socket a handle */ iosocket_handle(handles, &handles_len, TRUE, dsocketptr); socketptr->handle_len = handles_len; memcpy(socketptr->handle, handles, handles_len); socketptr->dev = newdsocket; /* use newdsocket temporarily for the sake of bind/connect */ } else { if (socket_specified) { /* use the socket flag to identify which socket to apply changes */ if (0 > (index = iosocket_handle(handles, &handles_len, FALSE, newdsocket))) { rts_error(VARLSTCNT(4) ERR_SOCKNOTFND, 2, handles_len, handles); return; } newdsocket->current_socket = index; socketptr = newdsocket->socket[index]; } else { socketptr = newdsocket->socket[newdsocket->current_socket]; if (newdsocket->n_socket <= newdsocket->current_socket) { assert(FALSE); rts_error(VARLSTCNT(4) ERR_CURRSOCKOFR, 2, newdsocket->current_socket, newdsocket->n_socket); return; } } } newsocket = *socketptr; /* ---------------------- apply changes to the local copy of the socket --------------------- */ if (0 <= delimiter_len) { iosocket_delimiter(delimiter_buffer, delimiter_len, &newsocket, (0 == delimiter_len)); /* The delimiter has changed. The iosocket_readfl/write routine won't notice so we have to do the UTF16xx conversion since we changed it. */ DBGSOCK2((stdout, "socuse: Delimiter(s) replaced - num delims: %d delimiter_len: %d ichset: %d ochset: %d\n", newsocket.n_delimiter, delimiter_len, iod->ichset, iod->ochset)); if (0 < delimiter_len) { if (!newsocket.first_read && (CHSET_UTF16BE == iod->ichset || CHSET_UTF16LE == iod->ichset)) { /* We have been reading with this socket so convert this new delimiter set */ DBGSOCK2((stdout, "socuse: Converting new delimiters for input\n")); iosocket_delim_conv(&newsocket, iod->ichset); } if (!newsocket.first_write && (CHSET_UTF16BE == iod->ochset || CHSET_UTF16LE == iod->ochset)) { /* We have been writing with this socket so convert the new default output delimiter */ DBGSOCK2((stdout, "socuse: Converting new delimiters for output\n")); if (newsocket.first_read || (CHSET_UTF16BE != iod->ichset && CHSET_UTF16LE != iod->ichset)) { /* Need to do conversion as iosocket_delim_conv above didn't do it for us */ DBGSOCK2((stdout, "socuse: running convert for write since input didn't do it\n")); new_len = gtm_conv(chset_desc[CHSET_UTF8], chset_desc[iod->ochset], &newsocket.delimiter[0], NULL, NULL); if (MAX_DELIM_LEN < new_len) { rts_error(VARLSTCNT(1) ERR_DELIMSIZNA); return; } } else { DBGSOCK2((stdout, "socuse: using previous length from read conversion\n")); new_len = newsocket.idelimiter[0].len; } newsocket.odelimiter0.len = new_len; UNICODE_ONLY(newsocket.odelimiter0.char_len = newsocket.delimiter[0].char_len); newsocket.odelimiter0.addr = malloc(new_len); memcpy(newsocket.odelimiter0.addr, (newsocket.first_read ? (char *)stringpool.free : newsocket.idelimiter[0].addr), new_len); } } } if (iod->wrap && 0 != newsocket.n_delimiter && iod->width < newsocket.delimiter[0].len) rts_error(VARLSTCNT(4) ERR_DELIMWIDTH, 2, iod->width, newsocket.delimiter[0].len); if (0 <= zff_len && /* ZFF or ZNOFF specified */ 0 < (newsocket.zff.len = zff_len)) /* assign the new ZFF len, might be 0 from ZNOFF, or ZFF="" */ { /* ZFF="non-zero-len-string" specified */ if (CHSET_UTF16BE == iod->ochset || CHSET_UTF16LE == iod->ochset) /* need conversion of ZFF */ { DBGSOCK2((stdout, "socuse: Converting zff\n")); lcl_zff.addr = (char *)zff_buffer; lcl_zff.len = zff_len; new_len = gtm_conv(chset_desc[CHSET_UTF8], chset_desc[iod->ochset], &lcl_zff, NULL, NULL); if (MAX_ZFF_LEN < new_len) rts_error(VARLSTCNT(4) ERR_ZFF2MANY, 2, new_len, MAX_ZFF_LEN); if (NULL == newsocket.zff.addr) /* we rely on newsocket.zff.addr being set to 0 in iosocket_create() */ newsocket.zff.addr = (char *)malloc(MAX_ZFF_LEN); newsocket.zff.len = new_len; UNICODE_ONLY(newsocket.zff.char_len = 0); /* don't care */ memcpy(newsocket.zff.addr, stringpool.free, new_len); } else { /* Store parm without conversion */ if (gtm_utf8_mode) /* Check if ZFF has any invalid UTF-8 character */ { /* Note: the ZFF string originates from the source program, so is in UTF-8 mode or M mode regardless of OCHSET of this device. ZFF is output on WRITE # command, and MUST contain valid UTF-8 sequence. This validation is handled by gtm_conv in the path above. */ utf8_len_strict(zff_buffer, zff_len); } if (NULL == newsocket.zff.addr) /* we rely on newsocket.zff.addr being set to 0 in iosocket_create() */ newsocket.zff.addr = (char *)malloc(MAX_ZFF_LEN); memcpy(newsocket.zff.addr, zff_buffer, zff_len); } } if (ioerror_specified) newsocket.ioerror = ('T' == ioerror || 't' == ioerror); if (nodelay_specified || delay_specified) newsocket.nodelay = nodelay_specified; /* defaults to DELAY */ if (ibfsize_specified) newsocket.bufsiz = ibfsize; if (moreread_specified) { newsocket.moreread_timeout = moreread_timeout; newsocket.def_moreread_timeout = TRUE; /* need to know this was user-defined in iosocket_readfl.c */ } if (!create_new_socket) { /* these changes apply to only pre-existing sockets */ if (bfsize_specified) newsocket.buffer_size = bfsize; #ifdef TCP_NODELAY nodelay = newsocket.nodelay ? 1 : 0; if ((socketptr->nodelay != newsocket.nodelay) && (-1 == tcp_routines.aa_setsockopt(newsocket.sd, IPPROTO_TCP, TCP_NODELAY, &nodelay, SIZEOF(nodelay)))) { save_errno = errno; errptr = (char *)STRERROR(save_errno); rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("TCP_NODELAY"), save_errno, LEN_AND_STR(errptr)); return; } #endif if ((socketptr->bufsiz != newsocket.bufsiz) && (-1 == tcp_routines.aa_setsockopt(newsocket.sd, SOL_SOCKET, SO_RCVBUF, &newsocket.bufsiz, SIZEOF(newsocket.bufsiz)))) { save_errno = errno; errptr = (char *)STRERROR(save_errno); rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("SO_RCVBUF"), save_errno, LEN_AND_STR(errptr)); return; } if (socketptr->buffer_size != newsocket.buffer_size) { if (socketptr->buffered_length > bfsize) rts_error(VARLSTCNT(4) ERR_SOCKBFNOTEMPTY, 2, bfsize, socketptr->buffered_length); newsocket.buffer = (char *)malloc(bfsize); if (0 < socketptr->buffered_length) { memcpy(newsocket.buffer, socketptr->buffer + socketptr->buffered_offset, socketptr->buffered_length); newsocket.buffered_offset = 0; } } } /* -------------------------------------- action -------------------------------------------- */ if ((listen_specified && (!iosocket_bind(&newsocket, NO_M_TIMEOUT, ibfsize_specified))) || (connect_specified && (!iosocket_connect(&newsocket, 0, ibfsize_specified)))) { /* error message should be printed from bind/connect */ if (socketptr->sd > 0) (void)tcp_routines.aa_close(socketptr->sd); iosocket_delimiter((unsigned char *)NULL, 0, &newsocket, TRUE); if (NULL != socketptr->zff.addr) free(socketptr->zff.addr); if (NULL != socketptr->buffer) free(socketptr->buffer); free(socketptr); return; } /* ------------------------------------ commit changes -------------------------------------- */ if (create_new_socket) { if (gtm_max_sockets <= newdsocket->n_socket) { rts_error(VARLSTCNT(3) ERR_SOCKMAX, 1, gtm_max_sockets); return; } /* a new socket is created. so add to the list */ newsocket.dev = dsocketptr; newdsocket->socket[newdsocket->n_socket++] = socketptr; newdsocket->current_socket = newdsocket->n_socket - 1; } else if (socketptr->buffer_size != newsocket.buffer_size) free(socketptr->buffer); *socketptr = newsocket; memcpy(dsocketptr, newdsocket, d_socket_struct_len); return; }
void db_init(gd_region *reg, sgmnt_data_ptr_t tsd) { static boolean_t mutex_init_done = FALSE; boolean_t is_bg, read_only; char machine_name[MAX_MCNAMELEN]; file_control *fc; int gethostname_res, stat_res, mm_prot; int4 status, semval, dblksize, fbwsize; sm_long_t status_l; sgmnt_addrs *csa; sgmnt_data_ptr_t csd; struct sembuf sop[3]; struct stat stat_buf; union semun semarg; struct semid_ds semstat; struct shmid_ds shmstat; struct statvfs dbvfs; uint4 sopcnt; unix_db_info *udi; #ifdef periodic_timer_removed void periodic_flush_check(); #endif error_def(ERR_CLSTCONFLICT); error_def(ERR_CRITSEMFAIL); error_def(ERR_DBNAMEMISMATCH); error_def(ERR_DBIDMISMATCH); error_def(ERR_NLMISMATCHCALC); error_def(ERR_REQRUNDOWN); error_def(ERR_SYSCALL); assert(tsd->acc_meth == dba_bg || tsd->acc_meth == dba_mm); is_bg = (dba_bg == tsd->acc_meth); read_only = reg->read_only; new_dbinit_ipc = FALSE; /* we did not create a new ipc resource */ udi = FILE_INFO(reg); memset(machine_name, 0, sizeof(machine_name)); if (GETHOSTNAME(machine_name, MAX_MCNAMELEN, gethostname_res)) rts_error(VARLSTCNT(5) ERR_TEXT, 2, LEN_AND_LIT("Unable to get the hostname"), errno); assert(strlen(machine_name) < MAX_MCNAMELEN); csa = &udi->s_addrs; csa->db_addrs[0] = csa->db_addrs[1] = csa->lock_addrs[0] = NULL; /* to help in dbinit_ch and gds_rundown */ reg->opening = TRUE; /* * Create ftok semaphore for this region. * We do not want to make ftok counter semaphore to be 2 for on mupip journal recover process. */ if (!ftok_sem_get(reg, !mupip_jnl_recover, GTM_ID, FALSE)) rts_error(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(reg)); /* * At this point we have ftok_semid sempahore based on ftok key. * Any ftok conflicted region will block at this point. * Say, a.dat and b.dat both has same ftok and we have process A to access a.dat and * process B to access b.dat. In this case only one can continue to do db_init() */ fc = reg->dyn.addr->file_cntl; fc->file_type = reg->dyn.addr->acc_meth; fc->op = FC_READ; fc->op_buff = (sm_uc_ptr_t)tsd; fc->op_len = sizeof(*tsd); fc->op_pos = 1; dbfilop(fc); /* Read file header */ udi->shmid = tsd->shmid; udi->semid = tsd->semid; udi->sem_ctime = tsd->sem_ctime.ctime; udi->shm_ctime = tsd->shm_ctime.ctime; dbsecspc(reg, tsd); /* Find db segment size */ if (!mupip_jnl_recover) { if (INVALID_SEMID == udi->semid) { if (0 != udi->sem_ctime || INVALID_SHMID != udi->shmid || 0 != udi->shm_ctime) /* We must have somthing wrong in protocol or, code, if this happens */ GTMASSERT; /* * Create new semaphore using IPC_PRIVATE. System guarantees a unique id. */ if (-1 == (udi->semid = semget(IPC_PRIVATE, FTOK_SEM_PER_ID, RWDALL | IPC_CREAT))) { udi->semid = INVALID_SEMID; rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, LEN_AND_LIT("Error with database control semget"), errno); } udi->shmid = INVALID_SHMID; /* reset shmid so dbinit_ch does not get confused in case we go there */ new_dbinit_ipc = TRUE; tsd->semid = udi->semid; semarg.val = GTM_ID; /* * Following will set semaphore number 2 (=FTOK_SEM_PER_ID - 1) value as GTM_ID. * In case we have orphaned semaphore for some reason, mupip rundown will be * able to identify GTM semaphores from the value and can remove. */ if (-1 == semctl(udi->semid, FTOK_SEM_PER_ID - 1, SETVAL, semarg)) rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, LEN_AND_LIT("Error with database control semctl SETVAL"), errno); /* * Warning: We must read the sem_ctime using IPC_STAT after SETVAL, which changes it. * We must NOT do any more SETVAL after this. Our design is to use * sem_ctime as creation time of semaphore. */ semarg.buf = &semstat; if (-1 == semctl(udi->semid, FTOK_SEM_PER_ID - 1, IPC_STAT, semarg)) rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, LEN_AND_LIT("Error with database control semctl IPC_STAT"), errno); tsd->sem_ctime.ctime = udi->sem_ctime = semarg.buf->sem_ctime; } else { if (INVALID_SHMID == udi->shmid) /* if mu_rndwn_file gets standalone access of this region and * somehow mupip process crashes, we can have semid != -1 but shmid == -1 */ rts_error(VARLSTCNT(10) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(tsd->machine_name), ERR_TEXT, 2, LEN_AND_LIT("semid is valid but shmid is invalid")); semarg.buf = &semstat; if (-1 == semctl(udi->semid, 0, IPC_STAT, semarg)) /* file header has valid semid but semaphore does not exists */ rts_error(VARLSTCNT(6) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(tsd->machine_name)); else if (semarg.buf->sem_ctime != tsd->sem_ctime.ctime) rts_error(VARLSTCNT(10) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(tsd->machine_name), ERR_TEXT, 2, LEN_AND_LIT("sem_ctime does not match")); if (-1 == shmctl(udi->shmid, IPC_STAT, &shmstat)) rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, LEN_AND_LIT("Error with database control shmctl"), errno); else if (shmstat.shm_ctime != tsd->shm_ctime.ctime) rts_error(VARLSTCNT(10) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(tsd->machine_name), ERR_TEXT, 2, LEN_AND_LIT("shm_ctime does not match")); } /* We already have ftok semaphore of this region, so just plainly do semaphore operation */ /* This is the database access control semaphore for any region */ sop[0].sem_num = 0; sop[0].sem_op = 0; /* Wait for 0 */ sop[1].sem_num = 0; sop[1].sem_op = 1; /* Lock */ sopcnt = 2; if (!read_only) { sop[2].sem_num = 1; sop[2].sem_op = 1; /* increment r/w access counter */ sopcnt = 3; } sop[0].sem_flg = sop[1].sem_flg = sop[2].sem_flg = SEM_UNDO | IPC_NOWAIT; SEMOP(udi->semid, sop, sopcnt, status); if (-1 == status) { errno_save = errno; gtm_putmsg(VARLSTCNT(4) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg)); rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semop()"), CALLFROM, errno_save); } } else /* for mupip_jnl_recover we were already in mu_rndwn_file and got "semid" semaphore */ { if (INVALID_SEMID == udi->semid || 0 == udi->sem_ctime) /* make sure mu_rndwn_file() has reset created semaphore for standalone access */ GTMASSERT; if (INVALID_SHMID != udi->shmid || 0 != udi->shm_ctime) /* make sure mu_rndwn_file() has reset shared memory */ GTMASSERT; udi->shmid = INVALID_SHMID; /* reset shmid so dbinit_ch does not get confused in case we go there */ new_dbinit_ipc = TRUE; } sem_incremented = TRUE; if (new_dbinit_ipc) { /* Create new shared memory using IPC_PRIVATE. System guarantees a unique id */ #ifdef __MVS__ if (-1 == (status_l = udi->shmid = shmget(IPC_PRIVATE, ROUND_UP(reg->sec_size, MEGA_BOUND), __IPC_MEGA | IPC_CREAT | RWDALL))) #else if (-1 == (status_l = udi->shmid = shmget(IPC_PRIVATE, reg->sec_size, RWDALL | IPC_CREAT))) #endif { udi->shmid = status_l = INVALID_SHMID; rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, LEN_AND_LIT("Error with database shmget"), errno); } tsd->shmid = udi->shmid; if (-1 == shmctl(udi->shmid, IPC_STAT, &shmstat)) rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, LEN_AND_LIT("Error with database control shmctl"), errno); tsd->shm_ctime.ctime = udi->shm_ctime = shmstat.shm_ctime; } #ifdef DEBUG_DB64 status_l = (sm_long_t)(csa->db_addrs[0] = (sm_uc_ptr_t)do_shmat(udi->shmid, next_smseg, SHM_RND)); next_smseg = (sm_uc_ptr_t)ROUND_UP((sm_long_t)(next_smseg + reg->sec_size), SHMAT_ADDR_INCS); #else status_l = (sm_long_t)(csa->db_addrs[0] = (sm_uc_ptr_t)do_shmat(udi->shmid, 0, SHM_RND)); #endif if (-1 == status_l) { rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, LEN_AND_LIT("Error attaching to database shared memory"), errno); } csa->nl = (node_local_ptr_t)csa->db_addrs[0]; csa->critical = (mutex_struct_ptr_t)(csa->db_addrs[0] + NODE_LOCAL_SIZE); assert(((int)csa->critical & 0xf) == 0); /* critical should be 16-byte aligned */ #ifdef CACHELINE_SIZE assert(0 == ((int)csa->critical & (CACHELINE_SIZE - 1))); #endif /* Note: Here we check jnl_sate from database file and its value cannot change without standalone access. * The jnl_buff buffer should be initialized irrespective of read/write process */ JNL_INIT(csa, reg, tsd); csa->backup_buffer = (backup_buff_ptr_t)(csa->db_addrs[0] + NODE_LOCAL_SPACE + JNL_SHARE_SIZE(tsd)); csa->lock_addrs[0] = (sm_uc_ptr_t)csa->backup_buffer + BACKUP_BUFFER_SIZE + 1; csa->lock_addrs[1] = csa->lock_addrs[0] + LOCK_SPACE_SIZE(tsd) - 1; csa->total_blks = tsd->trans_hist.total_blks; /* For test to see if file has extended */ if (new_dbinit_ipc) { memset(csa->nl, 0, sizeof(*csa->nl)); /* We allocated shared storage -- we have to init it */ if (JNL_ALLOWED(csa)) { /* initialize jb->cycle to a value different from initial value of jpc->cycle (0). although this is not * necessary right now, in the future, the plan is to change jnl_ensure_open() to only do a cycle mismatch * check in order to determine whether to call jnl_file_open() or not. this is in preparation for that. */ csa->jnl->jnl_buff->cycle = 1; } } if (is_bg) csd = csa->hdr = (sgmnt_data_ptr_t)(csa->lock_addrs[1] + 1 + CACHE_CONTROL_SIZE(tsd)); else { csa->acc_meth.mm.mmblk_state = (mmblk_que_heads_ptr_t)(csa->lock_addrs[1] + 1); FSTAT_FILE(udi->fd, &stat_buf, stat_res); if (-1 == stat_res) rts_error(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), errno); mm_prot = read_only ? PROT_READ : (PROT_READ | PROT_WRITE); #ifdef DEBUG_DB64 if (-1 == (sm_long_t)(csa->db_addrs[0] = (sm_uc_ptr_t)mmap((caddr_t)get_mmseg((size_t)stat_buf.st_size), (size_t)stat_buf.st_size, mm_prot, GTM_MM_FLAGS, udi->fd, (off_t)0))) rts_error(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), errno); put_mmseg((caddr_t)(csa->db_addrs[0]), (size_t)stat_buf.st_size); #else if (-1 == (sm_long_t)(csa->db_addrs[0] = (sm_uc_ptr_t)mmap((caddr_t)NULL, (size_t)stat_buf.st_size, mm_prot, GTM_MM_FLAGS, udi->fd, (off_t)0))) rts_error(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), errno); #endif csa->db_addrs[1] = csa->db_addrs[0] + stat_buf.st_size - 1; csd = csa->hdr = (sgmnt_data_ptr_t)csa->db_addrs[0]; } if (!csa->nl->glob_sec_init) { assert(new_dbinit_ipc); if (is_bg) *csd = *tsd; if (csd->machine_name[0]) /* crash occured */ { if (0 != memcmp(csd->machine_name, machine_name, MAX_MCNAMELEN)) /* crashed on some other node */ rts_error(VARLSTCNT(6) ERR_CLSTCONFLICT, 4, DB_LEN_STR(reg), LEN_AND_STR(csd->machine_name)); else rts_error(VARLSTCNT(6) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(csd->machine_name)); } if (is_bg) { bt_malloc(csa); csa->nl->cache_off = -CACHE_CONTROL_SIZE(tsd); db_csh_ini(csa); } db_csh_ref(csa); strcpy(csa->nl->machine_name, machine_name); /* machine name */ assert(MAX_REL_NAME > gtm_release_name_len); memcpy(csa->nl->now_running, gtm_release_name, gtm_release_name_len + 1); /* GT.M release name */ memcpy(csa->nl->label, GDS_LABEL, GDS_LABEL_SZ - 1); /* GDS label */ memcpy(csa->nl->fname, reg->dyn.addr->fname, reg->dyn.addr->fname_len); /* database filename */ csa->nl->creation_date_time = csd->creation.date_time; csa->nl->highest_lbm_blk_changed = -1; csa->nl->wcs_timers = -1; csa->nl->nbb = BACKUP_NOT_IN_PROGRESS; csa->nl->unique_id.uid = FILE_INFO(reg)->fileid; /* save what file we initialized this storage for */ /* save pointers in csa to access shared memory */ csa->nl->critical = (sm_off_t)((sm_uc_ptr_t)csa->critical - (sm_uc_ptr_t)csa->nl); if (JNL_ALLOWED(csa)) csa->nl->jnl_buff = (sm_off_t)((sm_uc_ptr_t)csa->jnl->jnl_buff - (sm_uc_ptr_t)csa->nl); csa->nl->backup_buffer = (sm_off_t)((sm_uc_ptr_t)csa->backup_buffer - (sm_uc_ptr_t)csa->nl); csa->nl->hdr = (sm_off_t)((sm_uc_ptr_t)csd - (sm_uc_ptr_t)csa->nl); csa->nl->lock_addrs = (sm_off_t)((sm_uc_ptr_t)csa->lock_addrs[0] - (sm_uc_ptr_t)csa->nl); if (!read_only || is_bg) { csd->trans_hist.early_tn = csd->trans_hist.curr_tn; csd->max_update_array_size = csd->max_non_bm_update_array_size = ROUND_UP2(MAX_NON_BITMAP_UPDATE_ARRAY_SIZE(csd), UPDATE_ARRAY_ALIGN_SIZE); csd->max_update_array_size += ROUND_UP2(MAX_BITMAP_UPDATE_ARRAY_SIZE, UPDATE_ARRAY_ALIGN_SIZE); /* add current db_csh counters into the cumulative counters and reset the current counters */ #define TAB_DB_CSH_ACCT_REC(COUNTER, DUMMY1, DUMMY2) \ csd->COUNTER.cumul_count += csd->COUNTER.curr_count; \ csd->COUNTER.curr_count = 0; #include "tab_db_csh_acct_rec.h" #undef TAB_DB_CSH_ACCT_REC } if (!read_only) { if (is_bg) { assert(memcmp(csd, GDS_LABEL, GDS_LABEL_SZ - 1) == 0); LSEEKWRITE(udi->fd, (off_t)0, (sm_uc_ptr_t)csd, sizeof(sgmnt_data), errno_save); if (0 != errno_save) { rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, LEN_AND_LIT("Error with database write"), errno_save); } } } reg->dyn.addr->ext_blk_count = csd->extension_size; mlk_shr_init(csa->lock_addrs[0], csd->lock_space_size, csa, (FALSE == read_only)); DEBUG_ONLY(locknl = csa->nl;) /* for DEBUG_ONLY LOCK_HIST macro */
boolean_t mu_truncate(int4 truncate_percent) { sgmnt_addrs *csa; sgmnt_data_ptr_t csd; int num_local_maps; int lmap_num, lmap_blk_num; int bml_status, sigkill; int save_errno; int ftrunc_status; uint4 jnl_status; uint4 old_total, new_total; uint4 old_free, new_free; uint4 end_blocks; int4 blks_in_lmap, blk; gtm_uint64_t before_trunc_file_size; off_t trunc_file_size; off_t padding; uchar_ptr_t lmap_addr; boolean_t was_crit; uint4 found_busy_blk; srch_blk_status bmphist; srch_blk_status *blkhist; srch_hist alt_hist; trans_num curr_tn; blk_hdr_ptr_t lmap_blk_hdr; block_id *blkid_ptr; unix_db_info *udi; jnl_private_control *jpc; jnl_buffer_ptr_t jbp; char *err_msg; intrpt_state_t prev_intrpt_state; off_t offset; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; csa = cs_addrs; csd = cs_data; if (dba_mm == csd->acc_meth) { gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_MUTRUNCNOTBG, 2, REG_LEN_STR(gv_cur_region)); return TRUE; } if ((GDSVCURR != csd->desired_db_format) || (csd->blks_to_upgrd != 0)) { gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_MUTRUNCNOV4, 2, REG_LEN_STR(gv_cur_region)); return TRUE; } if (csa->ti->free_blocks < (truncate_percent * csa->ti->total_blks / 100)) { gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_MUTRUNCNOSPACE, 3, REG_LEN_STR(gv_cur_region), truncate_percent); return TRUE; } /* already checked for parallel truncates on this region --- see mupip_reorg.c */ gv_target = NULL; assert(csa->nl->trunc_pid == process_id); assert(dba_mm != csd->acc_meth); old_total = csa->ti->total_blks; old_free = csa->ti->free_blocks; sigkill = 0; found_busy_blk = 0; memset(&alt_hist, 0, SIZEOF(alt_hist)); /* null-initialize history */ assert(csd->bplmap == BLKS_PER_LMAP); end_blocks = old_total % BLKS_PER_LMAP; /* blocks in the last lmap (first one we start scanning) */ if (0 == end_blocks) end_blocks = BLKS_PER_LMAP; num_local_maps = DIVIDE_ROUND_UP(old_total, BLKS_PER_LMAP); /* ======================================== PHASE 1 ======================================== */ for (lmap_num = num_local_maps - 1; (lmap_num > 0 && !found_busy_blk); lmap_num--) { if (mu_ctrly_occurred || mu_ctrlc_occurred) return TRUE; assert(csa->ti->total_blks >= old_total); /* otherwise, a concurrent truncate happened... */ if (csa->ti->total_blks != old_total) /* Extend (likely called by mupip extend) -- don't truncate */ { gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_MUTRUNCNOSPACE, 3, REG_LEN_STR(gv_cur_region), truncate_percent); return TRUE; } lmap_blk_num = lmap_num * BLKS_PER_LMAP; if (csa->nl->highest_lbm_with_busy_blk >= lmap_blk_num) { found_busy_blk = lmap_blk_num; break; } blks_in_lmap = (lmap_num == num_local_maps - 1) ? end_blocks : BLKS_PER_LMAP; /* Loop through non-bitmap blocks of this lmap, do recycled2free */ DBGEHND((stdout, "DBG:: lmap_num = [%lu], lmap_blk_num = [%lu], blks_in_lmap = [%lu]\n", lmap_num, lmap_blk_num, blks_in_lmap)); for (blk = 1; blk < blks_in_lmap && blk != -1 && !found_busy_blk;) { t_begin(ERR_MUTRUNCFAIL, UPDTRNS_DB_UPDATED_MASK); for (;;) /* retry loop for recycled to free transactions */ { curr_tn = csd->trans_hist.curr_tn; /* Read the nth local bitmap into memory */ bmphist.blk_num = lmap_blk_num; bmphist.buffaddr = t_qread(bmphist.blk_num, &bmphist.cycle, &bmphist.cr); lmap_blk_hdr = (blk_hdr_ptr_t)bmphist.buffaddr; if (!(bmphist.buffaddr) || (BM_SIZE(BLKS_PER_LMAP) != lmap_blk_hdr->bsiz)) { /* Could not read the block successfully. Retry. */ t_retry((enum cdb_sc)rdfail_detail); continue; } lmap_addr = bmphist.buffaddr + SIZEOF(blk_hdr); /* starting from the hint (blk itself), find the first busy or recycled block */ blk = bml_find_busy_recycled(blk, lmap_addr, blks_in_lmap, &bml_status); assert(blk < BLKS_PER_LMAP); if (blk == -1 || blk >= blks_in_lmap) { /* done with this lmap, continue to next */ t_abort(gv_cur_region, csa); break; } else if (BLK_BUSY == bml_status || csa->nl->highest_lbm_with_busy_blk >= lmap_blk_num) { /* stop processing blocks... skip ahead to phase 2 */ found_busy_blk = lmap_blk_num; t_abort(gv_cur_region, csa); break; } else if (BLK_RECYCLED == bml_status) { /* Write PBLK records for recycled blocks only if before_image journaling is * enabled. t_end() takes care of checking if journaling is enabled and * writing PBLK record. We have to at least mark the recycled block as free. */ RESET_UPDATE_ARRAY; update_trans = UPDTRNS_DB_UPDATED_MASK; *((block_id *)update_array_ptr) = blk; update_array_ptr += SIZEOF(block_id); *(int *)update_array_ptr = 0; alt_hist.h[1].blk_num = 0; alt_hist.h[0].level = 0; alt_hist.h[0].cse = NULL; alt_hist.h[0].tn = curr_tn; alt_hist.h[0].blk_num = lmap_blk_num + blk; alt_hist.h[0].buffaddr = t_qread(alt_hist.h[0].blk_num, &alt_hist.h[0].cycle, &alt_hist.h[0].cr); if (!alt_hist.h[0].buffaddr) { t_retry((enum cdb_sc)rdfail_detail); continue; } if (!t_recycled2free(&alt_hist.h[0])) { t_retry(cdb_sc_lostbmlcr); continue; } t_write_map(&bmphist, (unsigned char *)update_array, curr_tn, 0); /* Set the opcode for INCTN record written by t_end() */ inctn_opcode = inctn_blkmarkfree; if ((trans_num)0 == t_end(&alt_hist, NULL, TN_NOT_SPECIFIED)) continue; /* block processed, scan from the next one */ blk++; break; } else { assert(t_tries < CDB_STAGNATE); t_retry(cdb_sc_badbitmap); continue; } } /* END recycled2free retry loop */ } /* END scanning blocks of this particular lmap */ /* Write PBLK for the bitmap block, in case it hasn't been written i.e. t_end() was never called above */ /* Do a transaction that just increments the bitmap block's tn so that t_end() can do its thing */ DBGEHND((stdout, "DBG:: bitmap block inctn -- lmap_blk_num = [%lu]\n", lmap_blk_num)); t_begin(ERR_MUTRUNCFAIL, UPDTRNS_DB_UPDATED_MASK); for (;;) { RESET_UPDATE_ARRAY; BLK_ADDR(blkid_ptr, SIZEOF(block_id), block_id); *blkid_ptr = 0; update_trans = UPDTRNS_DB_UPDATED_MASK; inctn_opcode = inctn_mu_reorg; /* inctn_mu_truncate */ curr_tn = csd->trans_hist.curr_tn; blkhist = &alt_hist.h[0]; blkhist->blk_num = lmap_blk_num; blkhist->tn = curr_tn; blkhist->cse = NULL; /* start afresh (do not use value from previous retry) */ /* Read the nth local bitmap into memory */ blkhist->buffaddr = t_qread(lmap_blk_num, (sm_int_ptr_t)&blkhist->cycle, &blkhist->cr); lmap_blk_hdr = (blk_hdr_ptr_t)blkhist->buffaddr; if (!(blkhist->buffaddr) || (BM_SIZE(BLKS_PER_LMAP) != lmap_blk_hdr->bsiz)) { /* Could not read the block successfully. Retry. */ t_retry((enum cdb_sc)rdfail_detail); continue; } t_write_map(blkhist, (unsigned char *)blkid_ptr, curr_tn, 0); blkhist->blk_num = 0; /* create empty history for bitmap block */ if ((trans_num)0 == t_end(&alt_hist, NULL, TN_NOT_SPECIFIED)) continue; break; } } /* END scanning lmaps */ /* ======================================== PHASE 2 ======================================== */ assert(!csa->now_crit); for (;;) { /* wait for FREEZE, we don't want to truncate a frozen database */ grab_crit(gv_cur_region); if (FROZEN_CHILLED(cs_data)) DO_CHILLED_AUTORELEASE(csa, cs_data); if (!FROZEN(cs_data) && !IS_REPL_INST_FROZEN) break; rel_crit(gv_cur_region); while (FROZEN(cs_data) || IS_REPL_INST_FROZEN) { hiber_start(1000); if (FROZEN_CHILLED(cs_data) && CHILLED_AUTORELEASE(cs_data)) break; } } assert(csa->nl->trunc_pid == process_id); /* Flush pending updates to disk. If this is not done, old updates can be flushed AFTER ftruncate, extending the file. */ if (!wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH | WCSFLU_MSYNC_DB)) { assert(FALSE); gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_BUFFLUFAILED, 4, LEN_AND_LIT("MUPIP REORG TRUNCATE"), DB_LEN_STR(gv_cur_region)); rel_crit(gv_cur_region); return FALSE; } csa->nl->highest_lbm_with_busy_blk = MAX(found_busy_blk, csa->nl->highest_lbm_with_busy_blk); assert(IS_BITMAP_BLK(csa->nl->highest_lbm_with_busy_blk)); new_total = MIN(old_total, csa->nl->highest_lbm_with_busy_blk + BLKS_PER_LMAP); if (mu_ctrly_occurred || mu_ctrlc_occurred) { rel_crit(gv_cur_region); return TRUE; } else if (csa->ti->total_blks != old_total || new_total == old_total) { assert(csa->ti->total_blks >= old_total); /* Better have been an extend, not a truncate... */ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_MUTRUNCNOSPACE, 3, REG_LEN_STR(gv_cur_region), truncate_percent); rel_crit(gv_cur_region); return TRUE; } else if (GDSVCURR != csd->desired_db_format || csd->blks_to_upgrd != 0 || !csd->fully_upgraded) { gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_MUTRUNCNOV4, 2, REG_LEN_STR(gv_cur_region)); rel_crit(gv_cur_region); return TRUE; } else if (SNAPSHOTS_IN_PROG(csa->nl)) { gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_MUTRUNCSSINPROG, 2, REG_LEN_STR(gv_cur_region)); rel_crit(gv_cur_region); return TRUE; } else if (BACKUP_NOT_IN_PROGRESS != cs_addrs->nl->nbb) { gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_MUTRUNCBACKINPROG, 2, REG_LEN_STR(gv_cur_region)); rel_crit(gv_cur_region); return TRUE; } DEFER_INTERRUPTS(INTRPT_IN_TRUNC, prev_intrpt_state); if (JNL_ENABLED(csa)) { /* Write JRT_TRUNC and INCTN records */ if (!jgbl.dont_reset_gbl_jrec_time) SET_GBL_JREC_TIME; /* needed before jnl_ensure_open as that can write jnl records */ jpc = csa->jnl; jbp = jpc->jnl_buff; /* Before writing to jnlfile, adjust jgbl.gbl_jrec_time if needed to maintain time order * of jnl records. This needs to be done BEFORE the jnl_ensure_open as that could write * journal records (if it decides to switch to a new journal file). */ ADJUST_GBL_JREC_TIME(jgbl, jbp); jnl_status = jnl_ensure_open(gv_cur_region, csa); if (SS_NORMAL != jnl_status) send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region)); else { if (0 == jpc->pini_addr) jnl_put_jrt_pini(csa); jnl_write_trunc_rec(csa, old_total, csa->ti->free_blocks, new_total); inctn_opcode = inctn_mu_reorg; jnl_write_inctn_rec(csa); jnl_status = jnl_flush(gv_cur_region); if (SS_NORMAL != jnl_status) { send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd), ERR_TEXT, 2, RTS_ERROR_TEXT("Error with journal flush during mu_truncate"), jnl_status); assert(NOJNL == jpc->channel); /* jnl file lost has been triggered */ } } } /* Good to go ahead and REALLY truncate (reduce total_blks, clear cache_array, FTRUNCATE) */ curr_tn = csa->ti->curr_tn; CHECK_TN(csa, csd, curr_tn); udi = FILE_INFO(gv_cur_region); /* Information used by recover_truncate to check if the file size and csa->ti->total_blks are INCONSISTENT */ trunc_file_size = BLK_ZERO_OFF(csd->start_vbn) + ((off_t)csd->blk_size * (new_total + 1)); csd->after_trunc_total_blks = new_total; csd->before_trunc_free_blocks = csa->ti->free_blocks; csd->before_trunc_total_blks = old_total; /* Flags interrupted truncate for recover_truncate */ /* file size and total blocks: INCONSISTENT */ csa->ti->total_blks = new_total; /* past the point of no return -- shared memory intact */ assert(csa->ti->free_blocks >= DELTA_FREE_BLOCKS(old_total, new_total)); csa->ti->free_blocks -= DELTA_FREE_BLOCKS(old_total, new_total); new_free = csa->ti->free_blocks; KILL_TRUNC_TEST(WBTEST_CRASH_TRUNCATE_1); /* 55 : Issue a kill -9 before 1st fsync */ fileheader_sync(gv_cur_region); DB_FSYNC(gv_cur_region, udi, csa, db_fsync_in_prog, save_errno); CHECK_DBSYNC(gv_cur_region, save_errno); /* past the point of no return -- shared memory deleted */ KILL_TRUNC_TEST(WBTEST_CRASH_TRUNCATE_2); /* 56 : Issue a kill -9 after 1st fsync */ clear_cache_array(csa, csd, gv_cur_region, new_total, old_total); offset = (off_t)BLK_ZERO_OFF(csd->start_vbn) + (off_t)new_total * csd->blk_size; save_errno = db_write_eof_block(udi, udi->fd, csd->blk_size, offset, &(TREF(dio_buff))); if (0 != save_errno) { err_msg = (char *)STRERROR(errno); rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_MUTRUNCERROR, 4, REG_LEN_STR(gv_cur_region), LEN_AND_STR(err_msg)); return FALSE; } KILL_TRUNC_TEST(WBTEST_CRASH_TRUNCATE_3); /* 57 : Issue a kill -9 after reducing csa->ti->total_blks, before FTRUNCATE */ /* Execute an ftruncate() and truncate the DB file * ftruncate() is a SYSTEM CALL on almost all platforms (except SunOS) * It ignores kill -9 signal till its operation is completed. * So we can safely assume that the result of ftruncate() will be complete. */ FTRUNCATE(FILE_INFO(gv_cur_region)->fd, trunc_file_size, ftrunc_status); if (0 != ftrunc_status) { err_msg = (char *)STRERROR(errno); rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_MUTRUNCERROR, 4, REG_LEN_STR(gv_cur_region), LEN_AND_STR(err_msg)); /* should go through recover_truncate now, which will again try to FTRUNCATE */ return FALSE; } /* file size and total blocks: CONSISTENT (shrunk) */ KILL_TRUNC_TEST(WBTEST_CRASH_TRUNCATE_4); /* 58 : Issue a kill -9 after FTRUNCATE, before 2nd fsync */ csa->nl->root_search_cycle++; /* Force concurrent processes to restart in t_end/tp_tend to make sure no one * tries to commit updates past the end of the file. Bitmap validations together * with highest_lbm_with_busy_blk should actually be sufficient, so this is * just to be safe. */ csd->before_trunc_total_blks = 0; /* indicate CONSISTENT */ /* Increment TN */ assert(csa->ti->early_tn == csa->ti->curr_tn); csd->trans_hist.early_tn = csd->trans_hist.curr_tn + 1; INCREMENT_CURR_TN(csd); fileheader_sync(gv_cur_region); DB_FSYNC(gv_cur_region, udi, csa, db_fsync_in_prog, save_errno); KILL_TRUNC_TEST(WBTEST_CRASH_TRUNCATE_5); /* 58 : Issue a kill -9 after after 2nd fsync */ CHECK_DBSYNC(gv_cur_region, save_errno); ENABLE_INTERRUPTS(INTRPT_IN_TRUNC, prev_intrpt_state); curr_tn = csa->ti->curr_tn; rel_crit(gv_cur_region); send_msg_csa(CSA_ARG(csa) VARLSTCNT(7) ERR_MUTRUNCSUCCESS, 5, DB_LEN_STR(gv_cur_region), old_total, new_total, &curr_tn); util_out_print("Truncated region: !AD. Reduced total blocks from [!UL] to [!UL]. Reduced free blocks from [!UL] to [!UL].", FLUSH, REG_LEN_STR(gv_cur_region), old_total, new_total, old_free, new_free); return TRUE; } /* END of mu_truncate() */