[med-svn] [fis-gtm] 01/04: Imported Upstream version 6.2-001
Amul Shah
tuskentower-guest at moszumanska.debian.org
Fri Jan 23 00:10:02 UTC 2015
This is an automated email from the git hooks/post-receive script.
tuskentower-guest pushed a commit to branch master
in repository fis-gtm.
commit 921cb3013bf8f25b14a24e70ef612d3153eb4011
Author: Amul Shah <Amul.Shah at fisglobal.com>
Date: Sun Jan 11 19:56:27 2015 -0500
Imported Upstream version 6.2-001
---
CMakeLists.txt | 55 +-
README | 46 +-
sr_avms/release_name.h | 2 +-
sr_i386/merrors_ansi.h | 27 +-
sr_i386/merrors_ctl.c | 64 +-
sr_i386/obj_file.c | 26 +-
sr_linux/hugetlbfs_overrides.h | 25 -
sr_linux/release_name.h | 10 +-
sr_port/advancewindow.c | 16 +-
sr_port/buddy_list.c | 5 +-
sr_port/ceil_log2.c | 77 +
sr_port/cmd.c | 8 +-
sr_port/code_gen.c | 3 +-
sr_port/comp_fini.c | 4 +-
sr_port/comp_init.c | 7 +-
sr_port/compile_pattern.c | 5 +-
sr_port/compiler_startup.c | 3 +-
sr_port/db_auto_upgrade.c | 9 +-
sr_port/db_csh_getn.c | 72 +-
sr_port/dbcertify_certify_phase.c | 91 +-
sr_port/dbcertify_scan_phase.c | 27 +-
sr_port/dse.hlp | 28 +-
sr_port/dse_adrec.c | 4 +-
sr_port/dse_chng_fhead.c | 9 +-
sr_port/dse_getki.c | 2 -
sr_port/dump_record.c | 4 +-
sr_port/entryref.c | 2 +-
sr_port/error.h | 2 +
sr_port/exfunc.c | 2 +-
sr_port/expritem.c | 4 +-
sr_port/f_get.c | 4 +-
sr_port/f_name.c | 4 +-
sr_port/f_order.c | 4 +-
sr_port/find_rtn_hdr.c | 69 +-
sr_port/flush_jmp.c | 16 +-
sr_port/format2disp.c | 88 +
sr_port/gbldefs.c | 8 +-
sr_port/gde.hlp | 18 +-
sr_port/gdsbt.h | 6 +-
sr_port/gdsdbver.h | 3 +-
sr_port/gdsfhead.h | 71 +-
sr_port/gtm_env_init.c | 18 +
sr_port/gtm_stdlib.h | 56 +-
sr_port/gtm_threadgbl.h | 7 +-
sr_port/gtm_threadgbl_defs.h | 45 +-
sr_port/gtm_threadgbl_deftypes.c | 5 +-
sr_port/gtm_threadgbl_init.c | 9 +-
sr_port/gtmrecv_helpers_init.c | 38 +-
sr_port/gtmrecv_upd_proc_init.c | 45 +-
sr_port/gv_select.c | 60 +-
sr_port/gv_trigger_common.h | 23 +-
sr_port/gvcst_init.c | 44 +-
sr_port/hashtab.h | 93 +-
sr_port/have_crit.h | 3 +-
sr_port/indir.h | 2 +-
sr_port/indirection.c | 4 +-
sr_port/io_rundown.c | 6 +-
sr_port/iosocket_close.c | 29 +-
sr_port/iosocket_flush.c | 24 +-
sr_port/iosocket_iocontrol.c | 95 +-
sr_port/iosocket_readfl.c | 17 +-
sr_port/iosocket_snr.c | 140 +-
sr_port/iosocket_use.c | 7 +
sr_port/iosocket_wait.c | 95 +-
sr_port/iosocket_write.c | 293 +++-
sr_port/iosocketdef.h | 26 +-
sr_port/jnl.h | 38 +-
sr_port/jnl_file_open_common.c | 3 +-
sr_port/jnl_file_open_switch.c | 11 +-
sr_port/jnl_write.c | 3 +-
sr_port/jnl_write_poolonly.c | 3 +
sr_port/job_addr.c | 23 +-
sr_port/job_addr.h | 4 +-
sr_port/jobparams.h | 3 +-
sr_port/jobparamstrs.h | 5 +-
sr_port/lke.hlp | 9 +-
sr_port/lvzwr_init.c | 5 +-
sr_port/lvzwr_var.c | 18 +-
sr_port/m_do.c | 2 +-
sr_port/m_zstep.c | 4 +-
sr_port/m_zwrite.c | 4 +-
sr_port/maketriple.c | 5 +-
sr_port/md5_digest2hex.c | 40 -
sr_port/mdef.h | 70 +-
sr_port/merrors.msg | 35 +-
sr_port/mtables.c | 27 +-
sr_port/mu_extr_ident.c | 18 +-
sr_port/muextr.h | 12 +-
sr_port/mumps.hlp | 694 ++++----
sr_port/mupip.hlp | 299 ++--
sr_port/mupip_cvtgbl.h | 6 +-
sr_port/mupip_reorg.c | 12 +-
sr_port/mupip_set_journal_parse.c | 16 +-
sr_port/mv_stent.h | 21 +-
sr_port/obj_file.h | 34 +-
sr_port/objlabel.h | 2 +-
sr_port/one_job_param.c | 8 +-
sr_port/op_exp.c | 94 +-
sr_port/op_fntext.c | 29 +-
sr_port/op_fnview.c | 84 +-
sr_port/op_fnztrigger.c | 34 +-
sr_port/op_hang.c | 11 +-
sr_port/op_indpat.c | 4 +-
sr_port/op_indtext.c | 4 +-
sr_port/op_lvpatwrite.c | 5 +-
sr_port/op_lvzwrite.c | 5 +-
sr_port/op_merge.c | 2 +
sr_port/op_rhdaddr.c | 6 +-
sr_port/op_setzbrk.c | 65 +-
sr_port/op_svget.c | 15 +-
sr_port/op_tcommit.c | 4 +-
sr_port/op_tstart.c | 19 +-
sr_port/op_unwind.c | 5 +
sr_port/op_view.c | 151 +-
sr_port/op_zprint.c | 69 +-
sr_port/op_zshow.c | 14 +-
sr_port/opcode_def.h | 2 +
sr_port/put_indr.c | 15 +-
sr_port/put_lit.c | 10 +-
sr_port/put_str.c | 5 +-
sr_port/repl_errno.h | 11 +-
sr_port/repl_filter.c | 345 ++--
sr_port/repl_filter.h | 38 +-
sr_port/rtn_src_chksum.c | 25 +-
sr_port/rtn_src_chksum.h | 8 +-
sr_port/s2n.c | 3 +-
sr_port/srcline.h | 33 +-
sr_port/stp_gcol_src.h | 32 +-
sr_port/svnames.h | 3 +-
sr_port/t_end.c | 4 +-
sr_port/t_end_sysops.c | 7 +-
sr_port/tab_gvstats_rec.h | 12 +-
sr_port/tp.h | 22 +-
sr_port/tp_clean_up.c | 18 +-
sr_port/tp_incr_clean_up.c | 6 +-
sr_port/tp_tend.c | 33 +-
sr_port/unw_mv_ent.c | 18 +-
sr_port/unw_retarg.c | 38 +-
sr_port/updhelper_reader.c | 1 -
sr_port/updproc.c | 36 +-
sr_port/updproc.h | 47 +-
sr_port/updproc_get_gblname.c | 13 +-
sr_port/util.h | 25 +-
sr_port/verify_queue.c | 72 +-
sr_port/view_arg_convert.c | 30 +-
sr_port/viewtab.h | 9 +-
sr_port/wbox_test_init.h | 17 +-
sr_port/xfer.h | 2 +-
sr_port/zbreak.h | 8 +-
sr_port/zlput_rname.c | 103 +-
sr_port/{zr_get_free.c => zr_add_zbreak.c} | 12 +-
sr_port/{zr_put_free.c => zr_remove_zbreak.c} | 42 +-
sr_port/zr_remove_zbrks.c | 15 +-
sr_port/zr_unlink_rtn.c | 35 +-
sr_port/zshow.h | 7 +-
sr_port/zshow_output.c | 55 +-
sr_port/zshow_svn.c | 16 +-
sr_unix/CMakeLists.txt | 53 +-
sr_unix/Makefile.mk | 138 +-
sr_port/md5_digest2hex.h => sr_unix/arlinkdbg.h | 23 +-
sr_unix/auto_zlink.c | 20 +-
sr_unix/bin_load.c | 68 +-
sr_unix/buildaux.csh | 57 +-
sr_unix/callintogtmxfer.c | 10 +-
sr_unix/ce_substitute.c | 4 +-
sr_unix/cli.h | 6 +-
sr_unix/cli_parse.c | 2 +-
sr_unix/comlist.csh | 49 +-
sr_unix/comp_lits.c | 23 +-
sr_unix/dbcertify_signal_handler.c | 23 +-
sr_unix/do_shmat.c | 51 +-
sr_unix/do_shmat.h | 5 +-
sr_unix/dollarh.c | 21 +-
sr_unix/dsk_read.c | 7 +-
sr_unix/errorsp.h | 2 +
sr_port/lastchance3.c => sr_unix/exi_ch.c | 22 +-
sr_unix/file_input.c | 113 +-
sr_unix/file_input.h | 21 +-
sr_unix/ftok.c | 3 +
sr_unix/generate_help.csh | 102 ++
sr_unix/get_src_line.c | 63 +-
sr_unix/geteditor.c | 13 +-
sr_unix/go_load.c | 72 +-
sr_unix/grab_latch.c | 84 +
sr_unix/gt_timer.h | 68 +-
sr_unix/gt_timers.c | 112 +-
sr_unix/gtm_env_init_sp.c | 41 +-
sr_unix/gtm_exit_handler.c | 156 +-
sr_unix/gtm_ipc.h | 6 +-
sr_unix/gtm_logicals.h | 6 +-
sr_unix/gtm_permissions.c | 43 +-
sr_unix/gtm_permissions.h | 7 +-
sr_unix/gtm_semutils.h | 10 +-
sr_unix/gtm_startup.c | 10 +-
sr_unix/gtm_stdio.h | 14 +-
sr_unix/gtm_tls.h | 8 +-
sr_unix/gtm_tls_impl.c | 519 +++++-
sr_unix/gtm_tls_impl.h | 5 +-
sr_unix/gtm_tls_interface.h | 54 +-
sr_unix/gtm_trigger.c | 33 +-
sr_unix/gtm_trigger.h | 26 +-
sr_unix/gtm_trigger_trc.h | 4 +-
sr_unix/gtmci.c | 12 +-
sr_unix/gtmcrypt_interface.h | 44 +-
sr_unix/gtmcrypt_util.c | 32 +-
sr_unix/gtmcrypt_util.h | 14 +-
sr_unix/gtminstall.sh | 5 +
sr_unix/gtminstall_Solaris.sh | 5 +
sr_unix/gtmio.h | 19 +-
sr_unix/gtmprofile.gtc | 10 +-
sr_unix/gtmrecv_process.c | 104 +-
sr_unix/gtmsecshr.c | 14 +-
sr_unix/gtmsource.c | 3 +-
sr_unix/gtmsource.h | 22 +-
sr_unix/gtmsource_get_opt.c | 3 +-
sr_unix/gtmsource_process.c | 21 +-
sr_unix/gtmsource_process_ops.c | 7 +-
sr_unix/gtmsource_readfiles.c | 19 +-
sr_unix/gtmsrc.csh | 4 +-
sr_unix/gv_trigger.c | 91 +-
sr_unix/gv_trigger.h | 76 +-
sr_unix/gv_trigger_protos.h | 13 +-
sr_unix/gvcst_init_sysops.c | 18 +-
sr_unix/hugetlbfs_overrides.h | 34 +
sr_unix/incr_link.c | 352 +++-
sr_unix/incr_link.h | 26 +-
sr_unix/init_gtm.c | 6 +-
sr_unix/interlock.h | 14 +-
sr_unix/iopi_open.c | 132 +-
sr_unix/iosocket_tls.c | 357 ++++
sr_unix/jnlpool_init.c | 2 +-
sr_unix/jobchild_init.c | 28 +-
sr_unix/jobsp.h | 10 +-
sr_unix/kitstart.csh | 14 +-
sr_unix/libmupip.list | 3 +
sr_unix/load.h | 4 +-
sr_unix/m_zrupdate.c | 2 +-
sr_unix/maskpass.c | 57 +-
sr_unix/mdefsp.h | 23 +-
sr_unix/mmrhash.c | 500 +++++-
sr_unix/mmrhash.h | 30 +-
sr_unix/mu_all_version_standalone.c | 45 +-
sr_unix/mu_rndwn_file.c | 2 +-
sr_unix/mu_rndwn_rlnkctl.c | 65 +
sr_unix/{do_shmat.h => mu_rndwn_rlnkctl.h} | 10 +-
sr_unix/mupip_cmd.c | 29 +-
sr_unix/mupip_cmd_disallow.c | 6 +-
sr_unix/mupip_cvtgbl.c | 128 +-
sr_unix/mupip_exit_handler.c | 2 +-
sr_unix/mupip_hash.c | 65 +
sr_avms/release_name.h => sr_unix/mupip_hash.h | 6 +-
sr_unix/mupip_rctldump.c | 60 +
sr_unix/{do_shmat.h => mupip_rctldump.h} | 10 +-
sr_unix/mupip_rundown.c | 2 +-
sr_unix/mupip_trigger.c | 65 +-
sr_unix/mutex.c | 115 +-
sr_unix/mutexsp.h | 4 +-
sr_unix/obj_code.c | 79 +-
sr_unix/obj_file.c | 199 ++-
sr_unix/obj_filesp.h | 3 +-
sr_unix/obj_fileu.c | 147 ++
sr_unix/ojchildioclean.c | 5 +-
sr_unix/ojchildparms.c | 177 +-
sr_unix/ojparams.c | 6 +-
sr_unix/ojstartchild.c | 221 ++-
sr_unix/op_fnzpeek.c | 91 +-
sr_unix/op_fnzsearch.c | 2 +-
sr_unix/op_lab_ext.c | 4 +-
sr_unix/op_rhd_ext.c | 47 +-
sr_unix/op_zedit.c | 17 +-
sr_unix/op_zlink.c | 222 ++-
sr_unix/op_zrupdate.c | 184 +-
sr_unix/open_object_file.c | 111 --
sr_unix/parse_file.h | 8 +-
.../md5_digest2hex.h => sr_unix/probecrit_rec.h | 25 +-
sr_unix/rel_latch.c | 31 +
sr_unix/relinkctl.c | 849 ++++++---
sr_unix/relinkctl.h | 284 ++-
sr_unix/repl_inst_dump.c | 6 +-
sr_unix/repl_msg.h | 14 +-
sr_unix/rtnhdr.h | 68 +-
sr_unix/rtnobj.c | 997 +++++++++++
sr_unix/rtnobj.h | 34 +
sr_unix/runall.csh | 9 +-
sr_unix/secshr_client.c | 21 +-
sr_unix/sleep.c | 64 +-
sr_unix/sleep.h | 255 ++-
sr_unix/ss_context_mgr.c | 16 +-
sr_unix/tab_probecrit_rec.h | 23 +
sr_unix/trigger.h | 225 ++-
sr_unix/trigger_compare.c | 220 ++-
sr_unix/trigger_compare_protos.h | 4 +-
sr_unix/trigger_delete.c | 772 ++++-----
sr_unix/trigger_delete_protos.h | 8 +-
sr_unix/trigger_fill_xecute_buffer.c | 12 +-
sr_unix/trigger_gbl_fill_xecute_buffer.c | 59 +-
sr_unix/trigger_parse.c | 52 +-
sr_unix/trigger_read_name_entry.c | 66 -
sr_unix/trigger_read_name_entry.h | 17 -
sr_unix/trigger_select.c | 454 +++--
sr_unix/trigger_select_protos.h | 12 +-
sr_unix/trigger_source_read_andor_verify.c | 446 +++--
sr_unix/trigger_source_read_andor_verify.h | 4 +-
sr_unix/trigger_subs_def.h | 32 +-
sr_unix/trigger_trgfile.c | 114 +-
sr_unix/trigger_update.c | 1808 ++++++++++++--------
sr_unix/trigger_update_protos.h | 37 +-
sr_unix/trigger_upgrade.c | 542 ++++++
sr_unix/{do_shmat.h => trigger_upgrade_protos.h} | 8 +-
sr_unix/util_out_print_gtmio.c | 134 ++
sr_unix/util_output.c | 52 +-
sr_unix/wcs_flu.c | 30 +-
sr_unix/zhist.c | 104 +-
sr_unix/zhist.h | 42 -
sr_unix/zro_gettok.c | 51 +-
sr_unix/zro_load.c | 38 +-
sr_unix/zro_search.c | 233 ++-
sr_unix/zroutinessp.h | 5 +-
sr_unix/zshow_devices.c | 1029 +++++------
sr_unix/zshow_rctldump.c | 96 ++
sr_unix_nsb/obj_code.c | 14 +-
sr_unix_nsb/obj_filesp.h | 12 +-
sr_unix_nsb/rtnhdr.h | 4 +-
sr_vvms/dbcertify_exit_handler.c | 15 +-
sr_vvms/get_src_line.c | 14 +-
sr_vvms/gt_timers.c | 6 +-
sr_vvms/gtm$startup.c | 5 +-
sr_vvms/gtm_logicals.h | 5 +-
sr_vvms/gtmrecv_process.c | 6 +-
{sr_port => sr_vvms}/lastchance1.c | 0
{sr_port => sr_vvms}/lastchance2.c | 2 +-
{sr_port => sr_vvms}/lastchance3.c | 2 +-
sr_vvms/op_fnzsearch.c | 2 +-
{sr_port => sr_vvms}/op_setzbrk.c | 65 +-
sr_vvms/rtnhdr.h | 2 +-
sr_x86_64/merrors_ansi.h | 27 +-
sr_x86_64/merrors_ctl.c | 64 +-
sr_x86_64/obj_filesp.c | 9 +-
338 files changed, 14674 insertions(+), 6827 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9bb017b..04203d1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -26,7 +26,7 @@ foreach(lang ${languages})
endforeach()
# Defaults
-set(version V6.2-000)
+set(version V6.2-001)
if("${version}" STREQUAL "")
set(version V9.9-0)
endif()
@@ -60,8 +60,6 @@ set(gtm_osarch_libs "")
set(gt_src_list)
set(sources_used "")
set(extralibs "")
-set(GTMCRYPTLIB "GCRYPT")
-set(GTMCRYPTALGO "AES256CFB")
message("--> OS = ${CMAKE_SYSTEM_NAME} / ARCH = ${CMAKE_SYSTEM_PROCESSOR}")
# Establish platform
# Except for Solaris, CMAKE_COMPILER_IS_GNUCC is true
@@ -76,7 +74,6 @@ elseif("${CMAKE_SYSTEM_NAME}" MATCHES "SunOS")
else()
message(FATAL_ERROR "--> OS = ${CMAKE_SYSTEM_NAME} / ARCH = ${CMAKE_SYSTEM_PROCESSOR}")
endif()
-message("--> Encryption Library = ${GTMCRYPTLIB} / Algorithm = ${GTMCRYPTALGO}")
# Choose where to get bootstrap sources.
set(GTM_DIST "" CACHE PATH "Existing GT.M Distribution")
@@ -461,14 +458,50 @@ foreach(tlslib ssl crypto config)
set(TLS_LIBRARIES ${TLS_LIBRARIES} ${TLSLIB_${tlslib}})
endforeach()
-add_library(libgtmcrypt MODULE ${libgtmcrypt_SOURCES})
-set_target_properties(libgtmcrypt PROPERTIES
- OUTPUT_NAME gtmcrypt
- COMPILE_DEFINITIONS "USE_${GTMCRYPTLIB} -DUSE_${GTMCRYPTALGO}"
+# Building the three encryption libraries could by a loop of some sort, but
+# manually creating each target is way easier.
+
+# Library=GCRYPT Algorithm=AES256CFB
+add_library(libgtmcrypt_gcrypt_AES256CFB.so MODULE ${libgtmcrypt_SOURCES})
+set_target_properties(libgtmcrypt_gcrypt_AES256CFB.so PROPERTIES
+ OUTPUT_NAME gtmcrypt_gcrypt_AES256CFB
+ COMPILE_DEFINITIONS "USE_GCRYPT -DUSE_AES256CFB"
+ LIBRARY_OUTPUT_DIRECTORY ${GTM_BINARY_DIR}/plugin
+ )
+target_link_libraries(libgtmcrypt_gcrypt_AES256CFB.so ${GPG_LIBRARIES})
+install(TARGETS libgtmcrypt_gcrypt_AES256CFB.so DESTINATION ${GTM_INSTALL_DIR}/plugin)
+
+# Establish the default encryption link
+set(default_encr_link ${GTM_BINARY_DIR}/plugin/libgtmcrypt.so)
+set(default_encr_target libgtmcrypt_gcrypt_AES256CFB.so)
+add_custom_command(
+ OUTPUT ${default_encr_link}
+ COMMAND ${CMAKE_COMMAND} -E create_symlink "${default_encr_target}" "${default_encr_link}"
+ DEPENDS ${GTM_BINARY_DIR}/plugin/${default_encr_target}
+ COMMENT "Generating default_encr symbolic link"
+ )
+add_custom_target(install_default_encr ALL DEPENDS ${default_encr_link})
+install(FILES ${default_encr_link} DESTINATION ${GTM_INSTALL_DIR}/plugin)
+
+# Library=OPENSSL Algorithm=AES256CFB
+add_library(libgtmcrypt_openssl_AES256CFB MODULE ${libgtmcrypt_SOURCES})
+set_target_properties(libgtmcrypt_openssl_AES256CFB PROPERTIES
+ OUTPUT_NAME gtmcrypt_openssl_AES256CFB
+ COMPILE_DEFINITIONS "USE_OPENSSL -DUSE_AES256CFB"
+ LIBRARY_OUTPUT_DIRECTORY ${GTM_BINARY_DIR}/plugin
+ )
+target_link_libraries(libgtmcrypt_openssl_AES256CFB ${GPG_LIBRARIES} ${TLS_LIBRARIES})
+install(TARGETS libgtmcrypt_openssl_AES256CFB DESTINATION ${GTM_INSTALL_DIR}/plugin)
+
+# Library=OPENSSL Algorithm=BLOWFISHCFB
+add_library(libgtmcrypt_openssl_BLOWFISHCFB MODULE ${libgtmcrypt_SOURCES})
+set_target_properties(libgtmcrypt_openssl_BLOWFISHCFB PROPERTIES
+ OUTPUT_NAME gtmcrypt_openssl_BLOWFISHCFB
+ COMPILE_DEFINITIONS "USE_OPENSSL -DUSE_BLOWFISHCFB"
LIBRARY_OUTPUT_DIRECTORY ${GTM_BINARY_DIR}/plugin
)
-target_link_libraries(libgtmcrypt ${GPG_LIBRARIES})
-install(TARGETS libgtmcrypt DESTINATION ${GTM_INSTALL_DIR}/plugin)
+target_link_libraries(libgtmcrypt_openssl_BLOWFISHCFB ${GPG_LIBRARIES} ${TLS_LIBRARIES})
+install(TARGETS libgtmcrypt_openssl_BLOWFISHCFB DESTINATION ${GTM_INSTALL_DIR}/plugin)
add_library(libgtmtls MODULE ${libgtmtls_SOURCES})
set_target_properties(libgtmtls PROPERTIES
@@ -482,7 +515,7 @@ install(TARGETS libgtmtls DESTINATION ${GTM_INSTALL_DIR}/plugin)
add_executable(maskpass ${maskpass_SOURCES})
target_link_libraries(maskpass ${GPG_LIBRARIES} ${TLS_LIBRARIES})
set_target_properties(maskpass PROPERTIES
- COMPILE_DEFINITIONS "USE_${GTMCRYPTLIB} -DUSE_SYSLIB_FUNCS"
+ COMPILE_DEFINITIONS "USE_GCRYPT -DUSE_SYSLIB_FUNCS"
RUNTIME_OUTPUT_DIRECTORY ${GTM_BINARY_DIR}/plugin/gtmcrypt
)
install(TARGETS maskpass DESTINATION ${GTM_INSTALL_DIR}/plugin/gtmcrypt)
diff --git a/README b/README
index 43fd188..53a67e2 100644
--- a/README
+++ b/README
@@ -10,32 +10,36 @@ package.
GT.M relies on CMake to generate the Makefiles to build GT.M from source. The
prerequisites are CMake (at least 2.8.5), GNU make (at least 3.81), Linux
-(either x86 or x86_64), Unicode include files and GPG. Unicode include files
-are automatically installed if ICU is installed. GPG include files require
-installing the GNUPG and related library development packages. Debian 6, Ubuntu
-12.04 LTS and RHEL 6.0 were used to do the test builds for this distribution.
-The default ICU and GPG packages were taken from the distribution repositories.
+(either x86 or x86_64), libraries and development files for libz, Unicode,
+OpenSSL and GPG. Debian 6, Ubuntu 12.04/14.04 LTS and RHEL 6.0 were used to do
+the test builds for this distribution. The default ICU and GPG packages were
+taken from the distribution repositories.
To build GT.M for Linux, do the following steps:
1. Fulfill the pre-requisites
Install developement libraries libelf, zlib, libicu, libgpgme, libgpg-error,
- libgcrypt.
+ libgcrypt, libssl, libconfig.
Ensure that your locale settings are correct, otherwise you will see
GTM-E-NONUTF8LOCALE messages. Refer the Messages and Recovery Procedures
- Manual if you do encounter these messages.
+ Manual if you do encounter these messages. The following should give you a
+ valid locale:
+
+ $ locale -a | gawk 'BEGIN{IGNORECASE=1}/en_us.utf-*8/{print;exit}'
+ en_US.utf8
+ $ export LANG=C LC_ALL= LC_CTYPE="<answer from above>" LC_COLLATE=C
[optional] The GT.M source tarball includes pre-generated files. To generate
these files requires a binary distribution of GT.M. You can download GT.M
from http://sourceforge.net/projects/fis-gtm/ Unpack the tar file and run
the configure script as root. Note: the tar file unpacks everything into
your current working directory, not a new subdirectory. The Linux Standard
- Base (LSB) install path for GT.M V6.2-000 is /opt/fis-gtm/V6.2-000_i586 or
- /opt/fis-gtm/V6.2-000_x8664. These instructions are written using x8664, please
+ Base (LSB) install path for GT.M V6.2-001 is /opt/fis-gtm/V6.2-001_i586 or
+ /opt/fis-gtm/V6.2-001_x8664. These instructions are written using x8664, please
use i586 as necessary.
- $ tar xfz gtm_V62000_linux_x8664_pro.tar.gz
+ $ tar xfz gtm_V62001_linux_x8664_pro.tar.gz
# Note down the installation path for use with cmake below
@@ -43,16 +47,16 @@ To build GT.M for Linux, do the following steps:
2. Unpack the GT.M sources
The GT.M source tarball extracts to a directory with the version number in
- the name, fis-gtm-V6.2-000
- $ tar xfz fis-gtm-V6.2-000.tar.gz
- $ cd fis-gtm-V6.2-000
+ the name, fis-gtm-V6.2-001
+ $ tar xfz fis-gtm-V6.2-001.tar.gz
+ $ cd fis-gtm-V6.2-001
You should find this README, LICENSE, COPYING and CMakeLists.txt file and
sr_* source directories.
3. Building GT.M -
<fis-gtm-build> can be a sub directory of the source directory,
- fis-gtm-V6.2-000, or any other valid path.
+ fis-gtm-V6.2-001, or any other valid path.
$ mkdir <fis-gtm-build>
$ cd <fis-gtm-build>
@@ -71,16 +75,16 @@ To build GT.M for Linux, do the following steps:
#
# -D CMAKE_INSTALL_PREFIX:PATH=${PWD}/package
#
- $ cmake -D CMAKE_INSTALL_PREFIX:PATH=${PWD}/package <path to>/fis-gtm-V6.2-000
+ $ cmake -D CMAKE_INSTALL_PREFIX:PATH=${PWD}/package <path to>/fis-gtm-V6.2-001
$ make
$ make install
- $ cd package/lib/fis-gtm/V6.2-000_x86_64
+ $ cd package/lib/fis-gtm/V6.2-001_x86_64
# Now you are ready to install GT.M. Answer a few questions and install it.
- # The recommended installation path is /opt/fis-gtm/V6.2-000_x86_64
+ # The recommended installation path is /opt/fis-gtm/V6.2-001_x86_64
$ sudo ./configure
@@ -88,3 +92,11 @@ To build GT.M for Linux, do the following steps:
4. Packaging GT.M -
Create a tar file from the installed directory
+
+FAQ:
+- The CMake build fails with the following message followed by one or more cases.
+ CMake Error: The following variables are used in this project, but they are set to NOTFOUND.
+ Please set them or make sure they are set and tested correctly in the CMake files:
+ This indicates that required libraries are not found. Please consult the list
+ of libraries and check your distributions package manager.
+
diff --git a/sr_avms/release_name.h b/sr_avms/release_name.h
index 632b116..293a521 100644
--- a/sr_avms/release_name.h
+++ b/sr_avms/release_name.h
@@ -9,6 +9,6 @@
* *
****************************************************************/
-#define GTM_RELEASE_NAME "GT.M V6.2-000 VMS AXP"
+#define GTM_RELEASE_NAME "GT.M V6.2-001 VMS AXP"
#define GTM_PRODUCT "GT.M"
#define GTM_VERSION "V6.2"
diff --git a/sr_i386/merrors_ansi.h b/sr_i386/merrors_ansi.h
index 20e9320..f00646a 100644
--- a/sr_i386/merrors_ansi.h
+++ b/sr_i386/merrors_ansi.h
@@ -609,7 +609,7 @@ const static readonly int error_ansi[] = {
0, /* FREEZEID */
0, /* BLKWRITERR */
0, /* STOPTIMEOUT */
- 0, /* TRIGMODINTP */
+ 0, /* UNUSEDMSG776 */
0, /* BCKUPBUFLUSH */
0, /* NOFORKCORE */
0, /* JNLREAD */
@@ -731,7 +731,7 @@ const static readonly int error_ansi[] = {
0, /* SCNDDBNOUPD */
0, /* MUINFOUINT4 */
0, /* NLMISMATCHCALC */
- 0, /* UNUSEDMSG898 */
+ 0, /* RELINKCTLFULL */
0, /* UNUSEDMSG899 */
0, /* DBBADNSUB */
0, /* DBBADKYNM */
@@ -1200,13 +1200,13 @@ const static readonly int error_ansi[] = {
0, /* SSATTACHSHM */
0, /* TRIGDEFNOSYNC */
0, /* TRESTMAX */
- 0, /* UNUSEDMSG1367 */
+ 0, /* ZLINKBYPASS */
0, /* GBLEXPECTED */
0, /* GVZTRIGFAIL */
0, /* MUUSERLBK */
0, /* SETINSETTRIGONLY */
0, /* DZTRIGINTRIG */
- 0, /* SECNODZTRIGINTP */
+ 0, /* UNUSEDMSG1373 */
0, /* BOOLSIDEFFECT */
0, /* DBBADUPGRDSTATE */
0, /* WRITEWAITPID */
@@ -1218,7 +1218,7 @@ const static readonly int error_ansi[] = {
0, /* JNLORDBFLU */
0, /* ZCCLNUPRTNMISNG */
0, /* ZCINVALIDKEYWORD */
- 0, /* REPLNOMULTILINETRG */
+ 0, /* UNUSEDMSG1385 */
0, /* DBSHMNAMEDIFF */
0, /* SHMREMOVED */
0, /* DEVICEWRITEONLY */
@@ -1370,7 +1370,7 @@ const static readonly int error_ansi[] = {
0, /* ISSPANGBL */
0, /* TPNOSUPPORT */
0, /* GVSUBSERR */
- 0, /* TRIGNOSPANGBL */
+ 0, /* UNUSEDMSG1539 */
0, /* FILTERTIMEDOUT */
0, /* TLSDLLNOOPEN */
0, /* TLSINIT */
@@ -1407,4 +1407,19 @@ const static readonly int error_ansi[] = {
13, /* LABELNOTFND */
0, /* RELINKCTLERR */
0, /* INVLINKTMPDIR */
+ 0, /* NOEDITOR */
+ 0, /* UPDPROC */
+ 0, /* HLPPROC */
+ 0, /* REPLNOHASHTREC */
+ 0, /* REMOTEDBNOTRIG */
+ 0, /* NEEDTRIGUPGRD */
+ 0, /* REQRLNKCTLRNDWN */
+ 0, /* RLNKCTLRNDWNSUC */
+ 0, /* RLNKCTLRNDWNFL */
+ 0, /* MPROFRUNDOWN */
+ 0, /* ZPEEKNOJNLINFO */
+ 0, /* TLSPARAM */
+ 0, /* RLNKRECLATCH */
+ 0, /* RLNKSHMLATCH */
+ 0, /* JOBLVN2LONG */
};
diff --git a/sr_i386/merrors_ctl.c b/sr_i386/merrors_ctl.c
index 4c4ea08..fc01b83 100644
--- a/sr_i386/merrors_ctl.c
+++ b/sr_i386/merrors_ctl.c
@@ -330,7 +330,7 @@ LITDEF err_msg merrors[] = {
"FREEZE", "Region: !AD is already frozen", 2,
"NOSELECT", "None of the selected variables exist -- halting", 0,
"EXTRFAIL", "Extract failed for the global ^!AD. MUPIP INTEG should be run.", 2,
- "LDBINFMT", "Corrupt binary format header information", 0,
+ "LDBINFMT", "Unrecognized header for load file", 0,
"NOPREVLINK", "Journal file !AD has a null previous link", 2,
"CCEDUMPON", "", 0,
"CCEDMPQUALREQ", "A qualifier (DB,[NO]ON, or NOW) is required with the DUMP command", 0,
@@ -413,7 +413,7 @@ LITDEF err_msg merrors[] = {
"TEXT", "!AD", 2,
"ZWRSPONE", "Subscript patterns in ZWRITE are atomic; Invalid delimiter", 0,
"FILEDEL", "File !AD successfully deleted", 2,
- "JNLBADLABEL", "Journal file !AD does not have a GT.M Journal File Label", 2,
+ "JNLBADLABEL", "Journal file !AD has a bad GT.M Journal File Label. Expected !AD. Found !AD.", 6,
"JNLREADEOF", "End of journal file encountered for !AD", 2,
"JNLRECFMT", "Journal file record format error encountered", 0,
"BLKTOODEEP", "Block level too deep", 0,
@@ -611,7 +611,7 @@ LITDEF err_msg merrors[] = {
"FREEZEID", "Cache !AD on !AD by freeze id 0x!XL with match 0x!XL from 0x!XJ", 7,
"BLKWRITERR", "Unable to queue disk write for block 0x!XL. Will keep trying.", 1,
"STOPTIMEOUT", "Waited too long for stopped process to release. Region: !AD.", 2,
- "TRIGMODINTP", "Triggers for a given global cannot be both used and modified or removed in the same transaction", 0,
+ "UNUSEDMSG776", "TRIGMODINTP last used in V6.2-000", 0,
"BCKUPBUFLUSH", "Unable to flush buffer for online backup", 0,
"NOFORKCORE", "Unable to fork off process to create core. Core creation postponed.", 0,
"JNLREAD", "Error reading from journal file !AD at offset [0x!XL]", 3,
@@ -644,7 +644,7 @@ LITDEF err_msg merrors[] = {
"JNLRDONLY", "Journal file !AD read only", 2,
"ANCOMPTINC", "Deviceparameter !AD is not compatible with any other deviceparameters in the !AD command", 4,
"ABNCOMPTINC", "Deviceparameter !AD and deviceparameter !AD are not compatible in the !AD command", 6,
- "RECLOAD", "Error loading record number: !UL!/", 1,
+ "RECLOAD", "Error loading record number: !@UQ!/", 1,
"SOCKNOTFND", "Socket !AD not found", 2,
"CURRSOCKOFR", "Current socket of index !UL is out of range. There are only !UL sockets.", 2,
"SOCKETEXIST", "Socket !AD already exists", 2,
@@ -733,7 +733,7 @@ LITDEF err_msg merrors[] = {
"SCNDDBNOUPD", "Database Updates not allowed on the secondary", 0,
"MUINFOUINT4", "!AD : !UL [0x!XL]", 4,
"NLMISMATCHCALC", "Location of !AD expected at 0x!XL, but found at 0x!XL", 4,
- "UNUSEDMSG898", "GTMSECSHRLOGSWH last used in V5.5-000", 0,
+ "RELINKCTLFULL", "Relinkctl file for directory !AD is full (maximum entries !UL)", 3,
"UNUSEDMSG899", "GTMSECSHRDEFLOG last used in V5.5-000", 0,
"DBBADNSUB", "!AD Bad numeric subscript", 2,
"DBBADKYNM", "!AD Bad key name", 2,
@@ -1202,13 +1202,13 @@ LITDEF err_msg merrors[] = {
"SSATTACHSHM", "Error while attaching to shared memory identifier !UL", 1,
"TRIGDEFNOSYNC", "Global ^!AD has triggers defined on the !AD instance but none on the !AD instance. Current journal sequence number is 0x!16 at XQ", 7,
"TRESTMAX", "TRESTART not allowed in a final TP retry more than once", 0,
- "UNUSEDMSG1367", "TPLOCKRESTMAX : Last used in V5.5-000", 0,
+ "ZLINKBYPASS", "ZLINK of !AD bypassed - Identical routine already linked", 2,
"GBLEXPECTED", "Global variable reference expected in this context", 0,
"GVZTRIGFAIL", "ZTRIGGER of a global variable failed. Failure code: !AD.", 2,
"MUUSERLBK", "Abnormal shutdown of replication-enabled database !AD detected", 2,
"SETINSETTRIGONLY", "ISV !AD can only be modified in a 'SET' type trigger", 2,
"DZTRIGINTRIG", "$ZTRIGGER() is not allowed inside trigger context. Trigger name: !AD", 2,
- "SECNODZTRIGINTP", "Sequence number 0x!16 at XQ contains $ZTRIGGER() updates made inside a transaction which the current replicating instance does not support. The replicating instance must be upgraded to at least V5.4-002 to support this type of transaction. Cannot continue", 1,
+ "UNUSEDMSG1373", "SECNODZTRIGINTP : Last used in V6.2-000", 0,
"BOOLSIDEFFECT", "Extrinsic ($$), External call ($&) or $INCREMENT() with potential side effects in Boolean expression", 0,
"DBBADUPGRDSTATE", "Correcting conflicting values for fields describing database version upgrade state in the file header for region !AD (!AD) - make fresh backups with new journal files immediately.", 4,
"WRITEWAITPID", "PID !UL waited !UL minute(s) for PID !UL to finish writing block 0x!XL in database file !AD", 6,
@@ -1220,7 +1220,7 @@ LITDEF err_msg merrors[] = {
"JNLORDBFLU", "Error flushing database blocks to !AD. See related messages in the operator log", 2,
"ZCCLNUPRTNMISNG", "External call: Cleanup routine name missing. Cannot continue", 0,
"ZCINVALIDKEYWORD", "External call: Invalid keyword found. Cannot continue", 0,
- "REPLNOMULTILINETRG", "Sequence number 0x!16 at XQ contains a trigger definition too large for transmission to the current replicating instance, which does not support multi-line triggers - stopping replication", 1,
+ "UNUSEDMSG1385", "REPLNOMULTILINETRG : Last used in V6.2-000", 0,
"DBSHMNAMEDIFF", "Database file !AD points to shared memory (id = !UL) which points to a different database file !AZ", 4,
"SHMREMOVED", "Removed Shared Memory id !UL corresponding to file !AD", 3,
"DEVICEWRITEONLY", "Cannot read from a write-only device", 0,
@@ -1240,7 +1240,7 @@ LITDEF err_msg merrors[] = {
"JIUNHNDINT", "An error during $ZINTERRUPT processing was not handled: !AD", 2,
"GTMASSERT2", "!AD - Assert failed !AD line !UL for expression (!AD)", 7,
"ZTRIGNOTRW", "ZTRIGGER cannot operate on read-only region !AD", 2,
- "TRIGMODREGNOTRW", "Trigger(s) cannot be added/changed/deleted because region !AD is read-only", 2,
+ "TRIGMODREGNOTRW", "Trigger(s) cannot be added/changed/deleted/upgraded because region !AD is read-only", 2,
"INSNOTJOINED", "Replicating Instance !AD is not a member of the same Group as Instance !AD", 4,
"INSROLECHANGE", "Supplementary Instance !AD and non-Supplementary Instance !AD belong to the same Group", 4,
"INSUNKNOWN", "Supplementary Instance !AD has no instance definition for non-Supplementary Instance !AD", 4,
@@ -1372,7 +1372,7 @@ LITDEF err_msg merrors[] = {
"ISSPANGBL", "Operation cannot be performed on global ^!AD as it spans multiple regions in current global directory", 2,
"TPNOSUPPORT", "Operation cannot be performed while inside of a TP transaction", 0,
"GVSUBSERR", "Invalid subscripted global name specification in $VIEW() function", 0,
- "TRIGNOSPANGBL", "Triggers cannot be installed/deleted for global name !AD as it spans multiple regions in current global directory", 2,
+ "UNUSEDMSG1539", "TRIGNOSPANBL : Last used in V6.2-000", 0,
"FILTERTIMEDOUT", "Replication server timed out attempting to read seqno !16 at XQ from external filter", 1,
"TLSDLLNOOPEN", "Failed to load GT.M TLS/SSL library for secure communication", 0,
"TLSINIT", "Failed to initialize GT.M TLS/SSL library for secure communication", 0,
@@ -1409,6 +1409,21 @@ LITDEF err_msg merrors[] = {
"LABELNOTFND", "GOTO referenced a label that does not exist", 0,
"RELINKCTLERR", "Error with relink control structure for $ZROUTINES directory !AD", 2,
"INVLINKTMPDIR", "Value for $gtm_linktmpdir is either not found or not a directory: !AD", 2,
+ "NOEDITOR", "Can't find an executable editor: !AD", 2,
+ "UPDPROC", "Update Process error", 0,
+ "HLPPROC", "Helper Process error", 0,
+ "REPLNOHASHTREC", "Sequence number 0x!16 at XQ contains trigger definition updates. !AD side must be at least V6.2-000 for replication to continue", 3,
+ "REMOTEDBNOTRIG", "Trigger operations on global !AD not supported as it maps to database region !AD that points to a remote file", 4,
+ "NEEDTRIGUPGRD", "Cannot do trigger operation on database file !AD until it is upgraded; Run MUPIP TRIGGER -UPGRADE first", 2,
+ "REQRLNKCTLRNDWN", "Error accessing relinkctl file for $ZROUTINES directory !AD. Must be rundown", 2,
+ "RLNKCTLRNDWNSUC", "Relinkctl file for $ZROUTINES directory !AD successfully rundown", 2,
+ "RLNKCTLRNDWNFL", "Relinkctl file for $ZROUTINES directory !AD failed to rundown as it is open by !UL process(es)", 3,
+ "MPROFRUNDOWN", "Error during M-profiling rundown", 0,
+ "ZPEEKNOJNLINFO", "$ZPEEK() unable to access requested journal structure - region !AD is not currently journaled", 2,
+ "TLSPARAM", "TLS parameter !AD !AD", 4,
+ "RLNKRECLATCH", "Failed to get latch on relinkctl record for routine name !AZ in $ZROUTINES directory !AD", 3,
+ "RLNKSHMLATCH", "Failed to get latch on relinkctl shared memory for $ZROUTINES directory !AD", 2,
+ "JOBLVN2LONG", "The zwrite representation of a local variable transferred to a JOB'd process can not exceed !UL. Encountered size: !UL", 2,
};
LITDEF int ERR_ACK = 150372361;
@@ -2009,7 +2024,7 @@ LITDEF int ERR_MEMORYRECURSIVE = 150377116;
LITDEF int ERR_FREEZEID = 150377123;
LITDEF int ERR_BLKWRITERR = 150377131;
LITDEF int ERR_STOPTIMEOUT = 150377138;
-LITDEF int ERR_TRIGMODINTP = 150377146;
+LITDEF int ERR_UNUSEDMSG776 = 150377146;
LITDEF int ERR_BCKUPBUFLUSH = 150377154;
LITDEF int ERR_NOFORKCORE = 150377160;
LITDEF int ERR_JNLREAD = 150377170;
@@ -2131,7 +2146,7 @@ LITDEF int ERR_SECONDAHEAD = 150378090;
LITDEF int ERR_SCNDDBNOUPD = 150378098;
LITDEF int ERR_MUINFOUINT4 = 150378107;
LITDEF int ERR_NLMISMATCHCALC = 150378114;
-LITDEF int ERR_UNUSEDMSG898 = 150378122;
+LITDEF int ERR_RELINKCTLFULL = 150378122;
LITDEF int ERR_UNUSEDMSG899 = 150378131;
LITDEF int ERR_DBBADNSUB = 150378138;
LITDEF int ERR_DBBADKYNM = 150378146;
@@ -2600,13 +2615,13 @@ LITDEF int ERR_TCOMMITDISALLOW = 150381842;
LITDEF int ERR_SSATTACHSHM = 150381850;
LITDEF int ERR_TRIGDEFNOSYNC = 150381856;
LITDEF int ERR_TRESTMAX = 150381866;
-LITDEF int ERR_UNUSEDMSG1367 = 150381874;
+LITDEF int ERR_ZLINKBYPASS = 150381875;
LITDEF int ERR_GBLEXPECTED = 150381882;
LITDEF int ERR_GVZTRIGFAIL = 150381890;
LITDEF int ERR_MUUSERLBK = 150381898;
LITDEF int ERR_SETINSETTRIGONLY = 150381906;
LITDEF int ERR_DZTRIGINTRIG = 150381914;
-LITDEF int ERR_SECNODZTRIGINTP = 150381922;
+LITDEF int ERR_UNUSEDMSG1373 = 150381922;
LITDEF int ERR_BOOLSIDEFFECT = 150381928;
LITDEF int ERR_DBBADUPGRDSTATE = 150381936;
LITDEF int ERR_WRITEWAITPID = 150381946;
@@ -2618,7 +2633,7 @@ LITDEF int ERR_GTMSECSHRCHDIRF = 150381986;
LITDEF int ERR_JNLORDBFLU = 150381994;
LITDEF int ERR_ZCCLNUPRTNMISNG = 150382002;
LITDEF int ERR_ZCINVALIDKEYWORD = 150382010;
-LITDEF int ERR_REPLNOMULTILINETRG = 150382018;
+LITDEF int ERR_UNUSEDMSG1385 = 150382018;
LITDEF int ERR_DBSHMNAMEDIFF = 150382026;
LITDEF int ERR_SHMREMOVED = 150382035;
LITDEF int ERR_DEVICEWRITEONLY = 150382042;
@@ -2770,7 +2785,7 @@ LITDEF int ERR_GBLNOMAPTOREG = 150383202;
LITDEF int ERR_ISSPANGBL = 150383210;
LITDEF int ERR_TPNOSUPPORT = 150383218;
LITDEF int ERR_GVSUBSERR = 150383226;
-LITDEF int ERR_TRIGNOSPANGBL = 150383234;
+LITDEF int ERR_UNUSEDMSG1539 = 150383234;
LITDEF int ERR_FILTERTIMEDOUT = 150383242;
LITDEF int ERR_TLSDLLNOOPEN = 150383250;
LITDEF int ERR_TLSINIT = 150383258;
@@ -2807,9 +2822,24 @@ LITDEF int ERR_CRYPTBADWRTPOS = 150383498;
LITDEF int ERR_LABELNOTFND = 150383506;
LITDEF int ERR_RELINKCTLERR = 150383514;
LITDEF int ERR_INVLINKTMPDIR = 150383522;
+LITDEF int ERR_NOEDITOR = 150383530;
+LITDEF int ERR_UPDPROC = 150383538;
+LITDEF int ERR_HLPPROC = 150383546;
+LITDEF int ERR_REPLNOHASHTREC = 150383554;
+LITDEF int ERR_REMOTEDBNOTRIG = 150383562;
+LITDEF int ERR_NEEDTRIGUPGRD = 150383570;
+LITDEF int ERR_REQRLNKCTLRNDWN = 150383578;
+LITDEF int ERR_RLNKCTLRNDWNSUC = 150383587;
+LITDEF int ERR_RLNKCTLRNDWNFL = 150383594;
+LITDEF int ERR_MPROFRUNDOWN = 150383602;
+LITDEF int ERR_ZPEEKNOJNLINFO = 150383610;
+LITDEF int ERR_TLSPARAM = 150383618;
+LITDEF int ERR_RLNKRECLATCH = 150383626;
+LITDEF int ERR_RLNKSHMLATCH = 150383634;
+LITDEF int ERR_JOBLVN2LONG = 150383642;
GBLDEF err_ctl merrors_ctl = {
246,
"GTM",
&merrors[0],
- 1396};
+ 1411};
diff --git a/sr_i386/obj_file.c b/sr_i386/obj_file.c
index 6072f3c..ab858b3 100644
--- a/sr_i386/obj_file.c
+++ b/sr_i386/obj_file.c
@@ -44,6 +44,7 @@ GBLREF mident module_name;
GBLREF boolean_t run_time;
GBLREF int4 mlmax, mvmax;
GBLREF int4 code_size, lit_addrs, lits_size;
+GBLREF spdesc stringpool;
GBLDEF int4 psect_use_tab[GTM_LASTPSECT]; /* bytes of each psect in this module */
GBLREF char object_file_name[];
@@ -58,7 +59,8 @@ GBLREF uint4 txtrel_cnt;
static uint4 cdlits;
static struct rel_table *data_rel, *data_rel_end;
static struct rel_table *text_rel, *text_rel_end;
-DEBUG_ONLY(static uint4 txtrel_cnt_in_hdr;)
+static struct sym_table *symbols;
+DEBUG_ONLY(static uint4 txtrel_cnt_in_hdr;)
error_def(ERR_OBJFILERR);
error_def(ERR_STRINGOFLOW);
@@ -68,10 +70,8 @@ void create_object_file(rhdtyp *rhead)
struct exec hdr;
assert(!run_time);
-
init_object_file_name(); /* inputs: cmd_qlf.object_file, module_name; outputs: object_file_name, object_name_len */
object_file_des = mk_tmp_object_file(object_file_name, object_name_len);
-
memcpy(&rhead->jsb[0], "GTM_CODE", SIZEOF(rhead->jsb));
emit_addr((char *)&rhead->src_full_name.addr - (char *)rhead,
(int4)rhead->src_full_name.addr, (int4 *)&rhead->src_full_name.addr);
@@ -79,7 +79,6 @@ void create_object_file(rhdtyp *rhead)
(int4)rhead->routine_name.addr, (int4 *)&rhead->routine_name.addr);
txtrel_cnt += 2;
DEBUG_ONLY(txtrel_cnt_in_hdr = txtrel_cnt;)
-
set_psect(GTM_CODE, 0);
hdr.a_magic = OMAGIC;
hdr.a_stamp = OBJ_LABEL;
@@ -96,7 +95,7 @@ void create_object_file(rhdtyp *rhead)
emit_immed((char *)rhead, SIZEOF(*rhead));
}
-void close_object_file(void)
+void finish_object_file(void)
{
assert(0 == PADLEN(lits_size, NATIVE_WSIZE));
resolve_sym();
@@ -108,7 +107,6 @@ void close_object_file(void)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_OBJFILERR, 2, object_name_len, object_file_name, errno);
}
-
void drop_object_file(void)
{
int rc;
@@ -120,8 +118,6 @@ void drop_object_file(void)
}
}
-GBLREF spdesc stringpool;
-
void emit_addr(int4 refaddr, int4 offset, int4 *result)
{
struct rel_table *newrel;
@@ -152,7 +148,6 @@ void emit_addr(int4 refaddr, int4 offset, int4 *result)
return;
}
-
void emit_pidr(int4 refoffset, int4 data_offset, int4 *result)
{
struct rel_table *newrel;
@@ -178,7 +173,6 @@ void emit_pidr(int4 refoffset, int4 data_offset, int4 *result)
}
}
-
void emit_reference(uint4 refaddr, mstr *name, uint4 *result)
{
struct sym_table *sym;
@@ -212,13 +206,11 @@ void emit_reference(uint4 refaddr, mstr *name, uint4 *result)
}
}
-
/*
* emit_immed
*
* Args: buffer of executable code, and byte count to be output.
*/
-
void emit_immed(char *source, uint4 size)
{
short int write;
@@ -245,13 +237,11 @@ void emit_immed(char *source, uint4 size)
}
}
-
/*
* buff_emit
*
* Args: buffer pointer, number of bytes to emit
*/
-
void buff_emit(void)
{
uint4 stat;
@@ -261,7 +251,6 @@ void buff_emit(void)
emit_buff_used = 0;
}
-
void set_psect(unsigned char psect,unsigned char offset)
{
current_psect = psect;
@@ -276,8 +265,6 @@ void set_psect(unsigned char psect,unsigned char offset)
* Description: Buffers a definition of a global symbol with the
* given name and value in the given psect.
*/
-
-static struct sym_table *symbols;
struct sym_table *define_symbol(unsigned char psect, mstr *name, int4 value)
{
int cmp;
@@ -341,7 +328,6 @@ void resolve_sym(void)
}
}
-
void output_relocation(void)
{
struct rel_table *rel;
@@ -368,7 +354,6 @@ void output_relocation(void)
assert(cnt == lit_addrs);
}
-
void output_symbol(void)
{
uint4 string_length;
@@ -392,7 +377,6 @@ void output_symbol(void)
}
}
-
void obj_init(void)
{
cdlits = txtrel_cnt = 0;
@@ -400,8 +384,6 @@ void obj_init(void)
symbols = 0;
}
-
-
void emit_literals(void)
{
uint4 offset, padsize;
diff --git a/sr_linux/hugetlbfs_overrides.h b/sr_linux/hugetlbfs_overrides.h
deleted file mode 100644
index f212773..0000000
--- a/sr_linux/hugetlbfs_overrides.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/****************************************************************
- * *
- * Copyright 2012, 2013 Fidelity Information Services, Inc *
- * *
- * This source code contains the intellectual property *
- * of its copyright holder(s), and is made available *
- * under a license. If you do not know the terms of *
- * the license, please stop and do not read further. *
- * *
- ****************************************************************/
-
-#ifndef HUGETLBFS_OVERRIDES_H_
-#define HUGETLBFS_OVERRIDES_H_
-
-#if defined(__linux__) && ( defined(__i386__) || defined(__x86_64__) )
-# define HUGETLB_SUPPORTED 1
-#endif
-
-GBLREF long gtm_os_hugepage_size;
-#define OS_HUGEPAGE_SIZE gtm_os_hugepage_size
-
-extern int gtm_shmget(key_t __key, size_t __size, int __shmflg);
-void libhugetlbfs_init(void);
-
-#endif /* HUGETLBFS_OVERRIDES_H_ */
diff --git a/sr_linux/release_name.h b/sr_linux/release_name.h
index d67cbe3..051fb77 100644
--- a/sr_linux/release_name.h
+++ b/sr_linux/release_name.h
@@ -10,15 +10,15 @@
****************************************************************/
#ifdef __CYGWIN__
-#define GTM_RELEASE_NAME "GT.M V6.2-000 CYGWIN x86"
+#define GTM_RELEASE_NAME "GT.M V6.2-001 CYGWIN x86"
#elif defined(__ia64)
-#define GTM_RELEASE_NAME "GT.M V6.2-000 Linux IA64"
+#define GTM_RELEASE_NAME "GT.M V6.2-001 Linux IA64"
#elif defined(__x86_64__)
-#define GTM_RELEASE_NAME "GT.M V6.2-000 Linux x86_64"
+#define GTM_RELEASE_NAME "GT.M V6.2-001 Linux x86_64"
#elif defined(__s390__)
-#define GTM_RELEASE_NAME "GT.M V6.2-000 Linux S390X"
+#define GTM_RELEASE_NAME "GT.M V6.2-001 Linux S390X"
#else
-#define GTM_RELEASE_NAME "GT.M V6.2-000 Linux x86"
+#define GTM_RELEASE_NAME "GT.M V6.2-001 Linux x86"
#endif
#define GTM_PRODUCT "GT.M"
#define GTM_VERSION "V6.2"
diff --git a/sr_port/advancewindow.c b/sr_port/advancewindow.c
index 39b12d0..802a1cc 100644
--- a/sr_port/advancewindow.c
+++ b/sr_port/advancewindow.c
@@ -26,7 +26,7 @@
#endif
GBLREF unsigned char *source_buffer;
-GBLREF short int source_column;
+GBLREF int source_column;
GBLREF char *lexical_ptr;
GBLREF spdesc stringpool;
GBLREF boolean_t gtm_utf8_mode;
@@ -76,14 +76,15 @@ void advancewindow(void)
TREF(director_token) = TK_EOL;
return; /* if next character is terminator, avoid incrementing past it */
case TK_QUOTE:
- ENSURE_STP_FREE_SPACE(MAX_SRCLINE);
+ ENSURE_STP_FREE_SPACE(TREF(max_advancewindow_line));
cp1 = (unsigned char *)lexical_ptr + 1;
cp2 = cp3 = stringpool.free;
for (;;)
{
# ifdef UNICODE_SUPPORTED
if (gtm_utf8_mode)
- cptr = (unsigned char *)UTF8_MBTOWC((sm_uc_ptr_t)cp1, source_buffer + MAX_SRCLINE, ch);
+ cptr = (unsigned char *)UTF8_MBTOWC((sm_uc_ptr_t)cp1, source_buffer + TREF(max_advancewindow_line),
+ ch);
# endif
x = *cp1++;
if ((SP > x) UNICODE_ONLY(|| (gtm_utf8_mode && !(U_ISPRINT(ch)))))
@@ -178,7 +179,7 @@ void advancewindow(void)
break;
case TK_DIGIT:
(TREF(director_mval)).str.addr = lexical_ptr;
- (TREF(director_mval)).str.len = MAX_SRCLINE;
+ (TREF(director_mval)).str.len = TREF(max_advancewindow_line);
(TREF(director_mval)).mvtype = MV_STR;
lexical_ptr = (char *)s2n(&(TREF(director_mval)));
if (!((TREF(director_mval)).mvtype &= MV_NUM_MASK))
@@ -293,6 +294,9 @@ void advancewindow(void)
*
* All other uses still prohibit '#' from being in an MNAME. Routines that need to allow # in a name can call this routine to
* recombine the existing token and the look-ahead (director) token such that '#' is considered part of an mident.
+ *
+ * Update: Like '#', we need to allow '/' as well to allow for an overriding region name to be specified (where the
+ * trigger needs to be searched. So handle that as well in this same function.
*/
void advwindw_hash_in_mname_allowed(void)
{
@@ -310,9 +314,9 @@ void advwindw_hash_in_mname_allowed(void)
cp2 = ident_buffer + (TREF(window_ident)).len;
cp3 = ident_buffer + MAX_MIDENT_LEN;
*cp2++ = '#'; /* We are only called if director token is '#' so put that char in buffer now */
- /* Start processing with the token following the '#' */
+ /* Start processing with the token following the '#'. Allow '#' and/or '/' in addition to usual stuff. */
for (x = *lexical_ptr, ch = ctypetab[x];
- ((TK_UPPER == ch) || (TK_DIGIT == ch) || (TK_LOWER == ch) || (TK_HASH == ch));
+ ((TK_UPPER == ch) || (TK_DIGIT == ch) || (TK_LOWER == ch) || (TK_HASH == ch) || (TK_SLASH == ch));
x = *++lexical_ptr, ch = ctypetab[x])
{
if (cp2 < cp3)
diff --git a/sr_port/buddy_list.c b/sr_port/buddy_list.c
index d2ca856..6eb3d23 100644
--- a/sr_port/buddy_list.c
+++ b/sr_port/buddy_list.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -183,7 +183,8 @@ char *find_element(buddy_list *list, int4 index)
if (index > list->nElems)
return NULL;
initAllocBits = list->initAllocBits;
- for (i = initAllocBits; index >> i; i++);
+ for (i = initAllocBits; index >> i; i++) /* not sure if "ceil_log2_32bit" would be faster here */
+ ;
i = i - initAllocBits;
return list->ptrArray[i] + list->elemSize * (index - list->initAlloc * (i ? 1 << (i-1) : 0));
}
diff --git a/sr_port/ceil_log2.c b/sr_port/ceil_log2.c
new file mode 100644
index 0000000..c94e213
--- /dev/null
+++ b/sr_port/ceil_log2.c
@@ -0,0 +1,77 @@
+/****************************************************************
+ * *
+ * Copyright 2014 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+#include "mdef.h"
+
+/* ceil_log2_table[i] = # of bits needed to represent i */
+static int ceil_log2_table[] = { 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4 };
+
+/* Compute the ceiling(log_2(num)) where num is a 64-bit quantity */
+int ceil_log2_64bit(gtm_uint64_t num)
+{
+ int ret;
+
+ assert(num);
+ num--;
+ ret = 0;
+ if (((gtm_uint64_t)1 << 32) <= num)
+ {
+ ret += 32;
+ num = num >> 32;
+ }
+ if ((1 << 16) <= num)
+ {
+ ret += 16;
+ num = num >> 16;
+ }
+ if ((1 << 8) <= num)
+ {
+ ret += 8;
+ num = num >> 8;
+ }
+ if ((1 << 4) <= num)
+ {
+ ret += 4;
+ num = num >> 4;
+ }
+ assert(ARRAYSIZE(ceil_log2_table) > num);
+ /* Now that "num" is a small number, use lookup table to speed up computation */
+ ret += ceil_log2_table[num];
+ return ret;
+}
+
+/* Compute the ceiling(log_2(num)) where num is a 32-bit quantity */
+int ceil_log2_32bit(uint4 num)
+{
+ int ret;
+
+ assert(num);
+ num--;
+ ret = 0;
+ if ((1 << 16) <= num)
+ {
+ ret += 16;
+ num = num >> 16;
+ }
+ if ((1 << 8) <= num)
+ {
+ ret += 8;
+ num = num >> 8;
+ }
+ if ((1 << 4) <= num)
+ {
+ ret += 4;
+ num = num >> 4;
+ }
+ assert(ARRAYSIZE(ceil_log2_table) > num);
+ /* Now that "num" is a small number, use lookup table to speed up computation */
+ ret += ceil_log2_table[num];
+ return ret;
+}
diff --git a/sr_port/cmd.c b/sr_port/cmd.c
index 823d70f..0802dde 100644
--- a/sr_port/cmd.c
+++ b/sr_port/cmd.c
@@ -52,7 +52,7 @@ int cmd(void)
* One for full command and one for short-hand notation.
* For example, B and and BREAK.
*/
-LITDEF nametabent cmd_names[] =
+ LITDEF nametabent cmd_names[] =
{
{1, "B"}, {5, "BREAK"}
,{1, "C"}, {5, "CLOSE"}
@@ -97,7 +97,7 @@ LITDEF nametabent cmd_names[] =
,{2, "ZL"}, {5, "ZLINK"}
,{2, "ZM"}, {8, "ZMESSAGE"}
,{2, "ZP"}, {6, "ZPRINT"}
-# ifdef USHBIN_SUPPORTED
+# ifdef AUTORELINK_SUPPORTED
,{3, "ZRU"}, {8, "ZRUPDATE"}
# endif
,{3, "ZSH"}, {5, "ZSHOW"}
@@ -134,7 +134,7 @@ LITDEF unsigned char cmd_index[27] =
{
0, 0, 2, 4, 6, 8, 10, 12, 15, 17, 19, 21, 23
,25, 27, 29, 29, 31, 33, 35, 43, 45, 47, 49
- ,51, 51, 94 GTMTRIG_ONLY(+ 2) USHBIN_ONLY(+ 2) /* add ztrigger and zrupdate, respectively */
+ ,51, 51, 94 GTMTRIG_ONLY(+ 2) ARLINK_ONLY(+ 2) /* add ztrigger and zrupdate, respectively */
};
LITDEF struct
{
@@ -189,7 +189,7 @@ LITDEF struct
,{m_zlink, 1, 1, ALL_SYS}, {m_zlink, 1, 1, ALL_SYS}
,{m_zmessage, 0, 1, ALL_SYS}, {m_zmessage, 0, 1, ALL_SYS}
,{m_zprint, 1, 1, ALL_SYS}, {m_zprint, 1, 1, ALL_SYS}
-# ifdef USHBIN_SUPPORTED
+# ifdef AUTORELINK_SUPPORTED
,{m_zrupdate, 0, 1, ALL_SYS}, {m_zrupdate, 0, 1, ALL_SYS}
# endif
,{m_zshow, 1, 1, ALL_SYS}, {m_zshow, 1, 1, ALL_SYS}
diff --git a/sr_port/code_gen.c b/sr_port/code_gen.c
index 8df4b9f..5902588 100644
--- a/sr_port/code_gen.c
+++ b/sr_port/code_gen.c
@@ -29,7 +29,8 @@ GBLREF triple t_orig; /* head of triples */
GBLREF char cg_phase; /* code generation phase */
GBLREF int4 curr_addr; /* current address */
GBLREF src_line_struct src_head;
-GBLREF short source_column,source_line;
+GBLREF short source_line;
+GBLREF int source_column;
GBLREF int4 pending_errtriplecode; /* if non-zero contains the error code to invoke ins_errtriple with */
void code_gen(void)
diff --git a/sr_port/comp_fini.c b/sr_port/comp_fini.c
index 61c108b..724afde 100644
--- a/sr_port/comp_fini.c
+++ b/sr_port/comp_fini.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -28,7 +28,7 @@
* rts_stringpool to indr_stringpool during compilation setup.
*/
GBLREF spdesc stringpool, rts_stringpool, indr_stringpool;
-GBLREF short int source_column;
+GBLREF int source_column;
GBLREF char cg_phase;
GBLREF unsigned char *source_buffer;
diff --git a/sr_port/comp_init.c b/sr_port/comp_init.c
index 0864ba7..c9788e5 100644
--- a/sr_port/comp_init.c
+++ b/sr_port/comp_init.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -40,8 +40,8 @@ void comp_init(mstr *src, oprtype *dst)
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
- if ((unsigned)src->len >= MAX_SRCLINE)
- rts_error(VARLSTCNT(3) ERR_INDRMAXLEN, 1, MAX_SRCLINE);
+ if ((unsigned)src->len >= TREF(max_advancewindow_line))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_INDRMAXLEN, 1, TREF(max_advancewindow_line));
memcpy(source_buffer,src->addr,src->len);
source_buffer[src->len + 1] = source_buffer[src->len] = 0;
TREF(compile_time) = TRUE;
@@ -57,6 +57,7 @@ void comp_init(mstr *src, oprtype *dst)
indr_stringpool = stringpool;
} else
stringpool = indr_stringpool;
+ mcfree();
tripinit();
lb_init();
assert(TREF(for_stack_ptr) == TADR(for_stack));
diff --git a/sr_port/compile_pattern.c b/sr_port/compile_pattern.c
index 7904f07..2b6d9dc 100644
--- a/sr_port/compile_pattern.c
+++ b/sr_port/compile_pattern.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -24,7 +24,7 @@
GBLREF spdesc stringpool;
GBLREF char *lexical_ptr;
GBLREF unsigned char *source_buffer;
-GBLREF short int source_column;
+GBLREF int source_column;
int compile_pattern(oprtype *opr, boolean_t is_indirect)
{
@@ -70,6 +70,7 @@ int compile_pattern(oprtype *opr, boolean_t is_indirect)
stx_error(status);
return FALSE;
}
+ memset(&retmval, 0, SIZEOF(mval));
retmval.mvtype = MV_STR;
retmval.str.len = retstr.len * SIZEOF(uint4);
retmval.str.addr = (char *)stringpool.free;
diff --git a/sr_port/compiler_startup.c b/sr_port/compiler_startup.c
index 732782e..73c9ba3 100644
--- a/sr_port/compiler_startup.c
+++ b/sr_port/compiler_startup.c
@@ -33,7 +33,8 @@
#define HOPELESS_COMPILE 128
-GBLREF short int source_column, source_line;
+GBLREF short int source_line;
+GBLREF int source_column;
GBLREF unsigned char source_file_name[];
GBLREF unsigned char *source_buffer;
diff --git a/sr_port/db_auto_upgrade.c b/sr_port/db_auto_upgrade.c
index 99dde60..d088d12 100644
--- a/sr_port/db_auto_upgrade.c
+++ b/sr_port/db_auto_upgrade.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -132,8 +132,11 @@ void db_auto_upgrade(gd_region *reg)
case GDSMV60001:
/* GT.M V60002 introduced mutex_spin_parms.mutex_que_entry_space_size */
NUM_CRIT_ENTRY(csd) = DEFAULT_NUM_CRIT_ENTRY;
- break;
case GDSMV60002:
+ /* GT.M V62001 introduced ^#t upgrade. Record this pending event in filehdr. */
+ UNIX_ONLY(csd->hasht_upgrade_needed = TRUE;)
+ break;
+ case GDSMV62001:
/* Nothing to do for this version since it is GDSMVCURR for now. */
assert(FALSE); /* When this assert fails, it means a new GDSMV* was created, */
break; /* so a new "case" needs to be added BEFORE the assert. */
@@ -149,7 +152,7 @@ void db_auto_upgrade(gd_region *reg)
*/
assert(!dse_running);
csd->db_got_to_v5_once = TRUE; /* fix it in PRO */
- send_msg(VARLSTCNT(6) ERR_DBBADUPGRDSTATE, 4, REG_LEN_STR(reg), DB_LEN_STR(reg));
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_DBBADUPGRDSTATE, 4, REG_LEN_STR(reg), DB_LEN_STR(reg));
}
return;
}
diff --git a/sr_port/db_csh_getn.c b/sr_port/db_csh_getn.c
index 00d9fb3..3f37e7a 100644
--- a/sr_port/db_csh_getn.c
+++ b/sr_port/db_csh_getn.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -75,10 +75,10 @@ error_def(ERR_INVALIDRIP);
cache_rec_ptr_t db_csh_getn(block_id block)
{
- cache_rec_ptr_t hdr, q0, start_cr, cr;
+ cache_rec_ptr_t cr, hdr, midnite, our_midnite, q0, start_cr;
bt_rec_ptr_t bt;
unsigned int lcnt, ocnt;
- int rip, max_ent, pass1, pass2, pass3;
+ int max_ent, pass0, pass0cnt, pass1, pass2, pass3, rip;
int4 flsh_trigger;
uint4 first_r_epid, latest_r_epid;
sgmnt_addrs *csa;
@@ -95,15 +95,27 @@ cache_rec_ptr_t db_csh_getn(block_id block)
assert(csa->now_crit);
assert(csa == &FILE_INFO(gv_cur_region)->s_addrs);
max_ent = csd->n_bts;
- cr = (cache_rec_ptr_t)GDS_REL2ABS(csa->nl->cur_lru_cache_rec_off);
hdr = csa->acc_meth.bg.cache_state->cache_array + (block % csd->bt_buckets);
start_cr = csa->acc_meth.bg.cache_state->cache_array + csd->bt_buckets;
- pass1 = max_ent; /* skip referred or dirty or read-into cache records */
- pass2 = 2 * max_ent; /* skip referred cache records */
- pass3 = 3 * max_ent; /* skip nothing */
- dont_flush_buff = gv_cur_region->read_only UNIX_ONLY(||
- (!(dollar_tlevel ? sgm_info_ptr->update_trans : update_trans) && IS_REPL_INST_FROZEN)
- );
+ pass0 = csa->gbuff_limit; /* gbuff_limit set by VIEW "POOLLIMIT":<region> */
+ pass0cnt = (0 == pass0) ? 0 : 2; /* used both as a flag we are limiting and a counter for 2 limited trips */
+ pass1 = max_ent; /* skip referred or dirty or read-into cache records */
+ pass2 = 2 * max_ent; /* skip referred cache records */
+ pass3 = 3 * max_ent; /* skip nothing */
+ midnite = start_cr + max_ent; /* "on the clock" - point at which we have to wrap or change tactics */
+ cr = (cache_rec_ptr_t)GDS_REL2ABS(csa->nl->cur_lru_cache_rec_off);
+ if (pass0cnt)
+ {
+ our_midnite = csa->our_midnite; /* local copy of private "hand" for efficiency - only used if pass0cnt */
+ cr = our_midnite - pass0; /* direct this process to an area behind our chosen spot */
+ if (cr < start_cr)
+ cr += max_ent; /* we have to wrap before we use our_midnite */
+ else
+ midnite = our_midnite;
+ }
+ assert((start_cr <= cr) && ((start_cr + max_ent) > cr));
+ dont_flush_buff = gv_cur_region->read_only
+ UNIX_ONLY(|| (!(dollar_tlevel ? sgm_info_ptr->update_trans : update_trans) && IS_REPL_INST_FROZEN));
INCR_DB_CSH_COUNTER(csa, n_db_csh_getns, 1);
DEFER_INTERRUPTS(INTRPT_IN_DB_CSH_GETN);
for (lcnt = 0; ; lcnt++)
@@ -115,8 +127,36 @@ cache_rec_ptr_t db_csh_getn(block_id block)
break;
}
cr++;
- if (cr == start_cr + max_ent)
+ if (cr == midnite)
+ {
cr = start_cr;
+ if (pass0cnt)
+ { /* doing restricted looking */
+ if (midnite != our_midnite)
+ { /* "ordinary" end of buffer - wrap and set up private stop */
+ assert((start_cr + max_ent) == midnite);
+ midnite = our_midnite;
+ } else
+ { /* the end of our restricted area */
+ if (--pass0cnt)
+ { /* if limiting and in pass0, do a 2nd scan of the limit area */
+ cr = our_midnite - pass0; /* in our restricted area */
+ if (cr < start_cr)
+ { /* wrap before our_midnite */
+ cr += max_ent;
+ midnite = start_cr + max_ent;
+ }
+ } else
+ { /* or the limited area did not suffice - adopt the normal clock */
+ cr = (cache_rec_ptr_t)GDS_REL2ABS(csa->nl->cur_lru_cache_rec_off);
+ midnite = start_cr + max_ent;
+ }
+ assert((pass0cnt + lcnt) == pass0);
+ lcnt = 0;
+ }
+ }
+ }
+ assert((start_cr <= cr) && ((start_cr + max_ent) > cr));
VMS_ONLY(
if ((lcnt == pass1) || (lcnt == pass2))
wcs_wtfini(gv_cur_region);
@@ -266,7 +306,7 @@ cache_rec_ptr_t db_csh_getn(block_id block)
if (cr->read_in_progress < -1)
{
BG_TRACE_PRO(db_csh_getn_out_of_design); /* outside of design; clear to known state */
- send_msg(VARLSTCNT(4) ERR_INVALIDRIP, 2, DB_LEN_STR(gv_cur_region));
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_INVALIDRIP, 2, DB_LEN_STR(gv_cur_region));
assert(cr->r_epid == 0);
cr->r_epid = 0;
INTERLOCK_INIT(cr);
@@ -295,12 +335,11 @@ cache_rec_ptr_t db_csh_getn(block_id block)
BG_TRACE_PRO(db_csh_getn_buf_owner_stuck);
if (0 != latest_r_epid)
{
- if (first_r_epid != latest_r_epid)
- GTMASSERT;
+ assertpro(first_r_epid == latest_r_epid);
GET_C_STACK_FROM_SCRIPT("BUFRDTIMEOUT", process_id, latest_r_epid,
DEBUG_ONLY(TWICE) PRO_ONLY(ONCE));
RELEASE_BUFF_READ_LOCK(cr);
- send_msg(VARLSTCNT(8) ERR_BUFRDTIMEOUT, 6, process_id,
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_BUFRDTIMEOUT, 6, process_id,
cr->blk, cr, first_r_epid, DB_LEN_STR(gv_cur_region));
continue;
}
@@ -348,7 +387,8 @@ cache_rec_ptr_t db_csh_getn(block_id block)
q0 = (cache_rec_ptr_t)((sm_uc_ptr_t)cr + cr->blkque.fl);
shuffqth((que_ent_ptr_t)q0, (que_ent_ptr_t)hdr);
assert(0 == cr->dirty);
- csa->nl->cur_lru_cache_rec_off = GDS_ABS2REL(cr);
+ if (!pass0cnt)
+ csa->nl->cur_lru_cache_rec_off = GDS_ABS2REL(cr);
if (lcnt > pass1)
csa->nl->cache_hits = 0;
csa->nl->cache_hits++;
diff --git a/sr_port/dbcertify_certify_phase.c b/sr_port/dbcertify_certify_phase.c
index 2dc32e7..dbe0c9b 100644
--- a/sr_port/dbcertify_certify_phase.c
+++ b/sr_port/dbcertify_certify_phase.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2005, 2013 Fidelity Information Services, Inc *
+ * Copyright 2005, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -149,11 +149,11 @@ void dbcertify_certify_phase(void)
{
save_errno = errno;
if (save_errno == ENOENT)
- rts_error(VARLSTCNT(4) ERR_FILENOTFND, 2, RTS_ERROR_STRING((char_ptr_t)psa->outfn));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_FILENOTFND, 2, RTS_ERROR_STRING((char_ptr_t)psa->outfn));
else
{
errmsg = STRERROR(save_errno);
- rts_error(VARLSTCNT(8) ERR_DEVOPENFAIL, 2, RTS_ERROR_STRING((char_ptr_t)psa->outfn),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DEVOPENFAIL, 2, RTS_ERROR_STRING((char_ptr_t)psa->outfn),
ERR_TEXT, 2, RTS_ERROR_STRING(errmsg));
}
}
@@ -163,10 +163,10 @@ void dbcertify_certify_phase(void)
#endif
dbc_read_p1out(psa, &psa->ofhdr, SIZEOF(p1hdr)); /* Read phase 1 output file header */
if (0 != memcmp(psa->ofhdr.p1hdr_tag, P1HDR_TAG, SIZEOF(psa->ofhdr.p1hdr_tag)))
- rts_error(VARLSTCNT(4) ERR_DBCBADFILE, 2, RTS_ERROR_STRING((char_ptr_t)psa->outfn));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBCBADFILE, 2, RTS_ERROR_STRING((char_ptr_t)psa->outfn));
if (0 == psa->ofhdr.tot_blocks)
/* Sanity check that the output file was finished and completed */
- rts_error(VARLSTCNT(4) ERR_DBCSCNNOTCMPLT, 2, RTS_ERROR_STRING((char_ptr_t)psa->outfn));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBCSCNNOTCMPLT, 2, RTS_ERROR_STRING((char_ptr_t)psa->outfn));
assert(0 != psa->ofhdr.tn);
/* Check if region name still associates to the same file */
@@ -207,9 +207,9 @@ void dbcertify_certify_phase(void)
dbc_init_db(psa);
if (0 != strcmp((char_ptr_t)psa->dbc_gv_cur_region->dyn.addr->fname, (char_ptr_t)psa->ofhdr.dbfn))
/* File name change means db was moved or at least is not as it was when it was scanned */
- rts_error(VARLSTCNT(1) ERR_DBCNOTSAMEDB);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DBCNOTSAMEDB);
if (psa->ofhdr.tn > psa->dbc_cs_data->trans_hist.curr_tn)
- rts_error(VARLSTCNT(1) ERR_DBCNOTSAMEDB);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DBCNOTSAMEDB);
psa->max_blk_len = psa->dbc_cs_data->blk_size - psa->dbc_cs_data->reserved_bytes;
/* Initialize maximum key we may need later if we encounter gvtroot blocks */
@@ -265,7 +265,7 @@ void dbcertify_certify_phase(void)
if (0 != psa->rhdr.akey_len)
{ /* This module does not need the ascii key so just bypass it if it exists */
if (0 != psa->rhdr.blk_levl || SIZEOF(psa->rslt_buff) < psa->rhdr.akey_len )
- GTMASSERT; /* Must be corrupted file? */
+ assertpro(FALSE); /* Must be corrupted file? */
dbc_read_p1out(psa, (char_ptr_t)psa->rslt_buff, psa->rhdr.akey_len);
}
p1rec_read = TRUE; /* Note, not reset by restarted transaction */
@@ -278,7 +278,7 @@ void dbcertify_certify_phase(void)
{
++restart_cnt;
if (MAX_RESTART_CNT < restart_cnt)
- GTMASSERT; /* No idea what could cause this.. */
+ assertpro(FALSE); /* No idea what could cause this.. */
DBC_DEBUG(("DBC_DEBUG: ****************** Restarted transaction (%d) *****************\n",
(rec_num + 1)));
/* "restart_transaction" is either set or cleared by dbc_split_blk() below */
@@ -302,14 +302,14 @@ void dbcertify_certify_phase(void)
{
((sgmnt_data_ptr_t)psa->dbc_cs_data)->certified_for_upgrade_to = GDSV6;
psa->dbc_fhdr_dirty = TRUE;
- gtm_putmsg(VARLSTCNT(6) ERR_DBCDBCERTIFIED, 4, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn),
- RTS_ERROR_LITERAL("GT.M V5"));
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_DBCDBCERTIFIED, 4,
+ RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn), RTS_ERROR_LITERAL("GT.M V5"));
} else
{
DBC_DEBUG(("DBC_DEBUG: Database certification bypassed due to records to process limit being reached\n"));
}
} else
- gtm_putmsg(VARLSTCNT(4) ERR_DBCDBNOCERTIFY, 2, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn));
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBCDBNOCERTIFY, 2, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn));
dbc_flush_fhead(psa);
dbc_close_db(psa);
@@ -351,6 +351,8 @@ void dbcertify_certify_phase(void)
if (psa->first_rec_key)
free(psa->first_rec_key);
free(psa);
+ assert(psa == psa_gbl);
+ psa_gbl = NULL; /* nullify the global variable now that it has been freed */
}
/* Routine to handle the processing (splitting) of a given database block. If the current block process needs
@@ -473,7 +475,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
3) There was a TN reset done.
All three of these causes require a rerun of the scan phase.
*/
- rts_error(VARLSTCNT(3) ERR_DBCMODBLK2BIG, 1, blk_num);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_DBCMODBLK2BIG, 1, blk_num);
}
/* Isolate the full key in the first record of the block */
dbc_init_key(psa, &psa->first_rec_key);
@@ -524,9 +526,9 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
if (0 > blk_index)
{ /* Integrity error encountered or record not found. We cannot proceed */
assert(FALSE);
- rts_error(VARLSTCNT(8) ERR_DBCINTEGERR, 2, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn),
- ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Unable to find index (DT) record for an existing global"));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8)
+ ERR_DBCINTEGERR, 2, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn),
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to find index (DT) record for an existing global"));
}
break;
case gdsblk_gvtindex:
@@ -536,8 +538,9 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
if (0 > dtblk_index)
{ /* Integrity error encountered or record not found. We cannot proceed */
assert(FALSE);
- rts_error(VARLSTCNT(8) ERR_DBCINTEGERR, 2, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn),
- ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to locate DT leaf (root) block"));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8)
+ ERR_DBCINTEGERR, 2, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn),
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to locate DT leaf (root) block"));
}
assert(0 == ((v15_blk_hdr_ptr_t)psa->blk_set[dtblk_index].old_buff)->levl);
/* Note level 0 directory blocks can have collation data in them but it would be AFTER
@@ -559,7 +562,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
if (-1 == blk_index)
{ /* Integrity error encountered. We cannot proceed */
assert(FALSE);
- rts_error(VARLSTCNT(8) ERR_DBCINTEGERR, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DBCINTEGERR, 2,
RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn),
ERR_TEXT, 2,
RTS_ERROR_LITERAL("Unable to find index record for an existing global"));
@@ -584,7 +587,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
}
return FALSE; /* No restart necessary */
} else
- GTMASSERT;
+ assertpro(FALSE);
}
} else
{ /* This is a gvtroot block and is the subject of our search */
@@ -593,7 +596,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
}
break;
default:
- GTMASSERT;
+ assertpro(FALSE);
}
/* The most recently accessed block (that terminated the search) should be the block
we are looking for (which should have been found in the cache as block 0. If not,
@@ -602,7 +605,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
if (0 != blk_index)
{ /* Integrity error encountered. We cannot proceed */
assert(FALSE);
- rts_error(VARLSTCNT(8) ERR_DBCINTEGERR, 2, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DBCINTEGERR, 2, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn),
ERR_TEXT, 2,
RTS_ERROR_LITERAL("Did not locate record in same block as we started searching for"));
}
@@ -846,7 +849,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
blk_set_p->curr_rec + remain_offset,
remain_len - remain_offset);
if (0 == BLK_FINI(bs_ptr, bs1))
- GTMASSERT;
+ assertpro(FALSE);
assert(blk_seg_cnt == new_blk_len);
DBC_DEBUG(("DBC_DEBUG: Stopping block scan after simple update (no further inserts to previous lvls)\n"));
completed = TRUE;
@@ -912,7 +915,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
/* Common initialization */
++psa->block_depth; /* Need a new block to split into */
if (MAX_BLOCK_INFO_DEPTH <= psa->block_depth)
- GTMASSERT;
+ assertpro(FALSE);
DBC_DEBUG(("DBC_DEBUG: Block index %d used for newly created split (lhs) block\n", psa->block_depth));
blk_set_new_p = &psa->blk_set[psa->block_depth];
dbc_init_blk(psa, blk_set_new_p, -1, gdsblk_create, new_lh_blk_len, curr_blk_levl);
@@ -944,7 +947,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
* it by NOT certifying the database and requiring a rerun of the SCAN
*/
assert(FALSE);
- gtm_putmsg(VARLSTCNT(6) ERR_DBCREC2BIGINBLK, 4,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_DBCREC2BIGINBLK, 4,
blk_num, psa->dbc_cs_data->max_rec_size,
psa->dbc_gv_cur_region->dyn.addr->fname_len,
psa->dbc_gv_cur_region->dyn.addr->fname);
@@ -970,7 +973,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
}
/* Complete our LHS block */
if (0 == BLK_FINI(bs_ptr, bs1))
- GTMASSERT;
+ assertpro(FALSE);
assert(blk_seg_cnt == new_lh_blk_len);
/* Remember key of last record in this block */
if (0 == ins_rec_len)
@@ -1006,7 +1009,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
DBC_DEBUG(("DBC_DEBUG: Splitting root block, extra block to be created\n"));
++psa->block_depth; /* Need a new block to split into */
if (MAX_BLOCK_INFO_DEPTH <= psa->block_depth)
- GTMASSERT;
+ assertpro(FALSE);
blk_set_rhs_p = &psa->blk_set[psa->block_depth];
dbc_init_blk(psa, blk_set_rhs_p, -1, gdsblk_create, new_rh_blk_len, curr_blk_levl);
/* We will put the pointers to both this block and the RHS we build next
@@ -1037,7 +1040,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
curr_blk_len - curr_rec_offset - SIZEOF(rec_hdr));
/* Complete update array */
if (0 == BLK_FINI(bs_ptr, bs1))
- GTMASSERT;
+ assertpro(FALSE);
assert(blk_seg_cnt == new_rh_blk_len);
} else
{ /* Recompute sizes for inserted record being in righthand block as per
@@ -1071,7 +1074,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
*/
if (curr_blk_len <= psa->max_blk_len)
/* Well, that wasn't the problem, something else is wrong */
- rts_error(VARLSTCNT(8) ERR_DBCINTEGERR, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DBCINTEGERR, 2,
RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn),
ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to split block appropriately"));
/* If we do have to restart, we won't be able to reinvoke dbc_split_blk() with the
@@ -1084,7 +1087,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
++restart_cnt)
{
if (MAX_RESTART_CNT < restart_cnt)
- GTMASSERT; /* No idea what could cause this */
+ assertpro(FALSE); /* No idea what could cause this */
DBC_DEBUG(("DBC_DEBUG: *** *** Recursive call to handle too large block 0x%x\n",
restart_blk_set.blk_num));
psa->block_depth_hwm = -1; /* Zaps cache so all blocks are re-read */
@@ -1116,7 +1119,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
BLK_SEG(bs_ptr, blk_set_p->curr_rec - SIZEOF(block_id), SIZEOF(block_id));
/* Complete our LHS block */
if (0 == BLK_FINI(bs_ptr, bs1))
- GTMASSERT;
+ assertpro(FALSE);
assert(blk_seg_cnt == new_lh_blk_len);
if (!got_root)
{
@@ -1148,7 +1151,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
DBC_DEBUG(("DBC_DEBUG: Splitting root block, extra block to be created\n"));
++psa->block_depth; /* Need a new block to split into */
if (MAX_BLOCK_INFO_DEPTH <= psa->block_depth)
- GTMASSERT;
+ assertpro(FALSE);
blk_set_rhs_p = &psa->blk_set[psa->block_depth];
/* Key for last record in the LHS block used to (re)construct root block */
last_rec_key = blk_set_p->curr_blk_key;
@@ -1191,7 +1194,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
blk_set_p->curr_rec + remain_offset,
remain_len - remain_offset);
if (0 == BLK_FINI(bs_ptr, bs1))
- GTMASSERT;
+ assertpro(FALSE);
assert(blk_seg_cnt == new_rh_blk_len);
} /* else method (2) */
if (got_root)
@@ -1207,7 +1210,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
blk_set_p->blk_levl++; /* Needs to be at a new level */
if (MAX_BT_DEPTH <= blk_set_p->blk_levl)
/* Tree is too high */
- GTMASSERT;
+ assertpro(FALSE);
/* First record will have last key in LHS block */
BLK_ADDR(next_rec_hdr, SIZEOF(rec_hdr), rec_hdr);
next_rec_hdr->rsiz = SIZEOF(rec_hdr) + last_rec_key->end + 1 + SIZEOF(block_id);
@@ -1227,7 +1230,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
blk_set_rhs_p->ins_blk_id_p = rhs_block_id_p; /* Receives block id when created */
/* Complete update array */
if (0 == BLK_FINI(bs_ptr, bs1))
- GTMASSERT;
+ assertpro(FALSE);
/* The root block is the last one we need to change */
DBC_DEBUG(("DBC_DEBUG: Stopping block scan as blk_index %d is a root block\n", blk_index));
completed = TRUE;
@@ -1272,7 +1275,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
*/
dbc_init_db(psa);
if (created_blocks > psa->dbc_cs_data->trans_hist.free_blocks)
- rts_error(VARLSTCNT(4) ERR_DBCNOEXTND, 2, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBCNOEXTND, 2, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn));
/* Database is now extended -- safest bet is to restart this particular update so that it is certain
nothing else got in besides the extention.
*/
@@ -1306,8 +1309,8 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
if (NO_FREE_SPACE == lclmap_not_full)
{
assert(FALSE);
- rts_error(VARLSTCNT(5) ERR_DBCINTEGERR, 2, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn),
- ERR_BITMAPSBAD);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5)
+ ERR_DBCINTEGERR, 2, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn), ERR_BITMAPSBAD);
}
if (ROUND_DOWN2(psa->hint_blk, psa->dbc_cs_data->bplmap) != lclmap_not_full)
psa->hint_lcl = 1;
@@ -1328,8 +1331,8 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
if (NO_FREE_SPACE == lcl_blk)
{
assert(FALSE);
- rts_error(VARLSTCNT(5) ERR_DBCINTEGERR, 2, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn),
- ERR_BITMAPSBAD);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5)
+ ERR_DBCINTEGERR, 2, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn), ERR_BITMAPSBAD);
}
/* Found a free block, mark it busy. Note that bitmap blocks are treated somewhat differently
than other blocks. We do not create an update array for them but just change the copy in
@@ -1437,7 +1440,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
psa->dbc_cs_data->trans_hist.curr_tn++;
psa->dbc_fhdr_dirty = TRUE;
} else
- GTMASSERT; /* If we got this far we should have split a block which would create a block */
+ assertpro(FALSE); /* If we got this far we should have split a block which would create a block */
DBC_DEBUG(("DBC_DEBUG: Block processing completed\n"));
psa->blks_processed++;
@@ -1470,7 +1473,7 @@ void dbc_read_p1out(phase_static_area *psa, void *obuf, int olen)
save_errno = errno;
errmsg = STRERROR(save_errno);
assert(FALSE);
- rts_error(VARLSTCNT(11) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("read()"), CALLFROM,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(11) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("read()"), CALLFROM,
ERR_TEXT, 2, RTS_ERROR_STRING(errmsg));
}
}
@@ -1481,12 +1484,14 @@ void dbc_certify_phase_cleanup(void)
phase_static_area *psa;
psa = psa_gbl;
+ if (NULL == psa)
+ return;
if (psa->dbc_gv_cur_region && psa->dbc_gv_cur_region->dyn.addr && psa->dbc_gv_cur_region->dyn.addr->file_cntl)
{
dbc_flush_fhead(psa);
dbc_close_db(psa);
if (psa->dbc_critical)
- rts_error(VARLSTCNT(4) ERR_TEXT,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT,
2, RTS_ERROR_LITERAL("Failure while in critical section -- database damage likely"));
}
UNIX_ONLY(dbc_release_standalone_access(psa));
diff --git a/sr_port/dbcertify_scan_phase.c b/sr_port/dbcertify_scan_phase.c
index ba74a7c..ef495f2 100644
--- a/sr_port/dbcertify_scan_phase.c
+++ b/sr_port/dbcertify_scan_phase.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2005, 2013 Fidelity Information Services, Inc *
+ * Copyright 2005, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -420,6 +420,8 @@ void dbcertify_scan_phase(void)
psa->iebl = iebl;
}
free(psa);
+ assert(psa == psa_gbl);
+ psa_gbl = NULL; /* nullify the global variable now that it has been freed */
}
/* Write the given output record but keep the global variable "chksum" updated with the tally.
@@ -853,16 +855,21 @@ uchar_ptr_t dbc_format_key(phase_static_area *psa, uchar_ptr_t trec_p)
/* Simple cleanup routine for this scan phaase */
void dbc_scan_phase_cleanup(void)
{
+ phase_static_area *psa;
+
+ psa = psa_gbl;
+ if (NULL == psa)
+ return;
/* Cleanup our temporary files */
- if (psa_gbl->tmp_file_names_gend)
+ if (psa->tmp_file_names_gend)
{ /* only close/delete if we know what they are */
- if (psa_gbl->tcfp)
- dbc_close_command_file(psa_gbl);
- if (!psa_gbl->keep_temp_files)
- dbc_remove_command_file(psa_gbl);
- if (psa_gbl->trfp)
- dbc_close_result_file(psa_gbl);
- if (!psa_gbl->keep_temp_files)
- dbc_remove_result_file(psa_gbl);
+ if (psa->tcfp)
+ dbc_close_command_file(psa);
+ if (!psa->keep_temp_files)
+ dbc_remove_command_file(psa);
+ if (psa->trfp)
+ dbc_close_result_file(psa);
+ if (!psa->keep_temp_files)
+ dbc_remove_result_file(psa);
}
}
diff --git a/sr_port/dse.hlp b/sr_port/dse.hlp
index 3b0c3c1..c586487 100644
--- a/sr_port/dse.hlp
+++ b/sr_port/dse.hlp
@@ -244,19 +244,15 @@
the above command looks like the following:
Block 3 Size 4B Level 0 TN 6 V5
-
Rec:1 Blk 3 Off 10 Size 14 Cmpc 0 Key ^Fruits(1)
10 : | 14 0 0 0 46 72 75 69 74 73 0 BF 11 0 0 41 70 70 6C 65|
| . . . . F r u i t s . . . . . A p p l e|
-
Rec:2 Blk 3 Off 24 Size D Cmpc 8 Key ^Fruits(2)
24 : | D 0 8 0 21 0 0 42 61 6E 61 6E 61 |
| . . . . ! . . B a n a n a |
-
Rec:3 Blk 3 Off 31 Size D Cmpc 8 Key ^Fruits(3)
31 : | D 0 8 0 31 0 0 43 68 65 72 72 79 |
| . . . . 1 . . C h e r r y |
-
Rec:4 Blk 3 Off 3E Size D Cmpc 8 Key ^Fruits(4)
3E : | D 0 8 8 41 0 0 47 72 61 70 65 73 |
| . . . . A . . G r a p e s |
@@ -1216,7 +1212,6 @@
DSE> CACHE -VERIFY -ALL
Time 26-FEB-2011 14:31:30 : Region DEFAULT : Cache verification is clean
-
Execute CACHE recover command if Cache verification is "NOT" clean.
This command reports the state of database cache for all regions.
@@ -1233,7 +1228,6 @@
DSE> CACHE -SHOW
File /home/jdoe/node1/areg.dat
Region AREG
-
Region AREG : Shared_memory = 0x00002B6845040000
Region AREG : node_local = 0x0000000000000000
Region AREG : critical = 0x0000000000010000
@@ -1248,7 +1242,6 @@
Region AREG : th_base = 0x00000000002C71D0
Region AREG : bt_record = 0x00000000002C7200 : Numelems = 0x00000400 : Elemsize = 0x00000040
Region AREG : shared_memory_size = 0x00000000002D8000
-
DSE>
2 CLose
@@ -1499,7 +1492,6 @@
File /home/jdoe/.fis-gtm/V6.1-000_x86_64/g/gtm.dat
Region DEFAULT
-
File /home/jdoe/.fis-gtm/V6.1-000_x86_64/g/gtm.dat
Region DEFAULT
Date/Time 27-JAN-2014 03:13:40 [$H = 63214,11620]
@@ -1589,7 +1581,6 @@
Example:
DSE> evaluate -number=10 -decimal
-
Hex: A Dec: 10
This command displays the hexadecimal equivalent of decimal number 10.
@@ -1597,7 +1588,6 @@
Example:
DSE> evaluate -number=10 -hexadecimal
-
Hex: 10 Dec: 16
This command displays the decimal equivalent of hexadecimal 10.
@@ -1605,7 +1595,6 @@
Example:
$ dse evaluate -number=10
-
Hex: 10 Dec: 16
This command displays the decimal equivalent of Hexadecimal 10. Note that
@@ -1759,7 +1748,6 @@
Directory path
Path--blk:off
1:10 2:1E
-
Global paths
Path--blk:off
6:51 1A4:249 180
@@ -1772,7 +1760,6 @@
Example:
DSE> find -free -hint=180
-
Next free block is D8F.
This command locates the "closest" free block to block 180.
@@ -1947,7 +1934,6 @@
Block 1A0: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX |
Block 1C0: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX |
Block 1E0: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX |
-
'X' == BUSY '.' == FREE ':' == REUSABLE '?' == CORRUPT
Note that BLOCK 20 is marked as REUSABLE, which means FREE but in need of
@@ -1961,7 +1947,6 @@
is as follows:
Block 0 Size 90 Level -1 TN 1 V5 Master Status: Free Space
-
Low order High order
Block 0: | XXX..... ........ ........ ........ |
Block 20: | X....... ........ ........ ........ |
@@ -1979,7 +1964,6 @@
Block 1A0: | ........ ........ ........ ........ |
Block 1C0: | ........ ........ ........ ........ |
Block 1E0: | ........ ........ ........ ........ |
-
'X' == BUSY '.' == FREE ':' == REUSABLE '?' == CORRUPT
Note that the BLOCK 20 is marked as BUSY.
@@ -2009,7 +1993,6 @@
Example:
DSE> OPEN
-
Current output file: var.out
This command displays the current output file. In this case, the output
@@ -2176,7 +2159,6 @@
Example:
DSE> range -lower="^Fruits(15)" -upper="^Fruits(877)" -from=A -to=F
-
Blocks in the specified key range:
Block: 0000000A Level: 0
Block: 0000000B Level: 0
@@ -2184,7 +2166,6 @@
Block: 0000000D Level: 0
Block: 0000000E Level: 0
Block: 0000000F Level: 0
-
Found 6 blocks
This command search for keys between ^Fruits(15) and ^Fruits(877).
@@ -2845,15 +2826,16 @@
Copyright 2014
- Fidelity Information Services, Inc. All rights reserved.
+ Fidelity National Information Services, Inc. and/or its subsidiaries. All
+ rights reserved.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or any
later version published by the Free Software Foundation; with no Invariant
Sections, no Front-Cover Texts and no Back-Cover Texts.
- GT.M(TM) is a trademark of Fidelity Information Services, Inc. Other
- trademarks are the property of their respective owners.
+ GT.M(TM) is a trademark of Fidelity National Information Services, Inc.
+ Other trademarks are the property of their respective owners.
This document contains a description of GT.M and the operating
instructions pertaining to the various functions that comprise the system.
@@ -2864,7 +2846,7 @@
**Note**
- This help file is a concise representation of revision V6.2-000 of the
+ This help file is a concise representation of revision V6.2-001 of the
UNIX Administration and Operations Guide. To obtain a copy of the current
revision, go to www.fis-gtm.com and then click on the User Documentation
tab.
diff --git a/sr_port/dse_adrec.c b/sr_port/dse_adrec.c
index 0e55bcf..ec0ad4e 100644
--- a/sr_port/dse_adrec.c
+++ b/sr_port/dse_adrec.c
@@ -126,11 +126,11 @@ void dse_adrec(void)
free(lbp);
return;
}
- if (key_len + data_len > csa->hdr->max_rec_size)
+ if (VMS_ONLY(key_len + ) data_len > csa->hdr->max_rec_size)
{
t_abort(gv_cur_region, csa);
free(lbp);
- rts_error_csa(CSA_ARG(csa) VARLSTCNT(10) ERR_REC2BIG, 4, key_len + data_len,
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(10) ERR_REC2BIG, 4, VMS_ONLY(key_len + ) data_len,
(int4)csa->hdr->max_rec_size, REG_LEN_STR(gv_cur_region), ERR_GVIS, 2, LEN_AND_STR(key));
}
}
diff --git a/sr_port/dse_chng_fhead.c b/sr_port/dse_chng_fhead.c
index 1eaf09d..69c146a 100644
--- a/sr_port/dse_chng_fhead.c
+++ b/sr_port/dse_chng_fhead.c
@@ -572,14 +572,7 @@ void dse_chng_fhead(void)
cs_data->db_got_to_v5_once = TRUE;
}
if (CLI_PRESENT == cli_present("GVSTATSRESET"))
- {
- /* Clear statistics in NODE-LOCAL first */
-# define TAB_GVSTATS_REC(COUNTER,TEXT1,TEXT2) cs_addrs->nl->gvstats_rec.COUNTER = 0;
-# include "tab_gvstats_rec.h"
-# undef TAB_GVSTATS_REC
- /* Do it in the file-header next */
- gvstats_rec_cnl2csd(cs_addrs);
- }
+ CLRGVSTATS(cs_addrs);
if (CLI_PRESENT == cli_present("ONLINE_NBB"))
{
buf_len = SIZEOF(buf);
diff --git a/sr_port/dse_getki.c b/sr_port/dse_getki.c
index c5d5ff3..230bc72 100644
--- a/sr_port/dse_getki.c
+++ b/sr_port/dse_getki.c
@@ -44,8 +44,6 @@ GBLREF sgmnt_addrs *cs_addrs;
GBLREF gd_region *gv_cur_region;
GBLREF gv_namehead *gv_target;
-LITREF mval literal_hasht;
-
int dse_getki(char *dst, int *len, char *qual, int qual_len)
{
char buf[MAX_ZWR_KEY_SZ], *src, *temp_dst, *bot, *top, *tmp, slit[MAX_KEY_SZ + 1], key_buf[MAX_KEY_SZ + 1];
diff --git a/sr_port/dump_record.c b/sr_port/dump_record.c
index 5a09882..e67f80d 100644
--- a/sr_port/dump_record.c
+++ b/sr_port/dump_record.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -52,8 +52,6 @@ GBLREF int patch_fdmp_recs;
GBLREF gd_region *gv_cur_region;
GBLREF gv_namehead *gv_target;
-LITREF mval literal_hasht;
-
#define MAX_UTIL_LEN 80
#define NUM_BYTES_PER_LINE 20
diff --git a/sr_port/entryref.c b/sr_port/entryref.c
index e32b866..cd1d8cd 100644
--- a/sr_port/entryref.c
+++ b/sr_port/entryref.c
@@ -238,7 +238,7 @@ triple *entryref(opctype op1, opctype op2, mint commargcode, boolean_t can_comma
return rettrip;
}
-#ifdef USHBIN_SUPPORTED
+#ifdef AUTORELINK_SUPPORTED
/* Routine used in a USHBIN build (UNIX Shared BInary) to generate the triples to reference (call, extrinsic or goto)
* an external routine. This version calls additional opcodes to dynamically autorelink routines if the routine has been
* changed since it was last linked if autorelinking is enabled. This requires that all such M-calls with a routine specified
diff --git a/sr_port/error.h b/sr_port/error.h
index d107bdf..8559143 100644
--- a/sr_port/error.h
+++ b/sr_port/error.h
@@ -102,9 +102,11 @@ CONDITION_HANDLER(iomt_ch);
CONDITION_HANDLER(jnl_file_autoswitch_ch);
CONDITION_HANDLER(job_init_ch);
CONDITION_HANDLER(jobexam_dump_ch);
+#ifdef VMS
CONDITION_HANDLER(lastchance1);
CONDITION_HANDLER(lastchance2);
CONDITION_HANDLER(lastchance3);
+#endif
CONDITION_HANDLER(mdb_condition_handler);
CONDITION_HANDLER(mu_freeze_ch);
CONDITION_HANDLER(mu_int_ch);
diff --git a/sr_port/exfunc.c b/sr_port/exfunc.c
index 520aa0d..8ea8fc9 100644
--- a/sr_port/exfunc.c
+++ b/sr_port/exfunc.c
@@ -58,7 +58,7 @@ int exfunc(oprtype *a, boolean_t alias_target)
{
if (OC_CDLIT == calltrip_opr1_tref->opcode)
assert(CDLT_REF == calltrip_opr1_tref->operand[0].oprclass);
- else USHBIN_ONLY(if (OC_LAB_EXT != calltrip_opr1_tref->opcode))
+ else ARLINK_ONLY(if (OC_LAB_EXT != calltrip_opr1_tref->opcode))
{
assert(OC_LABADDR == calltrip_opr1_tref->opcode);
assert(TRIP_REF == calltrip_opr1_tref->operand[1].oprclass);
diff --git a/sr_port/expritem.c b/sr_port/expritem.c
index 1b2588e..b39c0df 100644
--- a/sr_port/expritem.c
+++ b/sr_port/expritem.c
@@ -106,6 +106,7 @@ LITDEF nametabent svn_names[] =
,{ 3, "ZSY*"}
,{ 4, "ZTCO*"}
,{ 4, "ZTDA*"}
+ ,{ 4, "ZTDE*"}
,{ 3, "ZTE" }, { 4, "ZTEX*"}
,{ 4, "ZTLE*"}
,{ 4, "ZTNA*"}
@@ -125,7 +126,7 @@ LITDEF nametabent svn_names[] =
LITDEF unsigned char svn_index[27] = {
0, 0, 0, 0, 2, 8, 8, 8, 10, /* a b c d e f g h i */
12, 14 ,16, 16, 16, 16, 16, 18, 20, /* j k l m n o p q r */
- 22, 28, 34 ,34, 34, 34, 35, 36, 92 /* s t u v w x y z ~ */
+ 22, 28, 34 ,34, 34, 34, 35, 36, 93 /* s t u v w x y z ~ */
};
/* These entries correspond to the entries in the svn_names array */
@@ -188,6 +189,7 @@ LITDEF svn_data_type svn_data[] =
,{ SV_ZSYSTEM, FALSE, ALL_SYS }
,{ SV_ZTCODE, FALSE, TRIGGER_OS }
,{ SV_ZTDATA, FALSE, TRIGGER_OS }
+ ,{ SV_ZTDELIM, FALSE, TRIGGER_OS }
,{ SV_ZTEXIT, TRUE, ALL_SYS }, { SV_ZTEXIT, TRUE, ALL_SYS }
,{ SV_ZTLEVEL, FALSE, TRIGGER_OS}
,{ SV_ZTNAME, FALSE, TRIGGER_OS }
diff --git a/sr_port/f_get.c b/sr_port/f_get.c
index 8a515a5..a3cad57 100644
--- a/sr_port/f_get.c
+++ b/sr_port/f_get.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -23,7 +23,7 @@
#include "show_source_line.h"
GBLREF boolean_t run_time;
-GBLREF short int source_column;
+GBLREF int source_column;
error_def(ERR_SIDEEFFECTEVAL);
error_def(ERR_VAREXPECTED);
diff --git a/sr_port/f_name.c b/sr_port/f_name.c
index d5260ac..13cf1a3 100644
--- a/sr_port/f_name.c
+++ b/sr_port/f_name.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -21,7 +21,7 @@
#include "show_source_line.h"
GBLREF boolean_t run_time;
-GBLREF short int source_column;
+GBLREF int source_column;
error_def(ERR_SIDEEFFECTEVAL);
error_def(ERR_VAREXPECTED);
diff --git a/sr_port/f_order.c b/sr_port/f_order.c
index 18ca797..ad96e09 100644
--- a/sr_port/f_order.c
+++ b/sr_port/f_order.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -25,7 +25,7 @@
#include "show_source_line.h"
GBLREF boolean_t run_time;
-GBLREF short int source_column;
+GBLREF int source_column;
error_def(ERR_ORDER2);
error_def(ERR_SIDEEFFECTEVAL);
diff --git a/sr_port/find_rtn_hdr.c b/sr_port/find_rtn_hdr.c
index 62aacaa..42e9fb6 100644
--- a/sr_port/find_rtn_hdr.c
+++ b/sr_port/find_rtn_hdr.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -18,7 +18,6 @@
#include "stack_frame.h"
#include "compiler.h" /* for WANT_CURRENT_RTN_MSTR macro */
-#define S_CUTOFF 7
GBLREF rtn_tabent *rtn_names, *rtn_names_end;
GBLREF stack_frame *frame_pointer;
@@ -40,7 +39,8 @@ rhdtyp *find_rtn_hdr(mstr *name)
* Returns FALSE otherwise.
* In either case, also "returns" (via <res>) the rtn_tabent
* corresponding to the first routine name greater than or equal to
- * <name>.
+ * <name>. This is useful for looking up trigger routines that
+ * include runtime disambiguators in their names.
*/
boolean_t find_rtn_tabent(rtn_tabent **res, mstr *name)
@@ -49,55 +49,42 @@ boolean_t find_rtn_tabent(rtn_tabent **res, mstr *name)
int4 comp;
mident rtn_name;
mident_fixed rtn_name_buff;
+ boolean_t ret;
+ int len;
- assert(name->len <= MAX_MIDENT_LEN);
- rtn_name.len = name->len;
+ len = name->len;
+ rtn_name.len = MIN(MAX_MIDENT_LEN, len);
#ifdef VMS
rtn_name.addr = &rtn_name_buff.c[0];
CONVERT_IDENT(rtn_name.addr, name->addr, name->len);
#else
rtn_name.addr = name->addr;
#endif
- bot = rtn_names;
- top = rtn_names_end;
- for (;;)
- { /* See if routine exists in list via a binary search which reverts to serial
- search when # of items drops below the threshold S_CUTOFF.
- */
- if (S_CUTOFF > (top - bot))
- {
- comp = -1;
- for (mid = bot; comp < 0 && mid <= top; mid++)
- {
- MIDENT_CMP(&mid->rt_name, &rtn_name, comp);
- if (0 == comp)
- {
- *res = mid;
- return TRUE;
- } else if (0 < comp)
- break;
- }
+ bot = rtn_names + 1; /* Exclude the first NULL entry */
+ top = rtn_names_end + 1;/* Include the last entry */
+ for ( ; ; )
+ {
+ if (bot == top)
break;
+ assert(bot < top);
+ mid = bot + (top - bot) / 2;
+ assert(mid >= bot);
+ MIDENT_CMP(&mid->rt_name, &rtn_name, comp);
+ if (0 == comp)
+ {
+ *res = mid;
+ return TRUE;
+ } else if (0 > comp)
+ {
+ bot = mid + 1;
+ continue;
} else
{
- mid = bot + (top - bot) / 2;
- MIDENT_CMP(&mid->rt_name, &rtn_name, comp);
- if (0 == comp)
- {
- *res = mid;
- return TRUE;
- }
- else if (comp < 0)
- {
- bot = mid + 1;
- continue;
- } else
- {
- top = mid - 1;
- continue;
- }
+ assert(mid < top);
+ top = mid;
+ continue;
}
}
- *res = mid;
+ *res = bot;
return FALSE;
}
diff --git a/sr_port/flush_jmp.c b/sr_port/flush_jmp.c
index a28e3c1..335512b 100644
--- a/sr_port/flush_jmp.c
+++ b/sr_port/flush_jmp.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -49,6 +49,7 @@ void flush_jmp (rhdtyp *rtn_base, unsigned char *context, unsigned char *transfe
char *top;
unsigned char *msp_save;
int4 shift, size, mv_st_type;
+ rhdtyp *old_rtnhdr;
unwind_nocounts();
/* We are going to mutate the current frame from the program it was running to the program we want it to run.
@@ -68,7 +69,12 @@ void flush_jmp (rhdtyp *rtn_base, unsigned char *context, unsigned char *transfe
frame_pointer->flags &= SFF_ETRAP_ERR_OFF; /* clear SFF_ETRAP_ERR bit */
frame_pointer->flags &= SFF_IMPLTSTART_CALLD_OFF; /* clear SFF_IMPLTSTART_CALLD bit since this frame is being rewritten */
GTMTRIG_ONLY(DBGTRIGR((stderr, "flush_jmp: Turrning off SFF_IMPLTSTART_CALLD_OFF in frame 0x"lvaddr"\n", frame_pointer)));
+ old_rtnhdr = frame_pointer->rvector;
frame_pointer->rvector = rtn_base;
+ /* Now that fp->rvector has been overwritten to new routine, check if the older routine had a "rtn_relinked" flag set
+ * and if so that cleanup can be performed now.
+ */
+ USHBIN_ONLY(CLEANUP_COPIED_RECURSIVE_RTN(old_rtnhdr)); /* cleanup if needed */
frame_pointer->vartab_ptr = (char *)VARTAB_ADR(rtn_base);
frame_pointer->vartab_len = frame_pointer->rvector->vartab_len;
frame_pointer->mpc = transfer_addr;
@@ -98,9 +104,9 @@ void flush_jmp (rhdtyp *rtn_base, unsigned char *context, unsigned char *transfe
if (msp <= stacktop)
{
msp = msp_save;
- rts_error(VARLSTCNT(1) ERR_STACKOFLOW);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKOFLOW);
} else
- rts_error(VARLSTCNT(1) ERR_STACKCRIT);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKCRIT);
}
memset(msp, 0, size);
DBGEHND((stderr, "flush_jmp: Old msp: 0x"lvaddr" New msp: 0x"lvaddr"\n", msp_save, msp));
@@ -155,9 +161,9 @@ void flush_jmp (rhdtyp *rtn_base, unsigned char *context, unsigned char *transfe
if ((unsigned char *)mv_chain + shift <= stackwarn)
{
if ((unsigned char *)mv_chain + shift <= stacktop)
- rts_error(VARLSTCNT(1) ERR_STACKOFLOW);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKOFLOW);
else
- rts_error(VARLSTCNT(1) ERR_STACKCRIT);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKCRIT);
}
DBGEHND((stderr, "flush_jmp: Shifting %d bytes of stack from 0x"lvaddr" to 0x"lvaddr" by %d bytes\n",
INTCAST(top - (char *)mv_chain), mv_chain, (mv_chain + shift), shift));
diff --git a/sr_port/format2disp.c b/sr_port/format2disp.c
new file mode 100644
index 0000000..abc59c5
--- /dev/null
+++ b/sr_port/format2disp.c
@@ -0,0 +1,88 @@
+/****************************************************************
+ * *
+ * Copyright 2013, 2014 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+#include "mdef.h"
+
+#include "patcode.h"
+#include "zshow.h"
+
+#ifdef UNICODE_SUPPORTED
+#include "gtm_icu_api.h" /* U_ISPRINT() needs this header */
+#include "gtm_utf8.h"
+#endif
+
+GBLREF uint4 *pattern_typemask;
+GBLREF boolean_t gtm_utf8_mode;
+
+/* Routine to convert a string to displayable format. That is any nonprintable
+ * characters are replaced by a dot (.) and the rest are used as is. No double-quote
+ * additions happen like in format2zwr. Used currently by the trigger routines.
+ * This function ensures the displayed part never goes more than "displen".
+ * A "..." is inserted at the end if input string happens to be more than displen
+ * can accommodate. The truncate length is returned in "displen" in that case.
+ */
+void format2disp(char *src, int src_len, char *dispbuff, int *displen)
+{
+ char *c, *c_top, *nextc, *dst, *dst_top, *disptop;
+ int chlen, dstlen, i;
+ unsigned char ch;
+ uint4 codepoint;
+ boolean_t isctl, isill;
+
+ dst = dispbuff;
+ dstlen = *displen;
+ if (0 > dstlen)
+ dstlen = 0;
+ disptop = dst + dstlen;
+ assert(3 < dstlen); /* we expect caller to ensure this */
+ dstlen = (3 > dstlen)? 0 : ((dstlen < src_len) ? dstlen - 3 : dstlen); /* if neded adjust dstlen to account for ellipsis */
+ dst_top = dst + dstlen;
+ for (c = src, c_top = c + src_len; c < c_top; )
+ {
+ if (!gtm_utf8_mode)
+ {
+ ch = *c;
+ isctl = (0 != (pattern_typemask[ch] & PATM_C));
+ isill = FALSE;
+ chlen = 1;
+ }
+# ifdef UNICODE_SUPPORTED
+ else {
+ nextc = (char *)UTF8_MBTOWC(c, c_top, codepoint);
+ isill = (WEOF == codepoint) ? (codepoint = *c, TRUE) : FALSE;
+ isctl = (!isill ? !U_ISPRINT(codepoint) : TRUE);
+ chlen = (int)(nextc - c);
+ }
+# endif
+ if ((dst + chlen) > dst_top)
+ break;
+ if (isctl)
+ { /* control character */
+ for (i = 0; i < chlen; i++)
+ *dst++ = '.';
+ c = c + chlen;
+ } else
+ { /* printable character (1 byte or > 1 byte) */
+ for (i = 0; i < chlen; i++)
+ *dst++ = *c++;
+ }
+ }
+ /* Add "..." if applicable */
+ if (c < c_top)
+ {
+ if (dst < disptop)
+ *dst++ = '.';
+ if (dst < disptop)
+ *dst++ = '.';
+ if (dst < disptop)
+ *dst++ = '.';
+ }
+ *displen = dst - dispbuff;
+}
diff --git a/sr_port/gbldefs.c b/sr_port/gbldefs.c
index 76402e9..14d4e39 100644
--- a/sr_port/gbldefs.c
+++ b/sr_port/gbldefs.c
@@ -296,7 +296,8 @@ GBLDEF char *lexical_ptr;
GBLDEF int4 aligned_source_buffer[MAX_SRCLINE / SIZEOF(int4) + 1];
GBLDEF unsigned char *source_buffer = (unsigned char *)aligned_source_buffer;
GBLDEF src_line_struct src_head;
-GBLDEF short int source_column, source_line;
+GBLDEF short int source_line;
+GBLDEF int source_column;
GBLDEF bool devctlexp;
GBLDEF char cg_phase; /* code generation phase */
/* Previous code generation phase: Only used by emit_code.c to initialize the push list at the
@@ -405,8 +406,6 @@ GBLDEF int gtmrecv_srv_count;
GBLDEF volatile int4 db_fsync_in_prog;
GBLDEF volatile int4 jnl_qio_in_prog;
#ifdef UNIX
-GBLDEF void (*op_write_ptr)(mval *);
-GBLDEF void (*op_wteol_ptr)(int4 n);
GBLDEF gtmsiginfo_t signal_info;
#ifndef MUTEX_MSEM_WAKE
GBLDEF int mutex_sock_fd = FD_INVALID;
@@ -717,7 +716,6 @@ GBLDEF boolean_t gvdupsetnoop = TRUE; /* if TRUE, duplicate SETs do not change G
* behavior is turned ON. GT.M has a way of turning it off with a VIEW command.
*/
GBLDEF boolean_t gtm_fullblockwrites; /* Do full (not partial) database block writes T/F */
-UNIX_ONLY(GBLDEF int4 gtm_shmflags;) /* Extra flags for shmat */
#ifdef VMS
GBLDEF uint4 gtm_memory_noaccess_defined; /* count of the number of GTM_MEMORY_NOACCESS_ADDR logicals which are defined */
GBLDEF uint4 gtm_memory_noaccess[GTM_MEMORY_NOACCESS_COUNT]; /* see VMS gtm_env_init_sp.c */
@@ -973,6 +971,7 @@ GBLDEF boolean_t *ztvalue_changed_ptr; /* -> boolean in current gtm_trigger_pa
GBLDEF boolean_t ztwormhole_used; /* TRUE if $ztwormhole was used by trigger code */
GBLDEF mstr *dollar_ztname;
GBLDEF mval *dollar_ztdata,
+ *dollar_ztdelim,
*dollar_ztoldval,
*dollar_ztriggerop,
*dollar_ztupdate,
@@ -1113,5 +1112,4 @@ GBLDEF gtm_tls_ctx_t *tls_ctx; /* Process private pointer to SSL/TLS context.
* Socket devices.
*/
#endif
-
GBLDEF lv_val *active_lv;
diff --git a/sr_port/gde.hlp b/sr_port/gde.hlp
index a9a7eb5..46847df 100644
--- a/sr_port/gde.hlp
+++ b/sr_port/gde.hlp
@@ -141,7 +141,6 @@
Jnl File (def ext: .mjl) Before Buff Alloc Exten AutoSwitch
------------------------------------------------------------------------------------------
<default> <based on DB file-spec> Y 2308 2048 2048 8386560
-
Segment Active Acc Typ Block Alloc Exten Options
------------------------------------------------------------------------------
<default> * BG DYN 4096 5000 10000 GLOB =1000
@@ -152,25 +151,21 @@
<default> MM DYN 4096 5000 10000 DEFER
LOCK = 40
MSLT =1024
-
*** NAMES ***
Global Region
------------------------------------------------------------------------------
* DEFAULT
-
*** REGIONS ***
Std Inst
Dynamic Def Rec Key Null Null Freeze Qdb
Region Segment Coll Size Size Subs Coll Jnl on Error Rndwn
--------------------------------------------------------------------------------------------------------------------------
DEFAULT DEFAULT 0 4080 255 NEVER Y Y DISABLED DISABLED
-
*** JOURNALING INFORMATION ***
Region Jnl File (def ext: .mjl) Before Buff Alloc Exten AutoSwitch
--------------------------------------------------------------------------------------------------------
DEFAULT $gtmdir/$gtmver/g/gtm.mjl
Y 2308 2048 2048 8386560
-
*** SEGMENTS ***
Segment File (def ext: .dat)Acc Typ Block Alloc Exten Options
-------------------------------------------------------------------------------------------
@@ -180,7 +175,6 @@
RES = 0
ENCR=OFF
MSLT=1024
-
*** MAP ***
- - - - - - - - - - Names - - - - - - - - - -
From Up to Region / Segment / File(def ext: .dat)
@@ -721,7 +715,6 @@
GDE> add -gblname EURCentral -collation=1
GDE> show -gblname
-
*** GBLNAMES ***
Global Coll Ver
------------------------------------------------------------------------------
@@ -1063,7 +1056,6 @@
Example:
GDE>show -template
-
*** TEMPLATES ***
Std Inst
Def Rec Key Null Null Freeze Qdb
@@ -1073,7 +1065,6 @@
Jnl File (def ext: .mjl) Before Buff Alloc Exten AutoSwitch
------------------------------------------------------------------------------------------
<default> <based on DB file-spec> Y 2308 2048 2048 8386560
-
Segment Active Acc Typ Block Alloc Exten Options
------------------------------------------------------------------------------
<default> * BG DYN 4096 5000 10000 GLOB =1000
@@ -2048,15 +2039,16 @@
Copyright 2014
- Fidelity Information Services, Inc. All rights reserved.
+ Fidelity National Information Services, Inc. and/or its subsidiaries. All
+ rights reserved.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or any
later version published by the Free Software Foundation; with no Invariant
Sections, no Front-Cover Texts and no Back-Cover Texts.
- GT.M(TM) is a trademark of Fidelity Information Services, Inc. Other
- trademarks are the property of their respective owners.
+ GT.M(TM) is a trademark of Fidelity National Information Services, Inc.
+ Other trademarks are the property of their respective owners.
This document contains a description of GT.M and the operating
instructions pertaining to the various functions that comprise the system.
@@ -2067,7 +2059,7 @@
**Note**
- This help file is a concise representation of revision V6.2-000 of the
+ This help file is a concise representation of revision V6.2-001 of the
UNIX Administration and Operations Guide. To obtain a copy of the current
revision, go to www.fis-gtm.com and then click on the User Documentation
tab.
diff --git a/sr_port/gdsbt.h b/sr_port/gdsbt.h
index 64f9115..7d22808 100644
--- a/sr_port/gdsbt.h
+++ b/sr_port/gdsbt.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -391,7 +391,7 @@ typedef struct node_local_struct
boolean_t snapshot_in_prog; /* Tells GT.M if any snapshots are in progress */
uint4 num_snapshots_in_effect; /* how many snapshots are currently in place for this region */
uint4 wbox_test_seq_num; /* used to coordinate with sequential testing steps */
- NON_GTM64_ONLY(int4 filler_8byte_align;) /* To align the following member at an 8-byte boundry on 32-bit platforms */
+ NON_GTM64_ONLY(int4 filler_8byte_align;) /* To align the following member at an 8-byte boundary on 32-bit platforms */
UNIX_ONLY(pid_t kip_pid_array[MAX_KIP_PID_SLOTS];) /* Processes actively doing kill (0 denotes empty slots) */
gtm_uint64_t sec_size; /* Upon going to larger shared memory sizes, we realized that this does not */
/* need to be in the file header but the node local since it can be calculated */
@@ -425,6 +425,8 @@ typedef struct node_local_struct
*/
boolean_t fake_db_enospc; /* used only by dbg versions to simulate ENOSPC scenarios in the database file */
boolean_t fake_jnl_enospc; /* used only by dbg versions to simulate ENOSPC scenarios in the journal file */
+ boolean_t doing_epoch; /* set when performing an epoch */
+ NON_GTM64_ONLY(int4 filler_8byte_align1;) /* 8-byte align the stucture on 32-bit platforms; 64s do it implicitly */
# endif
} node_local;
diff --git a/sr_port/gdsdbver.h b/sr_port/gdsdbver.h
index fbaa364..beb0301 100644
--- a/sr_port/gdsdbver.h
+++ b/sr_port/gdsdbver.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2005, 2013 Fidelity Information Services, Inc *
+ * Copyright 2005, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -69,6 +69,7 @@ enum mdb_ver
GDSMV60000, /* New freeze_on_fail field for anticipatory freeze; the wc_blocked field moved to shared memory */
GDSMV60001,
GDSMV60002, /* New field mutex_spin_parms.mutex_que_entry_space_size for configurable mutex queue size */
+ GDSMV62001, /* New field hasht_upgrade_needed for ^#t upgrade */
GDSMVLAST
};
#define GDSMVCURR ((enum mdb_ver)(GDSMVLAST - 1))
diff --git a/sr_port/gdsfhead.h b/sr_port/gdsfhead.h
index e6cbcbf..99fe5fa 100644
--- a/sr_port/gdsfhead.h
+++ b/sr_port/gdsfhead.h
@@ -221,8 +221,8 @@ typedef cache_rec **cache_rec_ptr_ptr_t;
typedef cache_state_rec *cache_state_rec_ptr_t;
typedef cache_que_heads *cache_que_heads_ptr_t;
-void verify_queue_lock(que_head_ptr_t qhdr);
-void verify_queue(que_head_ptr_t qhdr);
+gtm_uint64_t verify_queue_lock(que_head_ptr_t qhdr);
+gtm_uint64_t verify_queue(que_head_ptr_t qhdr);
#ifdef DB64
# ifdef __osf__
@@ -231,8 +231,8 @@ void verify_queue(que_head_ptr_t qhdr);
#endif
#ifdef DEBUG_QUEUE
-#define VERIFY_QUEUE(base) verify_queue(base)
-#define VERIFY_QUEUE_LOCK(base,latch) verify_queue_lock(base,latch)
+#define VERIFY_QUEUE(base) (void)verify_queue(base)
+#define VERIFY_QUEUE_LOCK(base,latch) (void)verify_queue_lock(base,latch)
#else
#define VERIFY_QUEUE(base)
#define VERIFY_QUEUE_LOCK(base,latch)
@@ -834,6 +834,8 @@ void verify_queue(que_head_ptr_t qhdr);
assert(reg->open); \
cs_addrs = &FILE_INFO(gv_cur_region)->s_addrs; \
cs_data = cs_addrs->hdr; \
+ assert((&FILE_INFO(gv_cur_region)->s_addrs == cs_addrs) \
+ && cs_addrs->hdr == cs_data); \
break; \
case dba_usr: \
case dba_cm: \
@@ -845,7 +847,6 @@ void verify_queue(que_head_ptr_t qhdr);
break; \
} \
} \
- assert(&FILE_INFO(gv_cur_region)->s_addrs == cs_addrs && cs_addrs->hdr == cs_data); \
}
#define PUSH_GV_CUR_REGION(reg, sav_reg, sav_cs_addrs, sav_cs_data) \
@@ -1499,18 +1500,42 @@ n_db_csh_acct_rec_types
#undef TAB_DB_CSH_ACCT_REC
#include "gvstats_rec.h"
+#ifdef UNIX
+#include "probecrit_rec.h"
+#endif
#define GVSTATS_SET_CSA_STATISTIC(csa, counter, value) \
{ \
csa->gvstats_rec.counter = value; \
}
-#define INCR_GVSTATS_COUNTER(csa, cnl, counter, increment) \
-{ \
- csa->gvstats_rec.counter += increment; \
- cnl->gvstats_rec.counter += increment; \
+#define INCR_GVSTATS_COUNTER(csa, cnl, counter, increment) \
+{ \
+ csa->gvstats_rec.counter += increment; /* process private stats */ \
+ cnl->gvstats_rec.counter += increment; /* database stats */ \
+}
+
+/* clear everything from the end of the encryption_hash up to the ntrpt_recov_resync_strm_seqno array, which includes:
+ * all bg_trc_rec_tn, all bg_trc_rec_cntr, all db_csh_acct_rec, all gvstats as well as any intervening filler;
+ * also clear tp_cdb_sc_blkmod
+ * This means we MUST NOT insert anything in the file header between the encryption_hash and intrpt_recov_resync_strm_seqno
+ * nor move either of those end points without appropriately adjusting this macro
+ */
+#define CLRGVSTATS(CSA) \
+{ \
+ char *CHPTR; \
+ int CLRLEN; \
+ sgmnt_data_ptr_t CSD; \
+ \
+ CSD = CSA->hdr; \
+ CHPTR = (char *)&CSD->encryption_hash + GTMCRYPT_RESERVED_HASH_LEN; \
+ CLRLEN = (char *)&CSD->intrpt_recov_resync_strm_seqno - CHPTR; \
+ memset(CHPTR, 0, CLRLEN); \
+ gvstats_rec_csd2cnl(CSA); /* we update gvstats in cnl */ \
+ memset((char *)&CSD->tp_cdb_sc_blkmod, 0, SIZEOF(CSD->tp_cdb_sc_blkmod)); \
}
+
#if defined(DEBUG) || defined(DEBUG_DB_CSH_COUNTER)
# define INCR_DB_CSH_COUNTER(csa, counter, increment) \
if (csa->read_write || dba_bg == csa->hdr->acc_meth) \
@@ -1547,6 +1572,7 @@ enum tp_blkmod_type /* used for accounting in cs_data->tp_cdb_sc_blkmod[] */
#define DONOTCOMMIT_REALLOCATE_BITMAP_BMLMOD (1 << 8) /* Restartable situation encountered in reallocate_bitmap */
#define DONOTCOMMIT_T_WRITE_CSE_DONE (1 << 9) /* Restartable situation encountered in t_write */
#define DONOTCOMMIT_T_WRITE_CSE_MODE (1 << 10) /* Restartable situation encountered in t_write */
+#define DONOTCOMMIT_TRIGGER_SELECT_XECUTE (1 << 11) /* Restartable situation encountered in trigger_select */
#define TAB_BG_TRC_REC(A,B) B,
enum bg_trc_rec_type
@@ -1818,7 +1844,12 @@ typedef struct sgmnt_data_struct
char machine_name[MAX_MCNAMELEN];
char encryption_hash[GTMCRYPT_RESERVED_HASH_LEN];
/* char filler_2k[256] was here before adding the encryption_hash. Since the GTMCRYPT_RESERVED_HASH_LEN
- * consumes 256 bytes, filler_2k has been removed. */
+ * consumes 256 bytes, filler_2k has been removed.
+ */
+ /* The CLRGVSTATS macro wipes out everything from here through the GVSTATS fields up to intrpt_recov_resync_strm_seqno
+ * starting from the end of the space reserved for the encryption_hash above - DO NOT insert anthing in this range or move
+ * those two end points without appropriately adjusting that macro
+ */
/************* BG_TRC_REC RELATED FIELDS ***********/
# define TAB_BG_TRC_REC(A,B) bg_trc_rec_tn B##_tn;
# include "tab_bg_trc_rec.h"
@@ -1867,10 +1898,12 @@ typedef struct sgmnt_data_struct
* See comment in "mur_get_max_strm_reg_seqno" function for
* purpose of this field. Must also be 8-byte aligned.
*/
+ /************* MISCELLANEOUS FIELDS ****************/
boolean_t freeze_on_fail; /* Freeze instance if failure of this database observed */
boolean_t span_node_absent; /* Database does not contain the spanning node */
boolean_t maxkeysz_assured; /* All the keys in the database are less than MAX_KEY_SIZE */
- char filler_7k[724];
+ boolean_t hasht_upgrade_needed; /* ^#t global needs to be upgraded from V62000 to post-V62000 format */
+ char filler_7k[720];
char filler_8k[1024];
/********************************************************/
/* Master bitmap immediately follows. Tells whether the local bitmaps have any free blocks or not. */
@@ -1923,6 +1956,8 @@ typedef struct
#define NEG_MNTSSA_END 0x0FF
#define KEY_DELIMITER 0X00
#define MIN_DB_BLOCKS 10 /* this should be maintained in conjunction with the mimimum allocation in GDEINIT.M */
+#define MIN_GBUFF_LIMIT 32 /* minimum gbuff limit */
+#define REORG_GBUFF_LIMIT "64" /* default gbuff_limit for REORG */
/* definition for NULL_SUBSCRIPTS */
#define NEVER 0
@@ -2237,12 +2272,16 @@ typedef struct sgmnt_addrs_struct
* should know to release crit even if hold_onto_crit is set to TRUE and so will
* rely on this variable
*/
+ int4 gbuff_limit; /* desired limit on global buffers; see db_csh_getn, op_view and op_fnview */
+ cache_rec_ptr_t our_midnite; /* anchor if we are using a gbuff_limit */
# ifdef UNIX
uint4 root_search_cycle; /* local copy of cnl->root_search_cycle */
uint4 onln_rlbk_cycle; /* local copy of cnl->onln_rlbk_cycle */
uint4 db_onln_rlbkd_cycle; /* local copy of cnl->db_onln_rlbkd_cycle */
boolean_t dbinit_shm_created; /* TRUE if shared memory for this region was created by this process */
boolean_t read_only_fs; /* TRUE if the region is read_only and the header was not updated due to EROFS */
+ boolean_t crit_probe; /* flag for indicating the process is doing a crit probe on this region */
+ probecrit_rec_t probecrit_rec; /* fields defined in tab_probecrit_rec.h and initialized in probecrit_rec.h */
# endif
} sgmnt_addrs;
@@ -2668,6 +2707,10 @@ typedef struct gvnh_reg_struct
assert(added); \
}
+/* Below macro is used whenever we need to print region of interest in case of a global that spans multiple regions */
+#define SPANREG_REGION_LIT " (region "
+#define SPANREG_REGION_LITLEN STR_LIT_LEN(SPANREG_REGION_LIT)
+
#define INVALID_GV_TARGET (gv_namehead *)-1L
/* Below macro is used to get the "gvnh_reg->gvspan->gvt_array[]" contents taking into account some
* might be set to INVALID_GV_TARGET (done only in DEBUG mode). In that case, we actually want to return NULL
@@ -2843,6 +2886,10 @@ GBLREF gv_namehead *gvt_tp_list;
* away instead of recomputing them). The only exception is if we were interrupted in the middle of TP transaction by an
* external signal which resulted in us terminating right away. In this case, we are guaranteed not to make a call to op_gvname
* again (because we are exiting) so it is ok not to do this check if process_exiting is TRUE.
+ *
+ * Update: The above comment is no longer true. As part of GTM-2168, the fast path in op_gvname was removed but we have not
+ * removed code that does the below macro invocation since this is dbg-only and is anyways otherwise true. If it is a hassle
+ * ensuring the below anywhere, it should be okay to remove it then.
*/
#define DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSADDRS) \
{ \
@@ -3570,8 +3617,6 @@ typedef replpool_identifier *replpool_id_ptr_t;
} \
}
-#define INVALID_SEMID -1
-#define INVALID_SHMID -1L
#ifdef VMS
#define NEW_DBINIT_SHM_IPC_MASK (1 << 0) /* 1 if db_init created a new shared memory (no pre-existing one) */
#define NEW_DBINIT_SEM_IPC_MASK (1 << 1) /* 1 if db_init created a new access control semaphore */
diff --git a/sr_port/gtm_env_init.c b/sr_port/gtm_env_init.c
index acde640..931e706 100644
--- a/sr_port/gtm_env_init.c
+++ b/sr_port/gtm_env_init.c
@@ -167,6 +167,24 @@ void gtm_env_init(void)
}
} else
(TREF(mprof_env_gbl_name)).str.addr = NULL;
+ val.addr = GTM_POOLLIMIT;
+ val.len = SIZEOF(GTM_POOLLIMIT) - 1;
+ if (SS_NORMAL == (status = TRANS_LOG_NAME(&val, &trans, buf, SIZEOF(buf), do_sendmsg_on_log2long)))
+ { /* Note assignment above */
+ if (SIZEOF(buf) >= trans.len)
+ {
+ if (('0' == (char)(*trans.addr)) || (0 == trans.len))
+ (TREF(gbuff_limit)).str.len = 0;
+ else
+ {
+ (TREF(gbuff_limit)).str.len = trans.len;
+ (TREF(gbuff_limit)).str.addr = malloc(trans.len);
+ memcpy((TREF(gbuff_limit)).str.addr, trans.addr, trans.len);
+ }
+ }
+ } else
+ (TREF(gbuff_limit)).str.len = 0;
+ (TREF(gbuff_limit)).mvtype = MV_STR;
# ifdef DEBUG
/* GTM_GVUNDEF_FATAL environment/logical */
val.addr = GTM_GVUNDEF_FATAL;
diff --git a/sr_port/gtm_stdlib.h b/sr_port/gtm_stdlib.h
index 225827a..29c8748 100644
--- a/sr_port/gtm_stdlib.h
+++ b/sr_port/gtm_stdlib.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -16,34 +16,50 @@
#include <stdlib.h>
#ifndef __CYGWIN__
-#define GETENV getenv
+# define GETENV getenv
#else
char *gtm_getenv(char *varname);
-#define GETENV gtm_getenv
+# define GETENV gtm_getenv
#endif
-#define ATOI atoi
-#define ATOL atol
-#define ATOF atof
-#define PUTENV putenv
-#define STRTOL strtol
-#define STRTOLL strtoll
-#define STRTOUL strtoul
+#define ATOI atoi
+#define ATOL atol
+#define ATOF atof
+#ifdef UNIX
+/* If interrupted, this function has previously caused hangs to do a subsequent syslog() invocation from generic_signal_handler(),
+ * so just defer interrupts to be safe. UNIX is a GT.M-specific compiler switch, which we expect to be undefined for any non-GT.M
+ * compilation that might include this file.
+ */
+# define PUTENV(VAR, ARG) \
+{ \
+ DEFER_INTERRUPTS(INTRPT_IN_FUNC_WITH_MALLOC); \
+ VAR = putenv(ARG); \
+ ENABLE_INTERRUPTS(INTRPT_IN_FUNC_WITH_MALLOC); \
+}
+#else
+# define PUTENV(VAR, ARG) \
+{ \
+ VAR = putenv(ARG); \
+}
+#endif
+#define STRTOL strtol
+#define STRTOLL strtoll
+#define STRTOUL strtoul
#if INT_MAX < LONG_MAX /* like Tru64 */
-#define STRTO64L strtol
-#define STRTOU64L strtoul
+# define STRTO64L strtol
+# define STRTOU64L strtoul
#elif defined(__hpux)
-#include <inttypes.h>
-#define STRTO64L strtoimax
-#define STRTOU64L strtoumax
+# include <inttypes.h>
+# define STRTO64L strtoimax
+# define STRTOU64L strtoumax
#else
-#define STRTO64L strtoll
-#define STRTOU64L strtoull
+# define STRTO64L strtoll
+# define STRTOU64L strtoull
#endif
#define MKSTEMP(template,mkstemp_res) (mkstemp_res = mkstemp(template))
-#ifdef VMS
-#define SYSTEM system
+#if defined(VMS) || defined(STATIC_ANALYSIS)
+# define SYSTEM system
#else
-#define SYSTEM gtm_system
+# define SYSTEM gtm_system
int gtm_system(const char *cmdline);
#endif
diff --git a/sr_port/gtm_threadgbl.h b/sr_port/gtm_threadgbl.h
index f87ab53..6e6ebe8 100644
--- a/sr_port/gtm_threadgbl.h
+++ b/sr_port/gtm_threadgbl.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2011 Fidelity Information Services, Inc *
+ * Copyright 2010, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -35,6 +35,8 @@
* TADR - Used to obtain the address of the element.
* TREF - Used to dereference a global var (see notes at TREF macro for usage).
* TAREF1/TAREF2 - Used to access array elements - TAREF1 for vectors, TAREF2 for 2 subscript access.
+ * TLEN - Used to obtain length of total element for both one and two dimension arrays. Not
+ * defined for non-arrays.
* RFPTR - Used to reference a function pointer in an expression or conditional.
* SFPTR - Used to set a new value into a function pointer.
* IVFPTR - Used to invoke a function pointer.
@@ -82,6 +84,9 @@
/* For address of item use TADR(name) macro */
#define TADR(name) ((ggt_##name *)((char *)lcl_gtm_threadgbl + ggo_##name))
+/* For character length of character arrays (for arrays only) */
+#define TLEN(name) (ggl_##name)
+
/* For access to single dimension array (vector), use TAREF1 macro */
#define TAREF1(name, indx1) (TADR(name))[indx1]
diff --git a/sr_port/gtm_threadgbl_defs.h b/sr_port/gtm_threadgbl_defs.h
index 4bb2098..231e386 100644
--- a/sr_port/gtm_threadgbl_defs.h
+++ b/sr_port/gtm_threadgbl_defs.h
@@ -50,13 +50,20 @@ THREADGBLDEF(expr_depth, unsigned int) /* expression nesting level */
THREADGBLDEF(expr_start, triple *) /* chain anchor for side effect early evaluation */
THREADGBLDEF(expr_start_orig, triple *) /* anchor used to test if there's anything hung on
* expr_start */
+THREADGBLDEF(defined_symbols, struct sym_table *) /* Anchor for symbol chain */
THREADGBLDEF(for_stack_ptr, oprtype **) /* part of FOR compilation nesting mechanism */
THREADGBLDEF(gtm_fullbool, unsigned int) /* controls boolean side-effect behavior defaults
* to 0 (GTM_BOOL) */
THREADGBLDEF(ind_result, mval *) /* pointer to indirection return location */
THREADGBLDEF(ind_source, mval *) /* pointer to indirection source location */
THREADGBLDEF(indirection_mval, mval) /* used for parsing subscripted indirection */
-THREADGBLDEF(last_source_column, short int) /* parser tracker */
+THREADGBLDEF(last_source_column, int) /* parser tracker */
+THREADGBLDEF(max_advancewindow_line, int4) /* the maximum source line length */
+THREADGBLDEF(linkage_first, struct linkage_entry *) /* Start of linkage (extern) list this routine */
+THREADGBLDEF(linkage_last, struct linkage_entry *) /* Last added entry */
+#ifdef USHBIN_SUPPORTED
+THREADGBLDEF(objhash_state, hash128_state_t) /* Seed value - progressive hash of object file */
+#endif
THREADGBLDEF(pos_in_chain, triple) /* anchor used to restart after a parsing error */
THREADGBLDEF(s2n_intlit, boolean_t) /* type info from s2n for advancewindow */
THREADGBLDEF(routine_source_offset, uint4) /* offset of M source within literal text pool */
@@ -80,6 +87,7 @@ THREADGBLDEF(dbinit_max_hrtbt_delta, uint4) /* max heartbeats before we bail
THREADGBLDEF(dollar_zmaxtptime, int4) /* tp timeout in seconds */
THREADGBLDEF(donot_commit, boolean_t) /* debug-only - see gdsfhead.h for purpose */
THREADGBLDEF(donot_write_inctn_in_wcs_recover, boolean_t) /* TRUE if wcs_recover should NOT write INCTN */
+THREADGBLDEF(gbuff_limit, mval) /* holds a GTM_POOLLIMIT value for REORG or DBG */
THREADGBLDEF(gd_targ_tn, trans_num) /* number that is incremented for every gvcst_spr*
* action. helps easily determine whether a region
* has already been seen in this gvcst_spr* action.
@@ -191,6 +199,8 @@ THREADGBLDEF(replgbl, replgbl_t) /* set of global variables needed by the s
* server */
THREADGBLDEF(tqread_nowait, boolean_t) /* avoid sleeping in t_qread if TRUE */
/* Miscellaneous */
+THREADGBLDEF(arlink_enabled, boolean_t) /* TRUE if any zroutines segment is autorelink
+ * enabled. */
THREADGBLDEF(collseq_list, collseq *) /* list of pointers to currently mapped collation
* algorithms - since this seems only used in
* collseq.c -seems more like a STATICDEF */
@@ -260,9 +270,13 @@ THREADGBLDEF(mprof_reclaim_cnt, int) /* Amount of mem to reclaim after unw_
THREADGBLDEF(mprof_stack_curr_frame, mprof_stack_frame *) /* Pointer to the last frame on the mprof stack */
THREADGBLDEF(mprof_stack_next_frame, mprof_stack_frame *) /* Pointer to the next frame to be put on the
* mprof stack */
-#ifdef USHBIN_SUPPORTED
+#ifdef AUTORELINK_SUPPORTED
THREADGBLDEF(open_relinkctl_list, open_relinkctl_sgm *) /* Anchor for open relinkctl list; similar to
* open_shlib_root */
+THREADGBLDEF(relinkctl_shm_min_index, int) /* Minimum size of rtnobj shared memory segment
+ * is 2**relinkctl_shm_min_index
+ */
+THREADGBLDEF(gtm_autorelink_keeprtn, boolean_t) /* do not let go of objects in rtnobj shm */
#endif
#ifdef UNIX
THREADGBLDEF(open_shlib_root, open_shlib *) /* Anchor for open shared library list */
@@ -277,9 +291,6 @@ THREADGBLDEF(pipefifo_interrupt, int) /* count of number of times a pipe or
* interrupted */
#endif
THREADGBLDEF(prof_fp, mprof_stack_frame *) /* Stack frame that mprof currently operates on */
-#ifdef USHBIN_SUPPORTED
-THREADGBLDEF(recent_zhist, zro_hist *) /* Saved history from last zro_search */
-#endif
THREADGBLDEF(relink_allowed, int) /* Non-zero if recursive relink permitted */
THREADGBLDEF(set_zroutines_cycle, uint4) /* Informs us if we changed $ZROUTINES between
* linking a routine and invoking it
@@ -329,6 +340,7 @@ THREADGBLAR1DEF(tp_restart_failhist_arry, char, FAIL_HIST_ARRAY_SIZE) /* tp_rest
THREADGBLDEF(user_id, uint4) /* USERID number */
#endif
THREADGBLAR1DEF(window_string, char, SIZEOF(mident_fixed)) /* Buffer for window_ident */
+THREADGBLAR1DEF(tmp_object_file_name, char, GTM_PATH_MAX) /* Hold temporary object name across routines */
/* Utility I/O */
THREADGBLDEF(last_va_list_ptr, va_list) /* Last variable-length argument list used for util
@@ -347,6 +359,9 @@ THREADGBLDEF(extcall_package_root, struct extcall_package_list *) /* External c
#ifdef UNIX
THREADGBLDEF(gtmci_nested_level, unsigned int) /* Current nested depth of callin environments */
THREADGBLDEF(temp_fgncal_stack, unsigned char *) /* Override for fgncal_stack when non-NULL */
+THREADGBLDEF(midchild_send_locals, boolean_t) /* The middle child will send the locals to the
+ * grandchild using ojmidchild_send_var() if TRUE.
+ */
#endif
THREADGBLDEF(want_empty_gvts, boolean_t) /* set to TRUE by MUPIP REORG when it is selecting
* globals to be reorged. Need to be able to select
@@ -391,6 +406,7 @@ THREADGBLDEF(no_spangbls, boolean_t) /* This process does not need to worry ab
* irrespective of whether the global spans regions or not.
*/
THREADGBLDEF(max_fid_index, int) /* maximum value of csa->fid_index across all open csa's */
+THREADGBLDEF(is_mu_rndwn_rlnkctl, int) /* this process is MUPIP RUNDOWN -RELINKCTL */
#ifdef GTM_TRIGGER
THREADGBLDEF(gvt_triggers_read_this_tn, boolean_t) /* if non-zero, indicates triggers were read for
* at least one gv_target in this transaction.
@@ -407,6 +423,13 @@ THREADGBLDEF(op_fntext_tlevel, uint4) /* Non-zero implies $TEXT argument is
* the time of the call to "get_src_line" in
* op_fntext.c. Later used by fntext_ch.c.
*/
+THREADGBLDEF(in_op_fntext, boolean_t) /* Denote the trigger was processed in $Text() */
+THREADGBLDEF(ztrigbuff, char *) /* Buffer to hold $ztrigger/mupip-trigger output
+ * until TCOMMIT.
+ */
+THREADGBLDEF(ztrigbuffAllocLen, int) /* Length of allocated ztrigbuff buffer */
+THREADGBLDEF(ztrigbuffLen, int) /* Length of used ztrigbuff buffer */
+THREADGBLDEF(ztrig_use_io_curr_device, boolean_t) /* Use current IO device instead of stderr/util_out_print */
#endif
/* Debug values */
@@ -435,4 +458,14 @@ THREADGBLDEF(activelv_dbg_array, activelv_dbg_t *) /* pointer to array holding
* ACTIVELV_DBG_ARRAY_SIZE_DEF most recent
* invocations of SET_ACTIVE_LV */
THREADGBLDEF(cli_get_str_max_len, uint4)
-#endif
+# ifdef GTM_TRIGGER
+THREADGBLDEF(gtmio_skip_tlevel_assert, boolean_t) /* Allow for "util_out_print_gtmio" calls without TP
+ * if this variable is TRUE.
+ */
+THREADGBLDEF(in_trigger_upgrade, boolean_t) /* caller is MUPIP TRIGGER -UPGRADE */
+#endif /* #ifdef GTM_TRIGGER */
+THREADGBLDEF(gtm_test_autorelink_always, boolean_t) /* DEBUG-only option to enable/disable autorelink always */
+THREADGBLDEF(fork_without_child_wait, boolean_t) /* we did a FORK but did not wait for child to detach from
+ * inherited shm so shm_nattch could be higher than we expect.
+ */
+#endif /* #ifdef DEBUG */
diff --git a/sr_port/gtm_threadgbl_deftypes.c b/sr_port/gtm_threadgbl_deftypes.c
index 1791cd3..61aa998 100644
--- a/sr_port/gtm_threadgbl_deftypes.c
+++ b/sr_port/gtm_threadgbl_deftypes.c
@@ -23,7 +23,7 @@
#include <signal.h>
#include <sys/time.h>
#ifdef UNIX
-# include <sys/un.h>
+# include "gtm_un.h"
#endif
#ifdef VMS
# include <descrip.h> /* Required for gtmsource.h */
@@ -142,9 +142,8 @@
# include "gtm_trigger.h"
#endif
-#ifdef USHBIN_SUPPORTED
+#ifdef AUTORELINK_SUPPORTED
# include "relinkctl.h"
-# include "zhist.h"
#endif
/* This module's purpose is to generate gtm_threadgbl_deftypes.h for a given platform. This header file
diff --git a/sr_port/gtm_threadgbl_init.c b/sr_port/gtm_threadgbl_init.c
index 5b4486c..b41d38a 100644
--- a/sr_port/gtm_threadgbl_init.c
+++ b/sr_port/gtm_threadgbl_init.c
@@ -29,12 +29,10 @@
#include "gtm_socket.h"
#include "gtm_unistd.h"
#include "gtm_limits.h"
+#include "gtm_un.h"
#include <signal.h>
#include <sys/time.h>
-#ifdef UNIX
-# include <sys/un.h>
-#endif
#ifdef VMS
# include <descrip.h> /* Required for gtmsource.h */
# include <ssdef.h>
@@ -152,9 +150,8 @@
# include "gtm_trigger.h"
#endif
-#ifdef USHBIN_SUPPORTED
+#ifdef AUTORELINK_SUPPORTED
# include "relinkctl.h"
-# include "zhist.h"
#endif
#include "gtm_threadgbl_init.h"
@@ -228,4 +225,6 @@ void gtm_threadgbl_init(void)
(TREF(replgbl)).jnl_release_timeout = DEFAULT_JNL_RELEASE_TIMEOUT;
(TREF(window_ident)).addr = TADR(window_string);
TREF(util_outbuff_ptr) = TADR(util_outbuff); /* Point util_outbuff_ptr to the beginning of util_outbuff at first. */
+ TREF(util_outptr) = TREF(util_outbuff_ptr);
+ TREF(max_advancewindow_line) = MAX_SRCLINE;
}
diff --git a/sr_port/gtmrecv_helpers_init.c b/sr_port/gtmrecv_helpers_init.c
index fd194cf..d3097e7 100644
--- a/sr_port/gtmrecv_helpers_init.c
+++ b/sr_port/gtmrecv_helpers_init.c
@@ -44,8 +44,10 @@
#include "memcoherency.h"
#include "getjobnum.h"
#include "gtmimagename.h"
+#include "wbox_test_init.h"
-#define UPDHELPER_CMD_MAXLEN 1024
+
+#define UPDHELPER_CMD_MAXLEN GTM_PATH_MAX
#define UPDHELPER_CMD "%s/mupip"
#define UPDHELPER_CMD_FILE "mupip"
#define UPDHELPER_CMD_ARG1 "replicate"
@@ -68,6 +70,7 @@ error_def(ERR_GTMDISTUNVERIF);
error_def(ERR_LOGTOOLONG);
error_def(ERR_RECVPOOLSETUP);
error_def(ERR_TEXT);
+error_def(ERR_HLPPROC);
static int helper_init(upd_helper_entry_ptr_t helper, recvpool_user helper_type)
{
@@ -93,13 +96,27 @@ static int helper_init(upd_helper_entry_ptr_t helper, recvpool_user helper_type)
if (!gtm_dist_ok_to_use)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_GTMDISTUNVERIF, 4, STRLEN(gtm_dist), gtm_dist,
gtmImageNames[image_type].imageNameLen, gtmImageNames[image_type].imageName);
+ if (WBTEST_ENABLED(WBTEST_MAXGTMDIST_HELPER_PROCESS))
+ {
+ memset(gtm_dist, 'a', GTM_PATH_MAX-2);
+ gtm_dist[GTM_PATH_MAX-1] = '\0';
+ }
+ helper_cmd_len = SNPRINTF(helper_cmd, UPDHELPER_CMD_MAXLEN, UPDHELPER_CMD, gtm_dist);
+ if ((-1 == helper_cmd_len) || (UPDHELPER_CMD_MAXLEN <= helper_cmd_len))
+ {
+ helper->helper_shutdown = save_shutdown;
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_HLPPROC, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Could not find path of Helper Process. Check value of $gtm_dist"));
+ repl_errno = EREPL_UPDSTART_BADPATH;
+ return UPDPROC_START_ERR ;
+ }
FORK(helper_pid);
if (0 > helper_pid)
{
save_errno = errno;
helper->helper_shutdown = save_shutdown;
- gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
- LEN_AND_LIT("Could not fork update process"), save_errno);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_HLPPROC, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Could not fork Helper process"), save_errno);
repl_errno = EREPL_UPDSTART_FORK;
return UPDPROC_START_ERR;
}
@@ -107,24 +124,17 @@ static int helper_init(upd_helper_entry_ptr_t helper, recvpool_user helper_type)
{ /* helper */
getjobnum();
helper->helper_pid_prev = process_id; /* identify owner of slot */
- helper_cmd_len = SNPRINTF(helper_cmd, UPDHELPER_CMD_MAXLEN, UPDHELPER_CMD, gtm_dist);
- if(-1 == helper_cmd_len)
- {
- helper->helper_shutdown = save_shutdown;
- gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
- LEN_AND_LIT("Could not find path of Helper Process. Check value of $gtm_dist"));
- repl_errno = EREPL_UPDSTART_BADPATH;
- return UPDPROC_START_ERR;
- }
+ if (WBTEST_ENABLED(WBTEST_BADEXEC_HELPER_PROCESS))
+ STRCPY(helper_cmd, "ersatz");
if (-1 == EXECL(helper_cmd, helper_cmd, UPDHELPER_CMD_ARG1, UPDHELPER_CMD_ARG2,
(UPD_HELPER_READER == helper_type) ? UPDHELPER_READER_CMD_ARG3 : UPDHELPER_WRITER_CMD_ARG3, NULL))
{
save_errno = errno;
helper->helper_shutdown = save_shutdown;
- gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_HLPPROC, 0, ERR_TEXT, 2,
LEN_AND_LIT("Could not exec Helper Process"), save_errno);
repl_errno = EREPL_UPDSTART_EXEC;
- return UPDPROC_START_ERR;
+ _exit(UPDPROC_START_ERR);
}
}
#elif defined(VMS)
diff --git a/sr_port/gtmrecv_upd_proc_init.c b/sr_port/gtmrecv_upd_proc_init.c
index 0d84541..df50d66 100644
--- a/sr_port/gtmrecv_upd_proc_init.c
+++ b/sr_port/gtmrecv_upd_proc_init.c
@@ -45,8 +45,9 @@
#include "repl_log.h"
#include "eintr_wrappers.h"
#include "gtmimagename.h"
+#include "wbox_test_init.h"
-#define UPDPROC_CMD_MAXLEN 1024
+#define UPDPROC_CMD_MAXLEN GTM_PATH_MAX
#define UPDPROC_CMD "%s/mupip"
#define UPDPROC_CMD_FILE "mupip"
#define UPDPROC_CMD_ARG1 "replicate"
@@ -68,6 +69,7 @@ error_def(ERR_LOGTOOLONG);
error_def(ERR_RECVPOOLSETUP);
error_def(ERR_REPLINFO);
error_def(ERR_TEXT);
+error_def(ERR_UPDPROC);
int gtmrecv_upd_proc_init(boolean_t fresh_start)
{
@@ -101,7 +103,7 @@ int gtmrecv_upd_proc_init(boolean_t fresh_start)
return(UPDPROC_EXISTS);
} else if (upd_status == SRV_ALIVE)
{
- gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDPROC, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Update process already exists. Please kill it before a fresh start"));
return(UPDPROC_EXISTS);
}
@@ -113,11 +115,24 @@ int gtmrecv_upd_proc_init(boolean_t fresh_start)
if (!gtm_dist_ok_to_use)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_GTMDISTUNVERIF, 4, STRLEN(gtm_dist), gtm_dist,
gtmImageNames[image_type].imageNameLen, gtmImageNames[image_type].imageName);
+ if (WBTEST_ENABLED(WBTEST_MAXGTMDIST_UPDATE_PROCESS))
+ {
+ memset(gtm_dist, 'a', GTM_PATH_MAX-2);
+ gtm_dist[GTM_PATH_MAX-1] = '\0';
+ }
+ upd_proc_cmd_len = SNPRINTF(upd_proc_cmd, UPDPROC_CMD_MAXLEN, UPDPROC_CMD, gtm_dist);
+ if ((-1 == upd_proc_cmd_len) || (UPDPROC_CMD_MAXLEN <= upd_proc_cmd_len))
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDPROC, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Could not find path of Update Process. Check value of $gtm_dist"));
+ repl_errno = EREPL_UPDSTART_BADPATH;
+ return(UPDPROC_START_ERR);
+ }
FORK(upd_pid);
if (0 > upd_pid)
{
recvpool.upd_proc_local->upd_proc_shutdown = save_upd_status;
- gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_UPDPROC, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Could not fork update process"), errno);
repl_errno = EREPL_UPDSTART_FORK;
return(UPDPROC_START_ERR);
@@ -125,20 +140,14 @@ int gtmrecv_upd_proc_init(boolean_t fresh_start)
if (0 == upd_pid)
{
/* Update Process */
- upd_proc_cmd_len = SNPRINTF(upd_proc_cmd, UPDPROC_CMD_MAXLEN, UPDPROC_CMD, gtm_dist);
- if (-1 == upd_proc_cmd_len)
- {
- gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Could not find path of Update Process. Check value of $gtm_dist"));
- repl_errno = EREPL_UPDSTART_BADPATH;
- return(UPDPROC_START_ERR);
- }
+ if (WBTEST_ENABLED(WBTEST_BADEXEC_UPDATE_PROCESS))
+ STRCPY(upd_proc_cmd, "ersatz");
if (EXECL(upd_proc_cmd, upd_proc_cmd, UPDPROC_CMD_ARG1, UPDPROC_CMD_ARG2, NULL) < 0)
{
- gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_UPDPROC, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Could not exec Update Process"), errno);
repl_errno = EREPL_UPDSTART_EXEC;
- return(UPDPROC_START_ERR);
+ _exit(UPDPROC_START_ERR);
}
}
#elif defined(VMS)
@@ -190,12 +199,12 @@ int gtmrecv_start_updonly(void)
if ((upd_status = is_updproc_alive()) == SRV_ALIVE)
{
- gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDPROC, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Update Process exists already. New process not started"));
return(UPDPROC_START_ERR);
} else if (upd_status == SRV_ERR)
{
- gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDPROC, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Error in starting up update process"));
return(UPDPROC_START_ERR);
}
@@ -220,15 +229,15 @@ int gtmrecv_start_updonly(void)
#endif
if (start_status == UPDPROC_START)
{
- gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDPROC, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Receiver server is not alive to start update process. Please start receiver server"));
} else if (start_status == UPDPROC_START_ERR)
{
- gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDPROC, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Error starting update process"));
} else if (start_status == UPDPROC_EXISTS)
{
- gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDPROC, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Update Process exists already. New process not started"));
}
return(UPDPROC_START_ERR);
diff --git a/sr_port/gv_select.c b/sr_port/gv_select.c
index eaa6cdf..9630afc 100644
--- a/sr_port/gv_select.c
+++ b/sr_port/gv_select.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -46,6 +46,15 @@
#include "gvnh_spanreg.h"
#include "change_reg.h"
+#ifdef EXTRACT_HASHT_GLOBAL
+# include "gv_trigger_common.h" /* for IS_GVKEY_HASHT_GBLNAME and HASHT_GBL_CHAR1 macros */
+# ifdef GTM_TRIGGER
+# include "gv_trigger.h"
+# include "targ_alloc.h"
+# include "gvcst_protos.h" /* for gvcst_root_search prototype used in GVTR_SWITCH_REG_AND_HASHT_BIND_NAME macro */
+# endif
+#endif
+
#define MAX_GMAP_ENTRIES_PER_ITER 2 /* maximum increase (could even be negative) in gmap array size per call to global_map */
error_def(ERR_DBRDONLY);
@@ -89,6 +98,11 @@ void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist
# else
hash_table_int4 ext_hash;
# endif
+# ifdef EXTRACT_HASHT_GLOBAL
+ gvnh_reg_t *hashgbl_gvnh_reg = NULL;
+ gd_region *r_top;
+ sgmnt_addrs *csa;
+# endif
memset(gmap, 0, SIZEOF(gmap));
gmap_size = SIZEOF(gmap) / SIZEOF(gmap[0]);
@@ -231,6 +245,39 @@ void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist
*/
if (MAX_MIDENT_LEN < curr_gbl_name.str.len)
curr_gbl_name.str.len = MAX_MIDENT_LEN;
+# if defined(GTM_TRIGGER) && defined(EXTRACT_HASHT_GLOBAL)
+ if (HASHT_GBL_CHAR1 == curr_gbl_name.str.addr[0])
+ { /* Global names starting with "#" e.g. ^#t. Consider these as spanning across
+ * all regions of the gbldir for the purposes of the caller (MUPIP EXTRACT
+ * or MUPIP REORG or MUPIP SIZE).
+ */
+ if (NULL == hashgbl_gvnh_reg)
+ {
+ hashgbl_gvnh_reg = (gvnh_reg_t *)malloc(SIZEOF(gvnh_reg_t));
+ /* initialize gvnh_reg fields to NULL specifically gvnh_reg->gvspan
+ * as this is used by the caller of gv_select.
+ */
+ memset(hashgbl_gvnh_reg, 0, SIZEOF(gvnh_reg_t));
+ }
+ /* At this time, only ^#t is supported. In the future ^#k or some such globals
+ * might be supported for other purposes. The following code needs to change if/when
+ * that happens.
+ */
+ assert(IS_GVKEY_HASHT_GBLNAME(curr_gbl_name.str.len, curr_gbl_name.str.addr));
+ if (!gd_header)
+ gvinit();
+ for (reg = gd_header->regions, r_top = reg + gd_header->n_regions; reg < r_top; reg++)
+ {
+ GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(reg);
+ csa = cs_addrs;
+ if (NULL == csa) /* not BG or MM access method */
+ continue;
+ gv_select_reg((void *)&ext_hash, freeze, reg_max_rec, reg_max_key,
+ reg_max_blk, restrict_reg, hashgbl_gvnh_reg, &gl_tail);
+ }
+ break;
+ }
+# endif
COMPUTE_HASH_MSTR(curr_gbl_name.str, hash_code);
op_gvname_fast(VARLSTCNT(2) hash_code, &curr_gbl_name);
assert((dba_bg == REG_ACC_METH(gv_cur_region)) || (dba_mm == REG_ACC_METH(gv_cur_region)));
@@ -246,8 +293,9 @@ void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist
gv_select_reg((void *)&ext_hash, freeze, reg_max_rec, reg_max_key, reg_max_blk,
restrict_reg, gvnh_reg, &gl_tail);
else
- { /* If global spans multiple regions, make sure gv_targets corresponding to ALL spanned regions
- * are allocated and gv_target->root is also initialized accordingly for all the spanned regions.
+ { /* If global spans multiple regions, make sure gv_targets corresponding to ALL
+ * spanned regions are allocated and gv_target->root is also initialized
+ * accordingly for all the spanned regions.
*/
gvnh_spanreg_subs_gvt_init(gvnh_reg, gd_header, NULL);
maxi = gvspan->max_reg_index;
@@ -264,7 +312,7 @@ void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist
gv_cur_region = reg;
change_reg();
gv_select_reg((void *)&ext_hash, freeze, reg_max_rec, reg_max_key,
- reg_max_blk, restrict_reg, gvnh_reg, &gl_tail);
+ reg_max_blk, restrict_reg, gvnh_reg, &gl_tail);
}
}
}
@@ -282,6 +330,10 @@ void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist
}
if (gmap_ptr_base != &gmap[0])
free(gmap_ptr_base);
+# ifdef EXTRACT_HASHT_GLOBAL
+ if (NULL != hashgbl_gvnh_reg)
+ free(hashgbl_gvnh_reg);
+# endif
}
/* Assumes "gv_target" and "gv_cur_region" are properly setup at function entry */
diff --git a/sr_port/gv_trigger_common.h b/sr_port/gv_trigger_common.h
index 0bf42d9..49ee3cc 100644
--- a/sr_port/gv_trigger_common.h
+++ b/sr_port/gv_trigger_common.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010 Fidelity Information Services, Inc *
+ * Copyright 2010, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -39,35 +39,18 @@
&& (HASHT_GBL_CHAR1 == ADDR[1]) \
&& (HASHT_GBL_CHAR2 == ADDR[2]))
-#define HASHT_GBL_CURLABEL "2" /* Currently supported ^#t global format */
+#define HASHT_GBL_CURLABEL "3" /* Currently supported ^#t global format */
/* HASHT_GBL_CURLABEL values of prior trigger versions */
#define V19_HASHT_GBL_LABEL "1" /* V5.4-000 to V5.4-001 */
+#define V21_HASHT_GBL_LABEL "2" /* V5.4-002 to V6.2-000 */
#define LITERAL_HASHLABEL "#LABEL"
#define LITERAL_HASHCYCLE "#CYCLE"
#define LITERAL_HASHCOUNT "#COUNT"
-#define LITERAL_CMD "CMD"
-#define LITERAL_GVSUBS "GVSUBS"
-#define LITERAL_OPTIONS "OPTIONS"
-#define LITERAL_DELIM "DELIM"
-#define LITERAL_ZDELIM "ZDELIM"
-#define LITERAL_PIECES "PIECES"
-#define LITERAL_TRIGNAME "TRIGNAME"
-#define LITERAL_XECUTE "XECUTE"
-#define LITERAL_CHSET "CHSET"
#define LITERAL_HASHLABEL_LEN STR_LIT_LEN(LITERAL_HASHLABEL)
#define LITERAL_HASHCYCLE_LEN STR_LIT_LEN(LITERAL_HASHCYCLE)
#define LITERAL_HASHCOUNT_LEN STR_LIT_LEN(LITERAL_HASHCOUNT)
-#define LITERAL_CMD_LEN STR_LIT_LEN(LITERAL_CMD)
-#define LITERAL_GVSUBS_LEN STR_LIT_LEN(LITERAL_GVSUBS)
-#define LITERAL_OPTIONS_LEN STR_LIT_LEN(LITERAL_OPTIONS)
-#define LITERAL_DELIM_LEN STR_LIT_LEN(LITERAL_DELIM)
-#define LITERAL_ZDELIM_LEN STR_LIT_LEN(LITERAL_ZDELIM)
-#define LITERAL_PIECES_LEN STR_LIT_LEN(LITERAL_PIECES)
-#define LITERAL_XECUTE_LEN STR_LIT_LEN(LITERAL_XECUTE)
-#define LITERAL_TRIGNAME_LEN STR_LIT_LEN(LITERAL_TRIGNAME)
-#define LITERAL_CHSET_LEN STR_LIT_LEN(LITERAL_CHSET)
#endif
diff --git a/sr_port/gvcst_init.c b/sr_port/gvcst_init.c
index 077c324..a27882e 100644
--- a/sr_port/gvcst_init.c
+++ b/sr_port/gvcst_init.c
@@ -56,6 +56,7 @@
#include "process_gvt_pending_list.h"
#include "gvt_hashtab.h"
#include "gtmmsg.h"
+#include "op.h"
#ifdef UNIX
#include "heartbeat_timer.h"
#include "anticipatory_freeze.h"
@@ -68,6 +69,7 @@
#include "gtm_dbjnl_dupfd_check.h"
#endif
+GBLREF boolean_t mu_reorg_process;
GBLREF gd_region *gv_cur_region, *db_init_region;
GBLREF sgmnt_data_ptr_t cs_data;
GBLREF sgmnt_addrs *cs_addrs;
@@ -100,7 +102,9 @@ GBLREF boolean_t pool_init;
GBLREF boolean_t jnlpool_init_needed;
GBLREF jnlpool_addrs jnlpool;
#endif
-
+#ifdef DEBUG
+GBLREF uint4 process_id;
+#endif
LITREF char gtm_release_name[];
LITREF int4 gtm_release_name_len;
@@ -113,6 +117,9 @@ error_def(ERR_DBVERPERFWARN2);
error_def(ERR_MMNODYNUPGRD);
error_def(ERR_REGOPENFAIL);
+static readonly mval literal_poollimit =
+ DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, (SIZEOF("POOLLIMIT") - 1), "POOLLIMIT", 0, 0);
+
void assert_jrec_member_offsets(void)
{
assert(REAL_JNL_HDR_LEN % DISK_BLOCK_SIZE == 0);
@@ -223,6 +230,7 @@ void gvcst_init(gd_region *greg)
# endif
int max_fid_index;
mstr log_nam, trans_log_nam;
+ mval reg_nam_mval = DEFINE_MVAL_STRING(MV_STR, 0 , 0 , SIZEOF(MAX_RN_LEN), 0, 0, 0);
char trans_buff[MAX_FN_LEN + 1];
unique_file_id *greg_fid, *reg_fid;
tp_region *tr;
@@ -325,6 +333,8 @@ void gvcst_init(gd_region *greg)
csa->hdr = NULL;
csa->nl = NULL;
csa->jnl = NULL;
+ csa->gbuff_limit = 0;
+ csa->our_midnite = NULL;
csa->persistent_freeze = FALSE; /* want secshr_db_clnup() to clear an incomplete freeze/unfreeze codepath */
csa->regcnt = 1; /* At this point, only one region points to this csa */
csa->db_addrs[0] = csa->db_addrs[1] = NULL;
@@ -638,7 +648,37 @@ void gvcst_init(gd_region *greg)
assert(0 == reformat_buffer_in_use);
--fast_lock_count;
}
-
+ assert(MV_STR & (TREF(gbuff_limit)).mvtype);
+ if (mu_reorg_process && (0 == (TREF(gbuff_limit)).str.len))
+ { /* if the environment variable wasn't supplied, use the default for REORG */
+ (TREF(gbuff_limit)).str.len = SIZEOF(REORG_GBUFF_LIMIT);
+ (TREF(gbuff_limit)).str.addr = malloc(SIZEOF(REORG_GBUFF_LIMIT));
+ memcpy((TREF(gbuff_limit)).str.addr, REORG_GBUFF_LIMIT, SIZEOF(REORG_GBUFF_LIMIT));
+ }
+ if ((0 != (TREF(gbuff_limit)).str.len) PRO_ONLY(&& mu_reorg_process)) /* if reorg or dbg apply env var */
+ {
+ reg_nam_mval.str.len = greg->rname_len;
+ reg_nam_mval.str.addr = (char *)&greg->rname;
+ op_view(VARLSTCNT(3) &literal_poollimit, ®_nam_mval, &(TREF(gbuff_limit)));
+# ifdef DEBUG
+ if (!mu_reorg_process) /* in dbg, randomize sizes to get test coverage */
+ {
+ if ((process_id & 1) ^ csa->regnum)
+ {
+ csa->gbuff_limit ^= process_id;
+ csa->gbuff_limit &= ((csd->n_bts / 2) - 1);
+ } else
+ csa->gbuff_limit = 0;
+ }
+ if (process_id & 2) /* also randomize our_midnite */
+ {
+ csa->our_midnite = csa->acc_meth.bg.cache_state->cache_array + csd->bt_buckets;
+ csa->our_midnite += (process_id & (csd->n_bts - 1));
+ assert((csa->acc_meth.bg.cache_state->cache_array + csd->bt_buckets + csd->n_bts)
+ > csa->our_midnite);
+ }
+# endif
+ }
}
if ((dba_bg == greg_acc_meth) || (dba_mm == greg_acc_meth))
{
diff --git a/sr_port/hashtab.h b/sr_port/hashtab.h
index f4a8893..8c7029c 100644
--- a/sr_port/hashtab.h
+++ b/sr_port/hashtab.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -65,15 +65,33 @@
free(base); \
}
-/*
-Different Hash Computation Macros for Strings:
-All these were experminted and result is given in the design document of V5.0-000 longname project.
-For now we decided to use ELF_HASH.
-Do not remove the commented out section below which has all the hash functions.
-We can remove them when we are certain that ELF_HASH is the best choice for us.
-*/
-
+/* For string hashing, ELF hash was found to be the best during the V5.0-000 longnames project.
+ * During V6.2-001, Murmur3 hash was found to be much better than ELF in terms of # of collisions.
+ * So we are going with MMR hash for now in Unix. In VMS, we dont yet have mmrhash.c so we continue
+ * to use ELF hash there (no point spending time to move mmrhash.c from sr_unix to sr_port).
+ * In addition, the 32-bit murmur3 hash gives different values for the same input on different endian
+ * machines which would not work at least for triggers since we expect the trigger definition M code to
+ * hash to the same value on different endian machines (this is needed so mupip endiancvt does not need
+ * to worry about changing ^#t(.*TRHASH.*) nodes. Therefore we came up with a modified 32-bit murmur3 hash
+ * implementation that is endian independent (gtmmrhash_32).
+ */
+#ifdef UNIX
+#include "mmrhash.h"
+#define STR_HASH(KEY, LEN, HASH, SEED) gtmmrhash_32(KEY, LEN, SEED, (uint4 *)&HASH)
+/* The STR_PHASH* macros are the progressive variants of the STR_HASH macro. */
+#define STR_PHASH_INIT(STATE, TOTLEN) HASH128_STATE_INIT(STATE, 0); TOTLEN = 0
+#define STR_PHASH_PROCESS(STATE, TOTLEN, KEY, LEN) gtmmrhash_128_ingest(&STATE, KEY, LEN); TOTLEN += LEN
+#define STR_PHASH_RESULT(STATE, TOTLEN, OUT4) \
+{ \
+ gtm_uint16 out16; \
+ \
+ gtmmrhash_128_result(&STATE, TOTLEN, &out16); \
+ OUT4 = (uint4)out16.one; \
+}
+#else
#define STR_HASH ELF_HASH
+#endif
+
#define ELF_HASH(sptr, len, hash, init_hashval) \
{ \
uint4 tempint; \
@@ -89,61 +107,4 @@ We can remove them when we are certain that ELF_HASH is the best choice for us.
hash = hcode; \
}
-/*
-#define CHAR_BITS 8
-#define BITS_IN_int (SIZEOF(int) * CHAR_BITS)
-#define THREE_QUARTERS (BITS_IN_int * 3 / 4)
-#define ONE_EIGHTH (BITS_IN_int / 8)
-#define HIGH_BITS (~((unsigned int)(~0) >> ONE_EIGHTH ))
-#define PJW_HASH(sptr, len, hash, init_hashval) \
-{ \
- uint4 tempint; \
- char *curr, *top; \
- hash = init_hashval; \
- for (curr = sptr, top = sptr + len; curr < top; curr++) \
- { \
- hash = ( hash << ONE_EIGHTH ) + *curr; \
- if ((tempint = hash & HIGH_BITS ) != 0 ) \
- hash = ( hash ^ ( tempint >> THREE_QUARTERS )) & ~HIGH_BITS;\
- } \
-}
-
-
-#define MISC1_HASH(sptr, len, hash, init_hashval) \
-{ \
- char *curr; \
- curr = sptr; \
- int indx; \
- hash = init_hashval; \
- for (indx = 0; indx < len; indx++, curr++) \
- hash += (*curr * (len - indx)); \
-}
-#define MISC2_HASH(sptr, len, hash, init_hashval) \
-
-{ \
- char *curr; \
- curr = sptr; \
- int indx; \
- hash = init_hashval; \
- for (indx = 0; indx < len; indx++, curr++) \
- hash = hash*31 + *curr; \
-}
-
-#define CURR_HASH(sptr, len, hash, init_hashval) \
-{ \
- char *ptr, tchar[MAXLEN]; \
- int indx; \
- uint4 temp1 = 0; \
- uint4 temp2 = 0; \
- memset(tchar, 0, MAXLEN); \
- memcpy(tchar, sptr, len); \
- ptr = &tchar[0]; \
- for ( indx = 0; indx < 4; indx++, ptr++) \
- temp1 = temp1 * 256 + *ptr ; \
- for ( ; indx < 8; indx++, ptr++) \
- temp2 = temp2 * 256 + *ptr ; \
- hash = (temp1 << 1) ^ (temp2) ; \
-}
-*/
-
#endif
diff --git a/sr_port/have_crit.h b/sr_port/have_crit.h
index 5d5d57e..83baf05 100644
--- a/sr_port/have_crit.h
+++ b/sr_port/have_crit.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -188,6 +188,7 @@ GBLREF boolean_t deferred_timers_check_needed;
#define OK_TO_SEND_MSG ((INTRPT_IN_X_TIME_FUNCTION != intrpt_ok_state) \
&& (INTRPT_IN_LOG_FUNCTION != intrpt_ok_state) \
+ && (INTRPT_IN_FUNC_WITH_MALLOC != intrpt_ok_state) \
&& (INTRPT_IN_FORK_OR_SYSTEM != intrpt_ok_state))
uint4 have_crit(uint4 crit_state);
diff --git a/sr_port/indir.h b/sr_port/indir.h
index 573220b..9c14e7b 100644
--- a/sr_port/indir.h
+++ b/sr_port/indir.h
@@ -85,6 +85,6 @@ INDIR(indir_fndata, f_data, OC_FNDATA)
,INDIR(indir_savglvn0, indirection, 0) /* this entry and the following use indirection as a dummy value */
,INDIR(indir_savlvn, indirection, 0)
,INDIR(indir_savglvn1, indirection, 0) /* 0 and 1 (above) separate 2 variants of generated code */
-#ifdef USHBIN_SUPPORTED
+#ifdef AUTORELINK_SUPPORTED
,INDIR(indir_zrupdate, m_zrupdate, 0)
#endif
diff --git a/sr_port/indirection.c b/sr_port/indirection.c
index be0b419..75ccac1 100644
--- a/sr_port/indirection.c
+++ b/sr_port/indirection.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -24,7 +24,7 @@ GBLREF boolean_t run_time;
GBLREF char *lexical_ptr;
GBLREF spdesc stringpool;
GBLREF unsigned char *source_buffer;
-GBLREF short int source_column;
+GBLREF int source_column;
error_def(ERR_BOOLSIDEFFECT);
error_def(ERR_EXPR);
diff --git a/sr_port/io_rundown.c b/sr_port/io_rundown.c
index f703063..e8f375d 100644
--- a/sr_port/io_rundown.c
+++ b/sr_port/io_rundown.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -55,7 +55,7 @@ void io_dev_close (io_log_name *d)
return;
}
- ESTABLISH(lastchance3);
+ VMS_ONLY(ESTABLISH(lastchance3);)
pp.mvtype = MV_STR;
pp.str.addr = (char *) p;
pp.str.len = SIZEOF(p);
@@ -63,5 +63,5 @@ void io_dev_close (io_log_name *d)
(d->iod->pair.in->disp_ptr->close)(d->iod->pair.in, &pp);
if (d->iod->pair.out && d->iod->pair.out->state == dev_open)
(d->iod->pair.out->disp_ptr->close)(d->iod->pair.out, &pp);
- REVERT;
+ VMS_ONLY(REVERT;)
}
diff --git a/sr_port/iosocket_close.c b/sr_port/iosocket_close.c
index 4347f8a..2629caa 100644
--- a/sr_port/iosocket_close.c
+++ b/sr_port/iosocket_close.c
@@ -37,6 +37,9 @@
#include "iosocketdef.h"
#include "stringpool.h"
#include "eintr_wrappers.h"
+#ifdef GTM_TLS
+#include "gtm_tls.h"
+#endif
GBLREF io_desc *active_device;
GBLREF int process_exiting;
@@ -50,6 +53,7 @@ error_def(ERR_CLOSEFAIL);
error_def(ERR_FILEOPENFAIL);
error_def(ERR_SOCKNOTFND);
error_def(ERR_SYSCALL);
+error_def(ERR_TLSIOERROR);
void iosocket_close_range(d_socket_struct *dsocketptr, int start, int end, boolean_t socket_delete, boolean_t socket_specified);
@@ -59,7 +63,7 @@ void iosocket_close(io_desc *iod, mval *pp)
unsigned char ch;
int handle_len;
d_socket_struct *dsocketptr;
- char sock_handle[MAX_HANDLE_LEN];
+ char sock_handle[MAX_HANDLE_LEN], *errp;
int4 start, end, index;
int p_offset = 0;
boolean_t socket_destroy = FALSE;
@@ -152,6 +156,7 @@ void iosocket_close_range(d_socket_struct *dsocketptr, int start, int end, boole
{
int4 ii,jj;
int rc, save_fd, save_rc = 0, save_errno;
+ ssize_t status;
socket_struct *socketptr;
# ifndef VMS
struct stat statbuf, fstatbuf;
@@ -182,6 +187,28 @@ void iosocket_close_range(d_socket_struct *dsocketptr, int start, int end, boole
LEN_AND_LIT("unlink during socket delete"), CALLFROM, errno);
}
# endif
+ /* below is similar to iosocket_flush but socketptr may not be current socket */
+ if (socketptr->obuffer_timer_set)
+ {
+ cancel_timer((TID)socketptr);
+ socketptr->obuffer_timer_set = FALSE;
+ }
+ status = 1; /* OK value */
+ if ((0 < socketptr->obuffer_length) && (0 == socketptr->obuffer_errno))
+ {
+ socketptr->obuffer_output_active = TRUE;
+ status = iosocket_output_buffer(socketptr);
+ socketptr->obuffer_output_active = FALSE;
+ }
+ if ((0 < socketptr->obuffer_size) && ((0 >= status) || (0 != socketptr->obuffer_errno)))
+ iosocket_buffer_error(socketptr); /* pre-existing error or error flushing buffer */
+#ifdef GTM_TLS
+ if (socketptr->tlsenabled)
+ {
+ gtm_tls_session_close((gtm_tls_socket_t **)&socketptr->tlssocket);
+ socketptr->tlsenabled = FALSE;
+ }
+#endif
CLOSE(socketptr->sd, rc);
if (-1 == rc)
{
diff --git a/sr_port/iosocket_flush.c b/sr_port/iosocket_flush.c
index cb695c7..d4cace2 100644
--- a/sr_port/iosocket_flush.c
+++ b/sr_port/iosocket_flush.c
@@ -29,13 +29,14 @@ error_def(ERR_SOCKPASSDATAMIX);
error_def(ERR_SOCKWRITE);
error_def(ERR_TEXT);
+GBLREF io_pair io_std_device;
+
void iosocket_flush(io_desc *iod)
{
-#ifdef C9A06001531
- /* pending change request C9A06001531 */
d_socket_struct *dsocketptr;
socket_struct *socketptr;
+ ssize_t status;
int on = 1, off = 0;
char *errptr;
int4 errlen;
@@ -61,6 +62,25 @@ void iosocket_flush(io_desc *iod)
return;
}
ENSURE_DATA_SOCKET(socketptr);
+ if (socketptr->obuffer_timer_set)
+ {
+ cancel_timer((TID)socketptr);
+ socketptr->obuffer_timer_set = FALSE;
+ }
+ if (!socketptr->obuffer_output_active)
+ { /* just to be safe */
+ status = 1; /* OK value */
+ if ((0 < socketptr->obuffer_length) && (0 == socketptr->obuffer_errno))
+ {
+ socketptr->obuffer_output_active = TRUE;
+ status = iosocket_output_buffer(socketptr);
+ socketptr->obuffer_output_active = FALSE;
+ }
+ if ((0 < socketptr->obuffer_size) && ((0 >= status) || (0 != socketptr->obuffer_errno)))
+ iosocket_buffer_error(socketptr); /* pre-existing error or error flushing buffer */
+ }
+#ifdef C9A06001531
+ /* pending change request C9A06001531 */
memcpy(iod->dollar.device, "0", SIZEOF("0"));
if ( -1 == setsockopt(socketptr->sd, SOL_SOCKET, TCP_NODELAY, &on, SIZEOF(on)) ||
(-1 == setsockopt(socketptr->sd, SOL_SOCKET, TCP_NODELAY, &off, SIZEOF(off))))
diff --git a/sr_port/iosocket_iocontrol.c b/sr_port/iosocket_iocontrol.c
index 8e517a4..3dcb108 100644
--- a/sr_port/iosocket_iocontrol.c
+++ b/sr_port/iosocket_iocontrol.c
@@ -29,6 +29,7 @@
GBLREF spdesc stringpool;
GBLREF io_pair io_curr_device;
+LITREF mval skiparg;
error_def(ERR_EXPR);
error_def(ERR_INVCTLMNE);
@@ -46,6 +47,9 @@ void iosocket_iocontrol(mstr *mn, int4 argcnt, va_list args)
int length, n, timeout;
pid_t pid;
mval *arg, *handlesvar = NULL;
+#ifdef GTM_TLS
+ mval *option, *tlsid, *password, *extraarg;
+#endif
if (0 == mn->len)
return;
@@ -59,9 +63,9 @@ void iosocket_iocontrol(mstr *mn, int4 argcnt, va_list args)
else
{
arg = va_arg(args, mval *);
- if ((NULL == arg) || !MV_DEFINED(arg))
+ if ((NULL == arg) || M_ARG_SKIPPED(arg) || !MV_DEFINED(arg))
{
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(2) ERR_EXPR, 0);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_EXPR);
return;
}
depth = MV_FORCE_INTD(arg);
@@ -74,12 +78,13 @@ void iosocket_iocontrol(mstr *mn, int4 argcnt, va_list args)
else
{
arg = va_arg(args, mval *);
- if ((NULL == arg) || !MV_DEFINED(arg))
+ if ((NULL != arg) && !M_ARG_SKIPPED(arg) && MV_DEFINED(arg))
+ timeout = MV_FORCE_INTD(arg);
+ else
{
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(2) ERR_EXPR, 0);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_EXPR);
return;
}
- timeout = MV_FORCE_INTD(arg);
}
iosocket_wait(io_curr_device.in, timeout);
# ifndef VMS
@@ -90,48 +95,110 @@ void iosocket_iocontrol(mstr *mn, int4 argcnt, va_list args)
{
arg = va_arg(args, mval *);
n--;
- if ((NULL != arg) && MV_DEFINED(arg))
+ if ((NULL != arg) && !M_ARG_SKIPPED(arg) && MV_DEFINED(arg))
pid = MV_FORCE_INTD(arg);
else
pid = -1;
- }
+ } else
+ pid = -1;
if (2 <= argcnt)
{
arg = va_arg(args, mval *);
n--;
- if ((NULL != arg) && MV_DEFINED(arg))
+ if ((NULL != arg) && !M_ARG_SKIPPED(arg) && MV_DEFINED(arg))
timeout = MV_FORCE_INTD(arg);
else
timeout = NO_M_TIMEOUT;
- }
+ } else
+ timeout = NO_M_TIMEOUT;
iosocket_pass_local(io_curr_device.out, pid, timeout, n, args);
} else if (0 == memcmp(action, "ACCEPT", length))
{
n = argcnt;
if (1 <= argcnt)
{
- handlesvar = va_arg(args, mval *);
+ arg = va_arg(args, mval *);
n--;
+ if ((NULL != arg) && !M_ARG_SKIPPED(arg))
+ handlesvar = arg;
}
if (2 <= argcnt)
{
arg = va_arg(args, mval *);
n--;
- if ((NULL != arg) && MV_DEFINED(arg))
+ if ((NULL != arg) && !M_ARG_SKIPPED(arg) && MV_DEFINED(arg))
pid = MV_FORCE_INTD(arg);
else
pid = -1;
- }
+ } else
+ pid = -1;
if (3 <= argcnt)
{
arg = va_arg(args, mval *);
n--;
- if ((NULL != arg) && MV_DEFINED(arg))
+ if ((NULL != arg) && !M_ARG_SKIPPED(arg) && MV_DEFINED(arg))
timeout = MV_FORCE_INTD(arg);
else
timeout = NO_M_TIMEOUT;
- }
+ } else
+ timeout = NO_M_TIMEOUT;
iosocket_accept_local(io_curr_device.in, handlesvar, pid, timeout, n, args);
+#ifdef GTM_TLS
+ } else if (0 == memcmp(action, "TLS", length))
+ { /* WRITE /TLS(option[,[timeout][,tlsid[,password]]]) */
+ if (1 <= argcnt)
+ {
+ option = va_arg(args, mval *);
+ if ((NULL != option) && !M_ARG_SKIPPED(option) && MV_DEFINED(option))
+ MV_FORCE_STRD(option);
+ else
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_EXPR);
+ return;
+ }
+ } else
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_EXPR);
+ return;
+ }
+ if (2 <= argcnt)
+ {
+ arg = va_arg(args, mval *);
+ if ((NULL != arg) && !M_ARG_SKIPPED(arg) && MV_DEFINED(arg))
+ timeout = MV_FORCE_INTD(arg);
+ else
+ timeout = NO_M_TIMEOUT;
+ } else
+ timeout = NO_M_TIMEOUT;
+ if (3 <= argcnt)
+ {
+ tlsid = va_arg(args, mval *);
+ if ((NULL != tlsid) && !M_ARG_SKIPPED(tlsid) && MV_DEFINED(tlsid))
+ MV_FORCE_STRD(tlsid);
+ else
+ tlsid = NULL;
+ } else
+ tlsid = NULL;
+ if ((4 <= argcnt) && (NULL != tlsid))
+ { /* password only valid if tlsid provided */
+ password = va_arg(args, mval *);
+ if ((NULL != password) && !M_ARG_SKIPPED(password) && MV_DEFINED(password))
+ MV_FORCE_STRD(password);
+ else
+ password = NULL;
+ } else
+ password = NULL;
+ if (5 <= argcnt)
+ {
+ extraarg = va_arg(args, mval *);
+ if ((NULL != extraarg) && !M_ARG_SKIPPED(extraarg) && MV_DEFINED(extraarg))
+ MV_FORCE_STRD(extraarg);
+ else
+ extraarg = NULL;
+ } else
+ extraarg = NULL;
+ iosocket_tls(option, timeout, tlsid, password, extraarg);
+# endif
# endif
} else
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVCTLMNE);
diff --git a/sr_port/iosocket_readfl.c b/sr_port/iosocket_readfl.c
index d1e1fdf..eaa9fc2 100644
--- a/sr_port/iosocket_readfl.c
+++ b/sr_port/iosocket_readfl.c
@@ -40,6 +40,9 @@
#include "send_msg.h"
#include "error.h"
#include "trace_table.h"
+#ifdef GTM_TLS
+#include "gtm_tls.h"
+#endif
GBLREF stack_frame *frame_pointer;
GBLREF unsigned char *stackbase, *stacktop, *msp, *stackwarn;
@@ -127,7 +130,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout)
int ret, byteperchar;
boolean_t timed, vari, more_data, terminator, has_delimiter, requeue_done, do_delim_conv, need_get_chset;
boolean_t zint_restart, outofband_terminate, one_read_done, utf8_active;
- int flags, len, real_errno, save_errno, fcntl_res, errlen, charlen, stp_need;
+ int flags, len, real_errno, save_errno, fcntl_res, errlen, devlen, charlen, stp_need;
int bytes_read, orig_bytes_read, ii, max_bufflen, bufflen, chars_read, mb_len, match_delim;
io_desc *iod;
d_socket_struct *dsocketptr;
@@ -889,9 +892,17 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout)
iod->dollar.za = 9;
len = SIZEOF(ONE_COMMA) - 1;
memcpy(iod->dollar.device, ONE_COMMA, len);
- errptr = (char *)STRERROR(real_errno);
+#ifdef GTM_TLS
+ if (socketptr->tlsenabled && (0 > real_errno))
+ errptr = (char *)gtm_tls_get_error();
+ else /* TLS not enabled or system call error */
+#endif
+ errptr = (char *)STRERROR(real_errno);
errlen = STRLEN(errptr);
- memcpy(&iod->dollar.device[len], errptr, errlen + 1); /* + 1 for null */
+ devlen = MIN((SIZEOF(iod->dollar.device) - len - 1), errlen);
+ memcpy(&iod->dollar.device[len], errptr, devlen + 1);
+ if (devlen < errlen)
+ iod->dollar.device[SIZEOF(iod->dollar.device) - 1] = '\0';
# ifdef UNIX
if (io_curr_device.in == io_std_device.in)
{
diff --git a/sr_port/iosocket_snr.c b/sr_port/iosocket_snr.c
index 9ed6573..579db52 100644
--- a/sr_port/iosocket_snr.c
+++ b/sr_port/iosocket_snr.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -62,6 +62,9 @@ static int fcntl_res;
#include "min_max.h"
#include "gtm_utf8.h"
#include "outofband.h"
+#ifdef GTM_TLS
+#include "gtm_tls.h"
+#endif
/* MAX_SNR_IO is for read loop in iosocket_snr_utf_prebuffer(). It is possible for a series of interrupts (one
* from each active region) to interfere with this read so be generous here.
@@ -77,6 +80,9 @@ GBLREF io_pair io_curr_device;
GBLREF bool out_of_time;
GBLREF spdesc stringpool;
GBLREF int4 outofband;
+#ifdef GTM_TLS
+GBLREF gtm_tls_ctx_t *tls_ctx;
+#endif
/* Local routine we aren't making static due to increased debugging difficult static routines make */
ssize_t iosocket_snr_io(socket_struct *socketptr, void *buffer, size_t maxlength, int flags, ABS_TIME *time_for_read);
@@ -145,13 +151,19 @@ ssize_t iosocket_snr(socket_struct *socketptr, void *buffer, size_t maxlength, i
*/
ssize_t iosocket_snr_io(socket_struct *socketptr, void *buffer, size_t maxlength, int flags, ABS_TIME *time_for_read)
{
- int status, bytesread, real_errno;
- fd_set tcp_fd;
- struct timeval lcl_time_for_read;
+ int status, real_errno;
+ ssize_t bytesread;
+ boolean_t pollread;
# ifdef GTM_USE_POLL_FOR_SUBSECOND_SELECT
long poll_timeout;
unsigned long poll_nfds;
struct pollfd poll_fdlist[1];
+# else
+ fd_set tcp_fd, *readfds, *writefds;
+ struct timeval lcl_time_for_read;
+# endif
+# ifdef GTM_TLS
+ int tlspolldirection = 0;
# endif
DBGSOCK2((stdout, "socsnrio: Socket read request - socketptr: 0x"lvaddr" buffer: 0x"lvaddr" maxlength: %d flags: %d ",
@@ -161,36 +173,92 @@ ssize_t iosocket_snr_io(socket_struct *socketptr, void *buffer, size_t maxlength
#ifndef GTM_USE_POLL_FOR_SUBSECOND_SELECT
assertpro(FD_SETSIZE > socketptr->sd);
FD_ZERO(&tcp_fd);
- FD_SET(socketptr->sd, &tcp_fd);
- assert(0 != FD_ISSET(socketptr->sd, &tcp_fd));
- lcl_time_for_read.tv_sec = time_for_read->at_sec;
- lcl_time_for_read.tv_usec = (gtm_tv_usec_t) time_for_read->at_usec;
- status = select(socketptr->sd + 1, (void *)(&tcp_fd), (void *)0, (void *)0, &lcl_time_for_read);
-#else
- poll_fdlist[0].fd = socketptr->sd;
- poll_fdlist[0].events = POLLIN;
- poll_nfds = 1;
- poll_timeout = time_for_read->at_usec / 1000; /* convert to millisecs */
- status = poll(&poll_fdlist[0], poll_nfds, poll_timeout);
#endif
- real_errno = errno;
- DEBUG_ONLY(gettimeofday(&tvafter, NULL);)
- DBGSOCK2((stdout, "socsnrio: Select return code: %d :: errno: %d\n", status, real_errno));
- if (0 < status)
+ while (TRUE)
{
- RECV(socketptr->sd, buffer, maxlength, flags, bytesread);
- real_errno = errno;
- socketptr->last_recv_errno = (-1 != status) ? 0 : real_errno; /* Save status of last recv for dbging purposes */
- DBGSOCK2((stdout, "socsnrio: aa_recv return code: %d :: errno: %d\n", bytesread, errno));
- if ((0 == bytesread) ||
- ((-1 == bytesread) && ((ECONNRESET == real_errno) || (EPIPE == real_errno) || (EINVAL == real_errno))))
- { /* Lost connection */
- if (0 == bytesread)
- errno = ECONNRESET;
- return (ssize_t)(-2);
- }
- DBGSOCK_ONLY2(errno = real_errno);
- return bytesread;
+ status = 0;
+# ifdef GTM_TLS
+ if (socketptr->tlsenabled)
+ {
+ pollread = (tlspolldirection == GTMTLS_WANT_WRITE) ? FALSE : TRUE;
+ status = gtm_tls_cachedbytes((gtm_tls_socket_t *)socketptr->tlssocket);
+ } else
+# endif
+ pollread = TRUE;
+ if (0 == status)
+ { /* if TLS cachedbytes available no need to poll */
+# ifndef GTM_USE_POLL_FOR_SUBSECOND_SELECT
+ FD_SET(socketptr->sd, &tcp_fd);
+ assert(0 != FD_ISSET(socketptr->sd, &tcp_fd));
+ lcl_time_for_read.tv_sec = time_for_read->at_sec;
+ lcl_time_for_read.tv_usec = (gtm_tv_usec_t)time_for_read->at_usec;
+ if (pollread)
+ {
+ readfds = &tcp_fd;
+ writefds = NULL;
+ } else
+ {
+ writefds = &tcp_fd;
+ readfds = NULL;
+ }
+ status = select(socketptr->sd + 1, readfds, writefds, NULL, &lcl_time_for_read);
+# else
+ poll_fdlist[0].fd = socketptr->sd;
+ poll_fdlist[0].events = pollread ? POLLIN : POLLOUT;
+ poll_nfds = 1;
+ poll_timeout = time_for_read->at_usec / 1000; /* convert to millisecs */
+ status = poll(&poll_fdlist[0], poll_nfds, poll_timeout);
+# endif
+ real_errno = errno;
+ DEBUG_ONLY(gettimeofday(&tvafter, NULL);)
+ DBGSOCK2((stdout, "socsnrio: Select return code: %d :: errno: %d\n", status, real_errno));
+ }
+ if (0 < status)
+ {
+# ifdef GTM_TLS
+ if (socketptr->tlsenabled)
+ {
+ bytesread = gtm_tls_recv((gtm_tls_socket_t *)socketptr->tlssocket, buffer, maxlength);
+ if (0 < bytesread)
+ return bytesread;
+ /* if want read or write, need to loop */
+ /* after setting tlspolldirection */
+ switch (bytesread)
+ {
+ case GTMTLS_WANT_READ:
+ tlspolldirection = GTMTLS_WANT_READ;
+ break;
+ case GTMTLS_WANT_WRITE:
+ tlspolldirection = GTMTLS_WANT_WRITE;
+ break;
+ default:
+ socketptr->last_recv_errno = errno = gtm_tls_errno();
+ if (ECONNRESET == errno)
+ {
+ return (ssize_t)(-2);
+ } else
+ return (ssize_t)(-1);
+ }
+ continue;
+ } else
+# endif
+ {
+ RECV(socketptr->sd, buffer, maxlength, flags, bytesread);
+ real_errno = errno;
+ socketptr->last_recv_errno = (-1 != status) ? 0 : real_errno; /* Save status for dbg purposes */
+ DBGSOCK2((stdout, "socsnrio: aa_recv return code: %d :: errno: %d\n", bytesread, errno));
+ if ((0 == bytesread) || ((-1 == bytesread) && ((ECONNRESET == real_errno) || (EPIPE == real_errno)
+ || (EINVAL == real_errno))))
+ { /* Lost connection */
+ if (0 == bytesread)
+ errno = ECONNRESET;
+ return (ssize_t)(-2);
+ }
+ DBGSOCK_ONLY2(errno = real_errno);
+ return bytesread;
+ }
+ } else
+ break; /* nothing ready */
}
DBGSOCK_ONLY2(errno = real_errno);
return (ssize_t)status;
@@ -266,8 +334,8 @@ ssize_t iosocket_snr_utf_prebuffer(io_desc *iod, socket_struct *socketptr, int f
break;
case CHSET_UTF16LE:
mblen = UTF16LE_MBFOLLOW(readptr, readptr + socketptr->buffered_length);
- if (0 > mblen)
- mblen = 1; /* If buffer is too small we will get -1 here. Assume need 2 chars */
+ if (0 > mblen)
+ mblen = 1; /* If buffer is too small we will get -1 here. Assume need 2 chars */
break;
case CHSET_UTF16:
/* Special case as we don't know which mode we are in. This should only be used when
@@ -281,7 +349,7 @@ ssize_t iosocket_snr_utf_prebuffer(io_desc *iod, socket_struct *socketptr, int f
{
mblen = UTF16BE_MBFOLLOW(readptr, readptr + socketptr->buffered_length);
if (0 > mblen)
- mblen = 1; /* If buffer is too small we will get -1 here. Assume need 2 chars */
+ mblen = 1; /* If buffer is too small we will get -1 here. Assume need 2 chars */
}
break;
default:
@@ -314,7 +382,7 @@ ssize_t iosocket_snr_utf_prebuffer(io_desc *iod, socket_struct *socketptr, int f
bytesread = (int)iosocket_snr_io(socketptr, readptr, readlen, flags, time_for_read);
DBGSOCK2((stdout, "socsnrupb: Read %d chars\n", bytesread));
if (0 > bytesread)
- { /* Some error occurred. Check for restartable condition. */
+ { /* Some error occurred. Check for restartable condition. */
if (EINTR == errno)
if (!out_of_time)
continue;
diff --git a/sr_port/iosocket_use.c b/sr_port/iosocket_use.c
index 2ed9c33..2753ea1 100644
--- a/sr_port/iosocket_use.c
+++ b/sr_port/iosocket_use.c
@@ -90,6 +90,7 @@ void iosocket_use(io_desc *iod, mval *pp)
bfsize_specified = FALSE,
ibfsize_specified = FALSE,
moreread_specified = FALSE,
+ flush_specified = FALSE,
create_new_socket;
int4 index, n_specified, zff_len, delimiter_len, moreread_timeout;
int fil_type, nodelay, p_offset = 0;
@@ -306,6 +307,10 @@ void iosocket_use(io_desc *iod, mval *pp)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_MRTMAXEXCEEDED, 1, MAX_MOREREAD_TIMEOUT);
moreread_specified = TRUE;
break;
+ case iop_flush:
+ n_specified++;
+ flush_specified = TRUE;
+ break;
default:
/* ignore deviceparm */
break;
@@ -495,6 +500,8 @@ void iosocket_use(io_desc *iod, mval *pp)
if (!create_new_socket)
{
/* these changes apply to only pre-existing sockets */
+ if (flush_specified)
+ iosocket_flush(iod); /* buffered output if any */
if (bfsize_specified)
newsocket.buffer_size = bfsize;
#ifdef TCP_NODELAY
diff --git a/sr_port/iosocket_wait.c b/sr_port/iosocket_wait.c
index 2ca1921..9774e3a 100644
--- a/sr_port/iosocket_wait.c
+++ b/sr_port/iosocket_wait.c
@@ -208,28 +208,31 @@ boolean_t iosocket_wait(io_desc *iod, int4 timepar)
}
if (nselect)
{
- utimeout.tv_sec = timepar;
- utimeout.tv_usec = 0;
- msec_timeout = timeout2msec(timepar);
- sys_get_curr_time(&cur_time);
- if (!retry_accept && (!zint_restart || !sockintr->end_time_valid))
- add_int_to_abs_time(&cur_time, msec_timeout, &end_time);
- else
- { /* end_time taken from restart data. Compute what msec_timeout should be so timeout timer
- gets set correctly below. Or retry after failed accept.
- */
- DBGSOCK((stdout, "socwait: Taking timeout end time from wait restart data\n"));
- cur_time = sub_abs_time(&end_time, &cur_time);
- if (0 > cur_time.at_sec)
- {
- msec_timeout = -1;
- utimeout.tv_sec = 0;
- utimeout.tv_usec = 0;
- } else
- {
- msec_timeout = (int4)(cur_time.at_sec * 1000 + cur_time.at_usec / 1000);
- utimeout.tv_sec = cur_time.at_sec;
- utimeout.tv_usec = (gtm_tv_usec_t)cur_time.at_usec;
+ if (NO_M_TIMEOUT != timepar)
+ {
+ utimeout.tv_sec = timepar;
+ utimeout.tv_usec = 0;
+ msec_timeout = timeout2msec(timepar);
+ sys_get_curr_time(&cur_time);
+ if (!retry_accept && (!zint_restart || !sockintr->end_time_valid))
+ add_int_to_abs_time(&cur_time, msec_timeout, &end_time);
+ else
+ { /* end_time taken from restart data. Compute what msec_timeout should be so timeout timer
+ gets set correctly below. Or retry after failed accept.
+ */
+ DBGSOCK((stdout, "socwait: Taking timeout end time from wait restart data\n"));
+ cur_time = sub_abs_time(&end_time, &cur_time);
+ if (0 > cur_time.at_sec)
+ {
+ msec_timeout = -1;
+ utimeout.tv_sec = 0;
+ utimeout.tv_usec = 0;
+ } else
+ {
+ msec_timeout = (int4)(cur_time.at_sec * 1000 + cur_time.at_usec / 1000);
+ utimeout.tv_sec = cur_time.at_sec;
+ utimeout.tv_usec = (gtm_tv_usec_t)cur_time.at_usec;
+ }
}
}
zint_restart = sockintr->end_time_valid = FALSE;
@@ -265,8 +268,12 @@ boolean_t iosocket_wait(io_desc *iod, int4 timepar)
mv_chain->mv_st_cont.mvs_zintdev.io_ptr = iod;
mv_chain->mv_st_cont.mvs_zintdev.buffer_valid = FALSE;
sockintr->who_saved = sockwhich_wait;
- sockintr->end_time = end_time;
- sockintr->end_time_valid = TRUE;
+ if (NO_M_TIMEOUT != timepar)
+ {
+ sockintr->end_time = end_time;
+ sockintr->end_time_valid = TRUE;
+ } else
+ sockintr->end_time_valid = FALSE;
dsocketptr->mupintr = TRUE;
socketus_interruptus++;
DBGSOCK((stdout, "socwait: mv_stent queued - endtime: %d/%d"
@@ -277,15 +284,18 @@ boolean_t iosocket_wait(io_desc *iod, int4 timepar)
assertpro(FALSE); /* Should *never* return from outofband_action */
return FALSE; /* For the compiler.. */
}
- sys_get_curr_time(&cur_time);
- cur_time = sub_abs_time(&end_time, &cur_time);
- if (0 > cur_time.at_sec)
+ if (NO_M_TIMEOUT != timepar)
{
- rv = 0; /* time out */
- break;
+ sys_get_curr_time(&cur_time);
+ cur_time = sub_abs_time(&end_time, &cur_time);
+ if (0 > cur_time.at_sec)
+ {
+ rv = 0; /* time out */
+ break;
+ }
+ utimeout.tv_sec = cur_time.at_sec;
+ utimeout.tv_usec = (gtm_tv_usec_t)cur_time.at_usec;
}
- utimeout.tv_sec = cur_time.at_sec;
- utimeout.tv_usec = (gtm_tv_usec_t)cur_time.at_usec;
} else
break; /* either other error or done */
}
@@ -293,8 +303,11 @@ boolean_t iosocket_wait(io_desc *iod, int4 timepar)
{ /* none selected or prior pending event */
iod->dollar.key[0] = '\0';
if (NO_M_TIMEOUT != timepar)
+ {
dollar_truth = FALSE;
- return FALSE;
+ return FALSE;
+ } else
+ continue;
} else if (rv < 0)
{
errptr = (char *)STRERROR(errno);
@@ -306,8 +319,11 @@ boolean_t iosocket_wait(io_desc *iod, int4 timepar)
{ /* nothing to select and no pending events */
iod->dollar.key[0] = '\0';
if (NO_M_TIMEOUT != timepar)
+ {
dollar_truth = FALSE;
- return FALSE;
+ return FALSE;
+ } else
+ continue;
}
/* find out which sockets are ready */
oldestlistencycle = oldestconnectedcycle = oldesteventcycle = 0;
@@ -324,7 +340,7 @@ boolean_t iosocket_wait(io_desc *iod, int4 timepar)
break;
}
assertpro((0 == jj) || (jj <= poll_nfds)); /* equal poll_nfds if not polled */
- if (nselect && (jj != poll_nfds) && (socketptr->sd == poll_fds[jj].fd) && (poll_fds[jj].revents & POLLIN))
+ if (nselect && (jj != poll_nfds) && (socketptr->sd == poll_fds[jj].fd) && poll_fds[jj].revents)
#endif
#ifdef USE_SELECT
assertpro(FD_SETSIZE > socketptr->sd);
@@ -374,7 +390,16 @@ boolean_t iosocket_wait(io_desc *iod, int4 timepar)
oldesteventcycle = oldestconnectedcycle;
oldesteventindex = oldestconnectedindex;
} else
- assertpro((0 < oldestlistencycle) || (0 < oldestconnectedcycle));
+ { /* unexpected nothing to do */
+ assert((0 < oldestlistencycle) || (0 < oldestconnectedcycle));
+ iod->dollar.key[0] = '\0';
+ if (NO_M_TIMEOUT != timepar)
+ {
+ dollar_truth = FALSE;
+ return FALSE;
+ } else
+ continue;
+ }
socketptr = dsocketptr->socket[oldesteventindex];
socketptr->pendingevent = FALSE;
if (socket_listening == socketptr->state)
diff --git a/sr_port/iosocket_write.c b/sr_port/iosocket_write.c
index 03c9ba4..4c53402 100644
--- a/sr_port/iosocket_write.c
+++ b/sr_port/iosocket_write.c
@@ -14,6 +14,11 @@
#include "mdef.h"
#include <errno.h>
+#ifdef USE_POLL
+#include <poll.h>
+#else
+#include "gtm_select.h"
+#endif
#include "gtm_socket.h"
#include "gtm_inet.h"
#include "gtm_stdio.h"
@@ -26,9 +31,14 @@
#include "dollarx.h"
#include "gtm_conv.h"
#include "gtm_utf8.h"
+#include "min_max.h"
#include "stringpool.h"
#include "send_msg.h"
#include "error.h"
+#include "rel_quant.h"
+#ifdef GTM_TLS
+#include "gtm_tls.h"
+#endif
GBLREF io_pair io_curr_device;
#ifdef UNIX
@@ -39,6 +49,9 @@ GBLREF bool prin_out_dev_failure;
GBLREF mstr chset_names[];
GBLREF UConverter *chset_desc[];
GBLREF spdesc stringpool;
+#ifdef GTM_TLS
+GBLREF gtm_tls_ctx_t *tls_ctx;
+#endif
error_def(ERR_CURRSOCKOFR);
error_def(ERR_DELIMSIZNA);
@@ -47,10 +60,11 @@ error_def(ERR_NOSOCKETINDEV);
error_def(ERR_SOCKPASSDATAMIX);
error_def(ERR_SOCKWRITE);
error_def(ERR_TEXT);
+UNIX_ONLY(error_def(ERR_TLSIOERROR);)
error_def(ERR_ZFF2MANY);
error_def(ERR_ZINTRECURSEIO);
-#define DOTCPSEND(SDESC, SBUFF, SBUFF_LEN, SFLAGS, RC) \
+#define DOTCPSEND_REAL(SOCKETPTR, SBUFF, SBUFF_LEN, SFLAGS, RC) \
{ \
ssize_t gtmioStatus; \
size_t gtmioBuffLen; \
@@ -62,7 +76,7 @@ error_def(ERR_ZINTRECURSEIO);
for (;;) \
{ \
gtmioChunk = gtmioBuffLen VMS_ONLY(> VMS_MAX_TCP_IO_SIZE ? VMS_MAX_TCP_IO_SIZE : gtmioBuffLen); \
- SEND(SDESC, gtmioBuff, gtmioChunk, SFLAGS, gtmioStatus); \
+ SEND((SOCKETPTR)->sd, gtmioBuff, gtmioChunk, SFLAGS, gtmioStatus); \
if ((ssize_t)-1 != gtmioStatus) \
{ \
gtmioBuffLen -= gtmioStatus; \
@@ -81,11 +95,280 @@ error_def(ERR_ZINTRECURSEIO);
RC = -1; /* Something kept us from sending what we wanted */ \
}
+#define DOTCPSEND(SOCKETPTR, SBUFF, SBUFF_LEN, SFLAGS, RC) \
+{ \
+ ssize_t localstatus; \
+ if (0 == (SOCKETPTR)->obuffer_size) \
+ DOTCPSEND_REAL(SOCKETPTR, SBUFF, SBUFF_LEN, SFLAGS, RC) \
+ else \
+ { \
+ localstatus = iosocket_write_buffered(SOCKETPTR, SBUFF, SBUFF_LEN); \
+ if (SBUFF_LEN == localstatus) \
+ RC = 0; \
+ else \
+ RC = -1; \
+ } \
+}
+
void iosocket_write(mstr *v)
{
iosocket_write_real(v, TRUE);
}
+void iosocket_buffer_error(socket_struct *socketptr)
+{ /* output error from obuffer_errno */
+ int errlen, devlen, save_obuffer_errno;
+ io_desc *iod;
+ d_socket_struct *dsocketptr;
+ const char *errptr;
+
+ if (0 == socketptr->obuffer_errno)
+ return; /* no error */
+ dsocketptr = socketptr->dev;
+ iod = dsocketptr->iod;
+# ifdef GTM_TLS
+ if (socketptr->tlsenabled)
+ {
+ iod->dollar.za = 9;
+ memcpy(iod->dollar.device, ONE_COMMA, SIZEOF(ONE_COMMA));
+ if (-1 == socketptr->obuffer_errno)
+ errptr = gtm_tls_get_error();
+ else
+ errptr = (char *)STRERROR(socketptr->obuffer_errno);
+ errlen = STRLEN(errptr);
+ devlen = MIN((SIZEOF(iod->dollar.device) - SIZEOF(ONE_COMMA)), errlen);
+ memcpy(&iod->dollar.device[SIZEOF(ONE_COMMA) - 1], errptr, devlen);
+ if (devlen < errlen)
+ iod->dollar.device[SIZEOF(iod->dollar.device) - 1] = '\0';
+ socketptr->obuffer_errno = 0;
+ if (socketptr->ioerror)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_TLSIOERROR, 2, LEN_AND_LIT("send"),
+ ERR_TEXT, 2, errlen, errptr);
+ } else
+# endif
+ {
+ save_obuffer_errno = socketptr->obuffer_errno;
+ socketptr->obuffer_errno = 0;
+ SOCKERROR(iod, socketptr, ERR_SOCKWRITE, save_obuffer_errno);
+ }
+}
+
+ssize_t iosocket_output(socket_struct *socketptr, char *buffer, size_t length, boolean_t resetbuffer, boolean_t timed);
+
+ssize_t iosocket_output(socket_struct *socketptr, char *buffer, size_t length, boolean_t resetbuffer, boolean_t timed)
+{
+ boolean_t pollwrite;
+ ssize_t status;
+ size_t llen;
+ int bytessent, istatus, timeout, save_errno;
+ char *lbuffer;
+# ifdef GTM_TLS
+ int tlspolldirection = 0;
+# endif
+# ifdef USE_POLL
+ struct pollfd fds;
+# else
+ fd_set fds, *readfds, *writefds;
+ struct timeval timeout_spec;
+# endif
+
+ if (!socketptr->obuffer_output_active)
+ return 0; /* how did we get here */
+ if (timed)
+ {
+ if (0 != socketptr->obuffer_errno)
+ return -1; /* unprocessed error */
+ timeout = 0; /* no waiting in poll */
+ } else
+ timeout = socketptr->obuffer_wait_time;
+# ifndef USE_POLL
+ FD_ZERO(&fds);
+ FD_SET(socketptr->sd, &fds);
+ timeout = timeout * 1000; /* convert milli to micro seconds */
+ timeout_spec.tv_sec = 0;
+ timeout_spec.tv_usec = timeout;
+# endif
+ llen = length;
+ lbuffer = buffer;
+ while (0 < llen)
+ { /* poll/select tlspolldirection - needed if noblocking */
+# ifdef GTM_TLS
+ if (socketptr->tlsenabled)
+ pollwrite = (tlspolldirection == GTMTLS_WANT_READ) ? FALSE : TRUE;
+ else
+# endif
+ pollwrite = TRUE;
+# ifdef USE_POLL
+ fds.fd = socketptr->sd;
+ fds.events = pollwrite ? POLLOUT : POLLIN;
+ istatus = poll(&fds, 1, timeout);
+# else
+ if (pollwrite)
+ {
+ writefds = &fds;
+ readfds = NULL;
+ } else
+ {
+ readfds = &fds;
+ writefds = NULL;
+ }
+ istatus = select(socketptr->sd + 1, readfds, writefds, NULL, &timeout_spec);
+# endif
+ if (-1 == istatus)
+ {
+ save_errno = errno;
+ if (timed)
+ { /* called from timer so only try once */
+ socketptr->obuffer_errno = save_errno;
+ status = -1;
+ break;
+ }
+ if (EAGAIN == save_errno)
+ rel_quant();
+ else if (EINTR != save_errno)
+ {
+ status = -1;
+ break;
+ }
+# ifndef USE_POLL
+ timeout_spec.tv_usec = timeout;
+ FD_SET(socketptr->sd, &fds);
+# endif
+ continue;
+ }
+# ifdef GTM_TLS
+ if (socketptr->tlsenabled)
+ {
+ bytessent = gtm_tls_send((gtm_tls_socket_t *)socketptr->tlssocket, lbuffer, llen);
+ if (0 < bytessent)
+ { /* unless partial writes enabled either none or all should have been written */
+ llen -= bytessent;
+ lbuffer += bytessent;
+ tlspolldirection = 0;
+ } else
+ {
+ switch (bytessent)
+ {
+ case GTMTLS_WANT_READ:
+ tlspolldirection = GTMTLS_WANT_READ;
+ break;
+ case GTMTLS_WANT_WRITE:
+ tlspolldirection = GTMTLS_WANT_WRITE;
+ break;
+ default:
+ assert(-1 == bytessent);
+ socketptr->obuffer_errno = gtm_tls_errno();
+ if (ECONNRESET == socketptr->obuffer_errno)
+ {
+ return (ssize_t)(-2);
+ } else
+ return (ssize_t)(-1);
+ }
+ }
+ if (0 == llen)
+ status = length;
+ else
+ status = 0;
+ } else
+# endif
+ {
+ DOTCPSEND_REAL(socketptr, buffer, length, 0, status);
+ if (0 != status)
+ { /* current callers do this check and return */
+ /* if timed, just return - maybe set flag in struct */
+ socketptr->obuffer_errno = status;
+ status = -1;
+ } else
+ status = length;
+ break;
+ }
+ }
+ if (status == length)
+ {
+ socketptr->obuffer_errno = 0;
+ if (resetbuffer)
+ socketptr->obuffer_length = socketptr->obuffer_offset = 0;
+ }
+ return status;
+}
+
+/* prototype in iosocketdef.h since called by iosocket_flush and iosocket_close */
+ssize_t iosocket_output_buffer(socket_struct *socketptr)
+{
+ ssize_t status;
+ status = iosocket_output(socketptr, socketptr->obuffer, socketptr->obuffer_length, TRUE, FALSE);
+ return status;
+}
+
+void iosocket_output_timed(socket_struct *socketptr);
+
+void iosocket_output_timed(socket_struct *socketptr)
+{
+ ssize_t status;
+ size_t length;
+
+ socketptr->obuffer_timer_set = FALSE;
+ if (!socketptr->obuffer_output_active && (0 < socketptr->obuffer_length))
+ { /* no current writer so output the buffer */
+ socketptr->obuffer_output_active = TRUE;
+ length = socketptr->obuffer_length;
+ status = iosocket_output(socketptr, socketptr->obuffer, length, TRUE, TRUE);
+ socketptr->obuffer_output_active = FALSE;
+ }
+ /* reschedule timer if needed */
+ if ((0 < socketptr->obuffer_length) && (0 == socketptr->obuffer_errno))
+ {
+ socketptr->obuffer_timer_set = TRUE;
+ start_timer((TID)socketptr, socketptr->obuffer_flush_time, iosocket_output_timed,
+ SIZEOF(socketptr), (char *)&socketptr);
+ }
+}
+
+ssize_t iosocket_write_buffered(socket_struct *socketptr, char *buffer, size_t length);
+ssize_t iosocket_write_buffered(socket_struct *socketptr, char *buffer, size_t length)
+{
+ ssize_t status, obuffered_len;
+ int errlen, devlen;
+ io_desc *iod;
+ d_socket_struct *dsocketptr;
+ const char *errptr;
+
+ socketptr->obuffer_output_active = TRUE; /* lock out timed writes */
+ status = (0 != socketptr->obuffer_errno) ? -1 : 0;
+ if ((0 == status ) && (0 < socketptr->obuffer_length) && ((socketptr->obuffer_size - socketptr->obuffer_length) <= length))
+ { /* more output than space left in buffer */
+ obuffered_len = socketptr->obuffer_length;
+ status = iosocket_output_buffer(socketptr);
+ if (obuffered_len == status)
+ status = 0; /* success */
+ }
+ if ((0 == status ) && (length > socketptr->obuffer_size))
+ { /* more output than can fit in buffer so just output it now */
+ status = iosocket_output(socketptr, buffer, length, FALSE, FALSE);
+ if (status == length)
+ status = 0; /* success */
+ } else if (0 == status)
+ { /* put in buffer since room is available */
+ memcpy((void *)(socketptr->obuffer + socketptr->obuffer_offset), buffer, length);
+ socketptr->obuffer_offset += length;
+ socketptr->obuffer_length += length;
+ status = length;
+ /* start timer if not active */
+ if (!socketptr->obuffer_timer_set)
+ {
+ socketptr->obuffer_timer_set = TRUE;
+ start_timer((TID)socketptr, socketptr->obuffer_flush_time, iosocket_output_timed,
+ SIZEOF(socketptr), (char *)&socketptr);
+ }
+ }
+ socketptr->obuffer_output_active = FALSE;
+ if (0 > status)
+ { /* report error */
+ iosocket_buffer_error(socketptr);
+ }
+ return status;
+}
+
void iosocket_write_real(mstr *v, boolean_t convert_output)
{
io_desc *iod;
@@ -136,7 +419,7 @@ void iosocket_write_real(mstr *v, boolean_t convert_output)
iod->ochset = CHSET_UTF16BE; /* per Unicode standard, assume big endian when endian
format is unspecified */
get_chset_desc(&chset_names[iod->ochset]);
- DOTCPSEND(socketptr->sd, UTF16BE_BOM, UTF16BE_BOM_LEN, flags, status);
+ DOTCPSEND(socketptr, UTF16BE_BOM, UTF16BE_BOM_LEN, flags, status);
DBGSOCK2((stdout, "socwrite: TCP send of BOM-BE with rc %d\n", status));
if (0 != status)
{
@@ -229,7 +512,7 @@ void iosocket_write_real(mstr *v, boolean_t convert_output)
* there will be recursion iosocket_Write -> iosocket_Wteol ->iosocket_Write */
if (0 < socketptr->n_delimiter)
{
- DOTCPSEND(socketptr->sd, socketptr->odelimiter0.addr, socketptr->odelimiter0.len,
+ DOTCPSEND(socketptr, socketptr->odelimiter0.addr, socketptr->odelimiter0.len,
(socketptr->urgent ? MSG_OOB : 0) | flags, status);
DBGSOCK2((stdout, "socwrite: TCP send of %d byte delimiter with rc %d\n",
socketptr->odelimiter0.len, status));
@@ -271,7 +554,7 @@ void iosocket_write_real(mstr *v, boolean_t convert_output)
}
}
assert(0 != b_len);
- DOTCPSEND(socketptr->sd, out, b_len, (socketptr->urgent ? MSG_OOB : 0) | flags, status);
+ DOTCPSEND(socketptr, out, b_len, (socketptr->urgent ? MSG_OOB : 0) | flags, status);
DBGSOCK2((stdout, "socwrite: TCP data send of %d bytes with rc %d\n", b_len, status));
if (0 != status)
{
diff --git a/sr_port/iosocketdef.h b/sr_port/iosocketdef.h
index 90ec294..4983414 100644
--- a/sr_port/iosocketdef.h
+++ b/sr_port/iosocketdef.h
@@ -90,6 +90,8 @@ typedef struct
#define INITIAL_MOREREAD_TIMEOUT 200
#define DEFAULT_MOREREAD_TIMEOUT 10
#define MAX_MOREREAD_TIMEOUT 999
+/* For buffered output, wait this long for socket to be ready to output */
+#define DEFAULT_WRITE_WAIT 200
#define ONE_COMMA "1,"
@@ -327,7 +329,7 @@ typedef struct socket_struct_type
size_t buffer_size; /* size of the buffer for this socket */
size_t buffered_length; /* length of stuff buffered for this socket */
size_t buffered_offset; /* offset of the buffered stuff to buffer head */
- char *buffer; /* pointer to the the buffer of this socket */
+ char *buffer; /* pointer to the buffer of this socket */
boolean_t nodelay;
boolean_t first_read;
boolean_t first_write;
@@ -345,6 +347,23 @@ typedef struct socket_struct_type
boolean_t pendingevent; /* if listening, needs accept */
enum socket_creator howcreated;
char *parenthandle; /* listening socket this created from */
+ size_t obuffer_size; /* size of the output buffer for this socket */
+ size_t obuffer_length; /* length of output in this buffer */
+ size_t obuffer_offset; /* offset of the buffered output to buffer head */
+ volatile boolean_t obuffer_timer_set; /* timer scheduled to flush buffer */
+ volatile boolean_t obuffer_output_active; /* in buffer output now */
+ int obuffer_flush_time; /* flush output buffer after this many milliseconds */
+ int obuffer_wait_time; /* wait for output ready this many milliseconds */
+ int obuffer_errno; /* save status from timed output attempt */
+ char *obuffer; /* pointer to the output buffer of this socket */
+ boolean_t nonblocking; /* socket has been set O_NONBLOCK */
+#ifdef GTM_TLS
+ boolean_t tlsenabled;
+ void *tlssocket; /* actually gtm_tls_socket_t */
+ boolean_t tlsreadblocked;
+ boolean_t tlswriteblocked;
+ short tlspolldirection; /* what TLS wants */
+#endif
} socket_struct;
typedef struct socket_interrupt_type
@@ -389,4 +408,9 @@ void iosocket_readfl_badchar(mval *vmvalptr, int datalen, int delimlen, unsigned
boolean_t iosocket_listen_sock(socket_struct *socketptr, unsigned short len);
void iosocket_close_one(d_socket_struct *dsocketptr, int index);
int iosocket_accept(d_socket_struct *dsocketptr, socket_struct *socketptr, boolean_t selectfirst);
+ssize_t iosocket_output_buffer(socket_struct *socketptr);
+void iosocket_buffer_error(socket_struct *socketptr);
+#ifdef GTM_TLS
+void iosocket_tls(mval *optionmval, int4 timeoutarg, mval *tlsid, mval *password, mval *extraarg);
+#endif
#endif
diff --git a/sr_port/jnl.h b/sr_port/jnl.h
index 3334020..200656e 100644
--- a/sr_port/jnl.h
+++ b/sr_port/jnl.h
@@ -54,8 +54,8 @@ error_def(ERR_JNLENDIANLITTLE);
* which needs to change to say IF_curTO17 if the earliest supported version changes to V17 or so).
*
*/
-#define JNL_LABEL_TEXT "GDSJNL24" /* see above comment paragraph for todos whenever this is changed */
-#define JNL_VER_THIS 24
+#define JNL_LABEL_TEXT "GDSJNL25" /* see above comment paragraph for todos whenever this is changed */
+#define JNL_VER_THIS 25
#define JNL_VER_EARLIEST_REPL 17 /* Replication filter support starts here GDSJNL17 = GT.M V5.1-000.
* (even though it should be V5.0-000, since that is pre-multisite,
* the replication connection with V55000 will error out at handshake
@@ -67,11 +67,11 @@ error_def(ERR_JNLENDIANLITTLE);
*/
#define JRT_MAX_V19 JRT_UZTWORM /* Max jnlrec type in GDSJNL19/GDSJNL20 that can be input to replication filter */
#define JRT_MAX_V21 JRT_UZTRIG /* Max jnlrec type in GDSJNL21 that can be input to replication filter */
-#define JRT_MAX_V23 JRT_UZTRIG /* Max jnlrec type in GDSJNL22/GDSJNL23 that can be input to replication filter.
+#define JRT_MAX_V22 JRT_UZTRIG /* Max jnlrec type in GDSJNL22/GDSJNL23 that can be input to replication filter.
* Actually JRT_HISTREC is a higher record type than JRT_UZTRIG but it is only
* sent through the replication pipe and never seen by filter routines.
*/
-#define JRT_MAX_V24 JRT_ULGTRIG /* Max jnlrec type in GDSJNL22/GDSJNL23 that can be input to replication filter */
+#define JRT_MAX_V24 JRT_ULGTRIG /* Max jnlrec type in GDSJNL24/GDSJNL25 that can be input to replication filter */
#ifdef UNIX
# define JNL_ALLOC_DEF 2048
@@ -297,40 +297,30 @@ error_def(ERR_JNLENDIANLITTLE);
#define CHECK_JNL_FILE_IS_USABLE(JFH, STATUS, DO_GTMPUTMSG, JNL_FN_LEN, JNL_FN) \
{ \
- boolean_t check_failed = FALSE; \
- uint4 lcl_status; \
- \
assert(JNL_HDR_ENDIAN_OFFSET == OFFSETOF(jnl_file_header, is_little_endian)); \
if (0 != MEMCMP_LIT((JFH)->label, JNL_LABEL_TEXT)) \
{ \
- lcl_status = ERR_JNLBADLABEL; \
- check_failed = TRUE; \
+ STATUS = ERR_JNLBADLABEL; \
+ if (DO_GTMPUTMSG) \
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) STATUS, 6, JNL_FN_LEN, JNL_FN, \
+ LEN_AND_LIT(JNL_LABEL_TEXT), SIZEOF((JFH)->label), (JFH)->label); \
} \
BIGENDIAN_ONLY( \
else if ((JFH)->is_little_endian) \
{ \
- lcl_status = ERR_JNLENDIANLITTLE; \
- check_failed = TRUE; \
+ STATUS = ERR_JNLENDIANLITTLE; \
+ if (DO_GTMPUTMSG) \
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) STATUS, 2, JNL_FN_LEN, JNL_FN); \
} \
) \
LITTLEENDIAN_ONLY( \
else if (!(JFH)->is_little_endian) \
{ \
- lcl_status = ERR_JNLENDIANBIG; \
- check_failed = TRUE; \
- } \
- ) \
- /* Currently, we can do one gtm_putmsg for any of the above 3 error messages \
- * because all of them have a fao count of 2 and expect jnl_fn_len and jnl_fn \
- * as arguments. If a new error gets added and has a different fao format, \
- * then the below gtm_putmsg has to be done differently based on that error. \
- */ \
- if (check_failed) \
- { \
- STATUS = lcl_status; \
+ STATUS = ERR_JNLENDIANBIG; \
if (DO_GTMPUTMSG) \
- gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) lcl_status, 2, JNL_FN_LEN, JNL_FN); \
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) STATUS, 2, JNL_FN_LEN, JNL_FN); \
} \
+ ) \
}
/* Token generation used in non-replicated journaled environment. Note the assumption here
diff --git a/sr_port/jnl_file_open_common.c b/sr_port/jnl_file_open_common.c
index 2dbcae2..56e9c05 100644
--- a/sr_port/jnl_file_open_common.c
+++ b/sr_port/jnl_file_open_common.c
@@ -239,7 +239,8 @@ uint4 jnl_file_open_common(gd_region *reg, off_jnl_t os_file_size)
jb->before_images = header->before_images;
jb->epoch_tn = eof_record.prefix.tn;
csd->jnl_checksum = header->checksum;
- LOG2_OF_INTEGER(header->alignsize, jb->log2_of_alignsize);
+ assert(4 == SIZEOF(header->alignsize)); /* so we can use the 32bit version of ceil_log2 */
+ jb->log2_of_alignsize = ceil_log2_32bit(header->alignsize);
assert(header->autoswitchlimit == csd->autoswitchlimit);
assert(header->jnl_alq == csd->jnl_alq);
assert(header->jnl_deq == csd->jnl_deq);
diff --git a/sr_port/jnl_file_open_switch.c b/sr_port/jnl_file_open_switch.c
index f3d644d..8cff125 100644
--- a/sr_port/jnl_file_open_switch.c
+++ b/sr_port/jnl_file_open_switch.c
@@ -40,14 +40,19 @@ uint4 jnl_file_open_switch(gd_region *reg, uint4 sts)
jnl_create_info create;
char prev_jnl_fn[JNL_NAME_SIZE];
int status;
+# if defined(GTM_TRIGGER) && defined(DEBUG)
+ DCL_THREADGBL_ACCESS;
+ SETUP_THREADGBL_ACCESS;
+# endif
csa = &FILE_INFO(reg)->s_addrs;
jpc = csa->jnl;
-
- assert((ERR_JNLFILOPN != sts) && (NOJNL != jpc->channel) || (ERR_JNLFILOPN == sts) && (NOJNL == jpc->channel));
+ assert(sts GTMTRIG_ONLY(|| TREF(in_trigger_upgrade)));
+ assert(!sts || ((ERR_JNLFILOPN != sts) && (NOJNL != jpc->channel)) || ((ERR_JNLFILOPN == sts) && (NOJNL == jpc->channel)));
if (NOJNL != jpc->channel)
JNL_FD_CLOSE(jpc->channel, status); /* sets jpc->channel to NOJNL */
- jnl_send_oper(jpc, sts);
+ if (sts)
+ jnl_send_oper(jpc, sts);
/* attempt to create a new journal file */
memset(&create, 0, SIZEOF(create));
create.status = create.status2 = SS_NORMAL;
diff --git a/sr_port/jnl_write.c b/sr_port/jnl_write.c
index a35515d..673b1d2 100644
--- a/sr_port/jnl_write.c
+++ b/sr_port/jnl_write.c
@@ -50,6 +50,7 @@ GBLREF jnlpool_ctl_ptr_t jnlpool_ctl;
GBLREF jnl_gbls_t jgbl;
GBLREF boolean_t is_src_server;
GBLREF boolean_t in_jnl_file_autoswitch;
+GBLREF boolean_t is_replicator;
#ifdef DEBUG
STATICDEF int jnl_write_recursion_depth;
@@ -520,7 +521,7 @@ void jnl_write(jnl_private_control *jpc, enum jnl_record_type rectype, jnl_recor
jpc->new_freeaddr = lcl_freeaddr + rlen;
INCR_GVSTATS_COUNTER(csa, cnl, n_jbuff_bytes, rlen);
assert(lcl_free == jpc->new_freeaddr % lcl_size);
- if (REPL_ENABLED(csa) && is_replicated)
+ if (REPL_ENABLED(csa) && is_replicated && is_replicator)
{ /* If the database is encrypted, then at this point jfb->buff will contain encrypted
* data which we don't want to to push into the jnlpool. Instead, we make use of the
* alternate alt_buff which is guaranteed to contain the original unencrypted data.
diff --git a/sr_port/jnl_write_poolonly.c b/sr_port/jnl_write_poolonly.c
index 9a398f0..ee6601b 100644
--- a/sr_port/jnl_write_poolonly.c
+++ b/sr_port/jnl_write_poolonly.c
@@ -43,6 +43,7 @@ GBLREF sm_uc_ptr_t jnldata_base;
GBLREF jnlpool_addrs jnlpool;
GBLREF jnlpool_ctl_ptr_t jnlpool_ctl;
GBLREF jnl_gbls_t jgbl;
+GBLREF boolean_t is_replicator;
error_def(ERR_JNLWRTDEFER);
error_def(ERR_JNLWRTNOWWRTR);
@@ -71,6 +72,8 @@ void jnl_write_poolonly(jnl_private_control *jpc, enum jnl_record_type rectype,
DEBUG_ONLY(uint4 lcl_dskaddr;)
uchar_ptr_t tmp_buff;
+ if (!is_replicator)
+ return;
assert(NULL != jnl_rec);
assert(rectype > JRT_BAD && rectype < JRT_RECTYPES && JRT_ALIGN != rectype);
assert(jrt_is_replicated[rectype]);
diff --git a/sr_port/job_addr.c b/sr_port/job_addr.c
index 1faf9d6..4e2c1b4 100644
--- a/sr_port/job_addr.c
+++ b/sr_port/job_addr.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -10,15 +10,22 @@
****************************************************************/
#include "mdef.h"
+
+#include "gtm_string.h"
+
#include "cmd_qlf.h"
#include <rtnhdr.h>
#include "op.h"
#include "job_addr.h"
#include "zbreak.h"
+GBLREF mident_fixed zlink_mname;
+
error_def(ERR_JOBLABOFF);
+error_def(ERR_ZLINKFILE);
+error_def(ERR_ZLMODULE);
-boolean_t job_addr(mstr *rtn, mstr *label, int4 offset, char **hdr, char **labaddr)
+boolean_t job_addr(mstr *rtn, mstr *label, int4 offset, char **hdr, char **labaddr, boolean_t *need_rtnobj_shm_free)
{
rhdtyp *rt_hdr;
int4 *lp;
@@ -31,8 +38,14 @@ boolean_t job_addr(mstr *rtn, mstr *label, int4 offset, char **hdr, char **labad
rt.mvtype = MV_STR;
rt.str = *rtn;
op_zlink(&rt, NULL);
- assertpro(NULL != (rt_hdr = find_rtn_hdr(rtn)));
- }
+ rt_hdr = find_rtn_hdr(rtn);
+ if (NULL == rt_hdr)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZLINKFILE, 2, rtn->len, rtn->addr,
+ ERR_ZLMODULE, 2, STRLEN(&zlink_mname.c[0]), &zlink_mname);
+ *need_rtnobj_shm_free = ARLINK_ONLY(rt_hdr->shared_object) NON_ARLINK_ONLY(FALSE);
+ *hdr = (char *)rt_hdr;
+ } else
+ *need_rtnobj_shm_free = FALSE;
lp = NULL;
if ((rt_hdr->compiler_qlf & CQ_LINE_ENTRY) || (0 == offset))
/* Label offset with routine compiled with NOLINE_ENTRY should cause error. */
@@ -40,7 +53,7 @@ boolean_t job_addr(mstr *rtn, mstr *label, int4 offset, char **hdr, char **labad
if (!lp)
return (FALSE);
/* Set the pointer to address / offset for line number entry storage in lab_proxy. */
- USHBIN_ONLY((TREF(lab_proxy)).lnr_adr = lp;)
+ USHBIN_ONLY((TREF(lab_proxy)).lnr_adr = lp);
/* On non-shared-binary, calculcate the offset to the corresponding lnr_tabent record by subtracting
* the base address (routine header) from line number entry's address, and save the result in
* lab_ln_ptr field of lab_tabent structure.
diff --git a/sr_port/job_addr.h b/sr_port/job_addr.h
index b07094f..06f8cc5 100644
--- a/sr_port/job_addr.h
+++ b/sr_port/job_addr.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -12,6 +12,6 @@
#ifndef __JOB_ADDR_H_
#define __JOB_ADDR_H_
-boolean_t job_addr(mstr *rtn, mstr *label, int4 offset, char **hdr, char **labaddr);
+boolean_t job_addr(mstr *rtn, mstr *label, int4 offset, char **hdr, char **labaddr, boolean_t *need_rtnobj_shm_free);
#endif
diff --git a/sr_port/jobparams.h b/sr_port/jobparams.h
index b15b406..e4e8b16 100644
--- a/sr_port/jobparams.h
+++ b/sr_port/jobparams.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -26,6 +26,7 @@
JPDEF (jp_nodetached, jpdt_nul),
JPDEF (jp_noswapping, jpdt_nul),
JPDEF (jp_output, jpdt_str),
+ JPDEF (jp_passcurlvn, jpdt_nul),
JPDEF (jp_priority, jpdt_num),
JPDEF (jp_process_name, jpdt_str),
JPDEF (jp_schedule, jpdt_str),
diff --git a/sr_port/jobparamstrs.h b/sr_port/jobparamstrs.h
index 43d9ba3..aff456d 100644
--- a/sr_port/jobparamstrs.h
+++ b/sr_port/jobparamstrs.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -25,6 +25,9 @@ JPSDEF ( 5, "NOACC", jp_noaccount), JPSDEF ( 8, "NOACCOUN*", jp_noaccount),
JPSDEF ( 5, "NODET", jp_nodetached), JPSDEF ( 8, "NODETACH*", jp_nodetached),
JPSDEF ( 5, "NOSWA", jp_noswapping), JPSDEF ( 8, "NOSWAPPI*", jp_noswapping),
JPSDEF ( 3, "OUT", jp_output), JPSDEF ( 6, "OUTPUT", jp_output),
+#ifdef UNIX
+JPSDEF ( 4, "PASS", jp_passcurlvn), JPSDEF ( 10, "PASSCURLVN", jp_passcurlvn),
+#endif
JPSDEF ( 3, "PRI", jp_priority), JPSDEF ( 8, "PRIORITY", jp_priority),
JPSDEF ( 3, "PRO", jp_process_name), JPSDEF ( 7, "PROCESS*", jp_process_name),
JPSDEF ( 3, "SCH", jp_schedule), JPSDEF ( 8, "SCHEDULE", jp_schedule),
diff --git a/sr_port/lke.hlp b/sr_port/lke.hlp
index c110308..bcc0f91 100644
--- a/sr_port/lke.hlp
+++ b/sr_port/lke.hlp
@@ -557,15 +557,16 @@
Copyright 2014
- Fidelity Information Services, Inc. All rights reserved.
+ Fidelity National Information Services, Inc. and/or its subsidiaries. All
+ rights reserved.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or any
later version published by the Free Software Foundation; with no Invariant
Sections, no Front-Cover Texts and no Back-Cover Texts.
- GT.M(TM) is a trademark of Fidelity Information Services, Inc. Other
- trademarks are the property of their respective owners.
+ GT.M(TM) is a trademark of Fidelity National Information Services, Inc.
+ Other trademarks are the property of their respective owners.
This document contains a description of GT.M and the operating
instructions pertaining to the various functions that comprise the system.
@@ -576,7 +577,7 @@
**Note**
- This help file is a concise representation of revision V6.2-000 of the
+ This help file is a concise representation of revision V6.2-001 of the
UNIX Administration and Operations Guide. To obtain a copy of the current
revision, go to www.fis-gtm.com and then click on the User Documentation
tab.
diff --git a/sr_port/lvzwr_init.c b/sr_port/lvzwr_init.c
index 11e4012..cfffe56 100644
--- a/sr_port/lvzwr_init.c
+++ b/sr_port/lvzwr_init.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -33,7 +33,9 @@ GBLREF uint4 zwrtacindx;
void lvzwr_init(enum zwr_init_types zwrpattyp, mval *val)
{
lvzwrite_datablk *prevzwrb;
+ DCL_THREADGBL_ACCESS;
+ SETUP_THREADGBL_ACCESS;
/* Standard call at start of zwrite type functions. If this symval has aliases in it,
* prep a hash table we will use to track the lv_val addrs we process (but only if not merging).
*/
@@ -68,5 +70,6 @@ void lvzwr_init(enum zwr_init_types zwrpattyp, mval *val)
if (!lvzwrite_block->sub)
lvzwrite_block->sub = (zwr_sub_lst *)malloc(SIZEOF(zwr_sub_lst) * MAX_LVSUBSCRIPTS);
lvzwrite_block->fixed = TRUE;
+ TREF(in_zwrite) = TRUE;
return;
}
diff --git a/sr_port/lvzwr_var.c b/sr_port/lvzwr_var.c
index e5e7e60..0307272 100644
--- a/sr_port/lvzwr_var.c
+++ b/sr_port/lvzwr_var.c
@@ -34,6 +34,7 @@
#include "gtm_string.h"
#include "alias.h"
#include "promodemo.h" /* for "demote" prototype used in LV_NODE_GET_KEY */
+#include "jobsp.h"
#define eb_less(u, v) (numcmp(u, v) < 0)
@@ -120,6 +121,15 @@
lvzwr_var((lv_val *)NODE, n + 1); \
}
+#ifdef UNIX
+/* job command needs to send the local variables to the child */
+#define MIDCHILD_SEND_VAR \
+{ \
+ if (TREF(midchild_send_locals)) \
+ ojmidchild_send_var(); \
+}
+#endif
+
GBLREF lvzwrite_datablk *lvzwrite_block;
GBLREF int4 outofband;
GBLREF zshow_out *zwr_output;
@@ -178,11 +188,11 @@ void lvzwr_var(lv_val *lv, int4 n)
return;
if (outofband)
{
- assert(TREF(in_zwrite));
- TREF(in_zwrite) = FALSE;
+ assert(TREF(in_zwrite)); /* in_zwrite indicates we are properly set up for a zwrite and should be cleared */
+ TREF(in_zwrite) = FALSE; /* here along with the below 2 because outofband_action may not return */
lvzwrite_block->curr_subsc = lvzwrite_block->subsc_count = 0;
outofband_action(FALSE);
- TREF(in_zwrite) = TRUE;
+ TREF(in_zwrite) = TRUE; /* in case we come back because the outofband_action turns out to be info */
}
lvzwrite_block->curr_subsc = n;
zwr_sub = (zwr_sub_lst *)lvzwrite_block->sub;
@@ -216,6 +226,7 @@ void lvzwr_var(lv_val *lv, int4 n)
if (zav->value_printed)
{
lvzwr_out(lv);
+ UNIX_ONLY(MIDCHILD_SEND_VAR);
lvzwrite_block->curr_subsc = lvzwrite_block->subsc_count = 0;
return;
} else
@@ -230,6 +241,7 @@ void lvzwr_var(lv_val *lv, int4 n)
|| ((0 != n) && !(lvzwrite_block->mask >> n))))
{ /* Print value for *this* node */
lvzwr_out(lv);
+ UNIX_ONLY(MIDCHILD_SEND_VAR);
}
if (verify_hash_add && !lvzwrite_block->zav_added)
{ /* lvzwr_out processing didn't add a zav for this var. Take care of that now so we
diff --git a/sr_port/m_do.c b/sr_port/m_do.c
index 57d17ac..8208956 100644
--- a/sr_port/m_do.c
+++ b/sr_port/m_do.c
@@ -70,7 +70,7 @@ int m_do(void)
assert(TRIP_REF == calltrip->operand[1].oprclass);
if (OC_CDLIT == calltrip->operand[1].oprval.tref->opcode)
assert(CDLT_REF == calltrip->operand[1].oprval.tref->operand[0].oprclass);
- else USHBIN_ONLY(if (OC_LAB_EXT != calltrip->operand[1].oprval.tref->opcode))
+ else ARLINK_ONLY(if (OC_LAB_EXT != calltrip->operand[1].oprval.tref->opcode))
{
assert(OC_LABADDR == calltrip->operand[1].oprval.tref->opcode);
assert(TRIP_REF == calltrip->operand[1].oprval.tref->operand[1].oprclass);
diff --git a/sr_port/m_zstep.c b/sr_port/m_zstep.c
index 9515a53..1215c89 100644
--- a/sr_port/m_zstep.c
+++ b/sr_port/m_zstep.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -20,7 +20,7 @@
#include "cmd.h"
#include "namelook.h"
-GBLREF short int source_column;
+GBLREF int source_column;
error_def(ERR_INVZSTEP);
error_def(ERR_ZSTEPARG);
diff --git a/sr_port/m_zwrite.c b/sr_port/m_zwrite.c
index 387fc47..cf8def9 100644
--- a/sr_port/m_zwrite.c
+++ b/sr_port/m_zwrite.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -30,7 +30,7 @@
#include "mvalconv.h"
#include "namelook.h"
-GBLREF short int source_column;
+GBLREF int source_column;
GBLREF uint4 pat_everything[];
GBLREF mstr_len_t sizeof_pat_everything;
diff --git a/sr_port/maketriple.c b/sr_port/maketriple.c
index 9d4378a..c30ac66 100644
--- a/sr_port/maketriple.c
+++ b/sr_port/maketriple.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -14,7 +14,8 @@
#include "mdq.h"
#include "mmemory.h"
-GBLREF short int source_line,source_column;
+GBLREF short int source_line;
+GBLREF int source_column;
triple *maketriple(opctype op)
{
diff --git a/sr_port/md5_digest2hex.c b/sr_port/md5_digest2hex.c
deleted file mode 100644
index 40c8939..0000000
--- a/sr_port/md5_digest2hex.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/****************************************************************
- * *
- * Copyright 2014 Fidelity Information Services, Inc *
- * *
- * This source code contains the intellectual property *
- * of its copyright holder(s), and is made available *
- * under a license. If you do not know the terms of *
- * the license, please stop and do not read further. *
- * *
- ****************************************************************/
-
-#include "mdef.h"
-
-#include "copy.h"
-#include "eintr_wrappers.h"
-#include "gtm_string.h"
-#include "io.h"
-#include "gtmio.h"
-
-#include "md5hash.h"
-#include "md5_digest2hex.h"
-
-/*
- * Construct printable 32-character MD5 checksum string from raw 128-bit digest array.
- */
-void md5_digest2hex(char hexstr[MD5_HEXSTR_LENGTH], const unsigned char digest[MD5_DIGEST_LENGTH])
-{
- int i, tlen;
- char *bptr;
-
- bptr = (char *)&hexstr[0];
- /* TODO - improve efficiency to avoid syscall using i2hexl() */
- for (i = 0; i < MD5_DIGEST_LENGTH; i++)
- {
- tlen = SPRINTF(bptr, "%02x", digest[i]);
- assert(2 == tlen);
- bptr += tlen;
- }
- assert('\0' == hexstr[MD5_HEXSTR_LENGTH - 1]);
-}
diff --git a/sr_port/mdef.h b/sr_port/mdef.h
index bb3946a..7526145 100644
--- a/sr_port/mdef.h
+++ b/sr_port/mdef.h
@@ -83,6 +83,10 @@ typedef unsigned int uint4; /* 4-byte unsigned integer */
*/
#define SHMDT(X) shmdt((void *)(X))
+/* Because shmget and semget returns -1 to indicate error, -1 can never be a valid shmid or semid */
+#define INVALID_SEMID -1
+#define INVALID_SHMID -1L
+
/* constant needed for FIFO - OS390 redefines in mdefsp.h */
#define FIFO_PERMISSION 010666 /* fifo with RW permissions for owner, group, other */
@@ -112,20 +116,31 @@ error_def(ERR_ASSERT);
# define lvaddr "%08lx"
#endif
+/* Need to set a flag to 0 or 1 depending on whether AUTORELINK_SUPPORTED is set or not. This is needed by gtmpcat so it can
+ * tell if autorelink is supported on the platform or not. While this could be done by always setting AUTORELINK_SUPPORTED
+ * which a value of 0 or 1, that's not how the code that uses it is structured so create this new variable with a value
+ * depending on whether AUTORELINK_SUPPORTED is defined or not.
+ */
+#ifdef AUTORELINK_SUPPORTED
+# define ARLINK_ENABLED 1
+#else
+# define ARLINK_ENABLED 0
+#endif
+
/* Define GT.M interlude functions for open, close, pipe, creat and dup system calls. This lets GT.M trace through all file
- * descriptor activity (needed for D9I11-002714). Do this on all Unix platforms. Note that only the macro GTM_FD_TRACE is
+ * descriptor activity (needed for D9I11-002714). Do this on all UNIX platforms. Note that only the macro GTM_FD_TRACE is
* defined here. gtm_unistd.h and gtm_fcntl.h define the actual GT.M interlude functions based on this macro.
*/
-#if defined(UNIX)
+#if defined(UNIX) && ! defined(STATIC_ANALYSIS)
# define GTM_FD_TRACE
# define GTM_FD_TRACE_ONLY(X) X
#else
# define GTM_FD_TRACE_ONLY(X)
#endif
-/* Define what is an invalid file descriptor in Unix and VMS. */
+/* Define what is an invalid file descriptor in UNIX and VMS. */
#if defined(UNIX)
-# define FD_INVALID -1 /* fd of -1 is invalid in Unix posix calls */
+# define FD_INVALID -1 /* fd of -1 is invalid in UNIX posix calls */
# define FD_INVALID_NONPOSIX FD_INVALID
#else
# define FD_INVALID -1 /* fd of -1 is invalid in VMS if using POSIX interface (open/close etc.) */
@@ -333,7 +348,7 @@ typedef struct
# define HAS_LITERAL_SECT
#endif
-typedef long ulimit_t; /* NOT int4; the Unix ulimit function returns a value of type long */
+typedef long ulimit_t; /* NOT int4; the UNIX ulimit function returns a value of type long */
/* Bit definitions for mval type (mvtype) */
#define MV_NM 1 /* 0x0001 */
@@ -455,6 +470,8 @@ mval *underr_strict(mval *start, ...);
#define MV_FORCE_BOOL(X) (MV_FORCE_NUM(X), (X)->m[1] ? TRUE : FALSE)
#define MV_FORCE_INT(M) (MV_FORCE_DEFINED(M), MV_FORCE_INTD(M))
#define MV_FORCE_INTD(M) (DBG_ASSERT(MV_DEFINED(M)) (M)->mvtype & MV_INT ? (M)->m[1]/MV_BIAS : mval2i(M))
+#define MV_FORCE_UINT(M) (MV_FORCE_DEFINED(M), MV_FORCE_UINTD(M))
+#define MV_FORCE_UINTD(M) (DBG_ASSERT(MV_DEFINED(M)) (M)->mvtype & MV_INT ? (M)->m[1]/MV_BIAS : mval2ui(M))
#define MV_FORCE_UMVAL(M,I) (((I) >= 1000000) ? i2usmval((M),(int)(I)) : \
(void)( (M)->mvtype = MV_NM | MV_INT , (M)->m[1] = (int)(I)*MV_BIAS ))
#define MV_FORCE_MVAL(M,I) (((I) >= 1000000 || (I) <= -1000000) ? i2mval((M),(int)(I)) : \
@@ -583,14 +600,6 @@ mval *underr_strict(mval *start, ...);
/* Length needed to pad out to a given power of 2 boundary */
#define PADLEN(value, bndry) (int)(ROUND_UP2((sm_long_t)(value), bndry) - (sm_long_t)(value))
-/* LOG2_OF_INTEGER returns the ceiling of log (base 2) of number */
-#define LOG2_OF_INTEGER(number, log2_of_number) \
-{ \
- int temp = (number) - 1; \
- for (log2_of_number = 0; 0 < temp; log2_of_number++) \
- temp = (temp) >> 1; \
-}
-
#define CALLFROM LEN_AND_LIT(__FILE__), __LINE__
void gtm_assert(int file_name_len, char file_name[], int line_no);
int gtm_assert2(int condlen, char *condtext, int file_name_len, char file_name[], int line_no);
@@ -672,7 +681,7 @@ int4 timeout2msec(int4 timeout);
/* If this is unix, we have a faster sleep for short sleeps ( < 1 second) than doing a hiber start.
* Take this chance to define UNIX_ONLY and VMS_ONLY macros.
*/
-int m_usleep(int useconds);
+void m_usleep(int useconds);
#ifdef UNIX
# define SHORT_SLEEP(x) {assert(1000 > (x)); m_usleep((x) * 1000);}
#else
@@ -723,10 +732,11 @@ int m_usleep(int useconds);
#endif
/* Note the macros below refer to the UNIX Shared Binary Support. Because the
- support is *specifically* for the Unix platform, "NON_USHBIN_ONLY()" will
- also be true for VMS even though that platform does have shared binary support
- (but it does not have Unix Shared Binary support). Use "NON_USHBIN_UNIX_ONLY()"
- for UNIX platforms that do not support Shared Binaries. */
+ * support is *specifically* for the UNIX platform, "NON_USHBIN_ONLY()" will
+ * also be true for VMS even though that platform does have shared binary support
+ * (but it does not have UNIX Shared Binary support). Use "NON_USHBIN_UNIX_ONLY()"
+ * for UNIX platforms that do not support Shared Binaries.
+ */
#ifdef USHBIN_SUPPORTED
# define USHBIN_ONLY(X) X
# define NON_USHBIN_ONLY(X)
@@ -740,10 +750,17 @@ int m_usleep(int useconds);
# define NON_USHBIN_UNIX_ONLY(X)
# endif
#endif
-
-/* Unicode. Although most (all?) Unix platforms currently support Unicode, that may
- not always be the case so a separate contingent is defined.
-*/
+/* Autorelink related macros */
+#ifdef AUTORELINK_SUPPORTED
+# define ARLINK_ONLY(X) X
+# define NON_ARLINK_ONLY(X)
+#else
+# define ARLINK_ONLY(X)
+# define NON_ARLINK_ONLY(X) X
+#endif
+/* Unicode. Although most (all?) UNIX platforms currently support Unicode, that may
+ * not always be the case so a separate contingent is defined.
+ */
#ifdef UNICODE_SUPPORTED
# define UNICODE_ONLY(X) X
# define NON_UNICODE_ONLY(X)
@@ -774,6 +791,9 @@ int m_usleep(int useconds);
typedef int64_t gtm_int64_t;
#endif
+int ceil_log2_32bit(uint4 num);
+int ceil_log2_64bit(gtm_uint64_t num);
+
typedef INTPTR_T sm_off_t;
/* HPPA latches (used by load_and_clear) must be 16 byte aligned.
@@ -1384,7 +1404,7 @@ qw_num gtm_byteswap_64(qw_num num64);
#define VARLSTCNT1(CNT) VARLSTCNT(CNT)
#define PUT_SYS_ERRNO(SYS_ERRNO) SYS_ERRNO
#elif defined(UNIX)
-#define DAYS 47117 /* adjust Unix returned days (seconds converted to days); Unix zero time 1970 */
+#define DAYS 47117 /* adjust UNIX returned days (seconds converted to days); UNIX zero time 1970 */
#define VARLSTCNT1(CNT) VARLSTCNT(CNT + 1)
#define PUT_SYS_ERRNO(SYS_ERRNO) 0, SYS_ERRNO
#else
@@ -1728,7 +1748,7 @@ typedef enum
# define GTM_SNAPSHOT_ONLY(X)
#endif
-/* Currently MUPIP REORG -TRUNCATE is only supported on Unix */
+/* Currently MUPIP REORG -TRUNCATE is only supported on UNIX */
#ifdef UNIX
# define GTM_TRUNCATE
# define NON_GTM_TRUNCATE_ONLY(X)
@@ -1738,7 +1758,7 @@ typedef enum
# define GTM_TRUNCATE_ONLY(X)
#endif
-/* Currently triggers are supported only on Unix */
+/* Currently triggers are supported only on UNIX */
#if defined(UNIX) && !defined(__hppa) /* triggers not supported on HPUX-HPPA */
# define GTM_TRIGGER
# define GTMTRIG_ONLY(X) X
diff --git a/sr_port/merrors.msg b/sr_port/merrors.msg
index 2139dd1..0679bda 100644
--- a/sr_port/merrors.msg
+++ b/sr_port/merrors.msg
@@ -492,7 +492,7 @@ EXTRACTFILERR <Error with extract file !AD>/error/fao=2!/ansi=0
FREEZE <Region: !AD is already frozen>/info/fao=2!/ansi=0
NOSELECT <None of the selected variables exist -- halting>/warning/fao=0!/ansi=0
EXTRFAIL <Extract failed for the global ^!AD. MUPIP INTEG should be run.>/error/fao=2!/ansi=0
-LDBINFMT <Corrupt binary format header information>/error/fao=0!/ansi=0
+LDBINFMT <Unrecognized header for load file>/error/fao=0!/ansi=0
NOPREVLINK <Journal file !AD has a null previous link>/error/fao=2!/ansi=0
CCEDUMPON <>/fatal/fao=0!/ansi=0
CCEDMPQUALREQ <A qualifier (DB,[NO]ON, or NOW) is required with the DUMP command>/error/fao=0!/ansi=0
@@ -575,7 +575,7 @@ RECCNT <Last LOAD record number: !UL>/info/fao=1!/ansi=0
TEXT <!AD>/info/fao=2!/ansi=0
ZWRSPONE <Subscript patterns in ZWRITE are atomic; Invalid delimiter>/error/fao=0!/ansi=0
FILEDEL <File !AD successfully deleted>/info/fao=2!/ansi=0
-JNLBADLABEL <Journal file !AD does not have a GT.M Journal File Label>/error/fao=2!/ansi=0
+JNLBADLABEL <Journal file !AD has a bad GT.M Journal File Label. Expected !AD. Found !AD.>/error/fao=6!/ansi=0
JNLREADEOF <End of journal file encountered for !AD>/error/fao=2!/ansi=0
JNLRECFMT <Journal file record format error encountered>/error/fao=0!/ansi=0
BLKTOODEEP <Block level too deep>/error/fao=0!/ansi=0
@@ -773,7 +773,7 @@ MEMORYRECURSIVE <Memory Subsystem called recursively>/fatal/fao=0!/ansi=0
FREEZEID <Cache !AD on !AD by freeze id 0x!XL with match 0x!XL from 0x!XJ>/info/fao=7!/ansi=0
BLKWRITERR <Unable to queue disk write for block 0x!XL. Will keep trying.>/info/fao=1!/ansi=0
STOPTIMEOUT <Waited too long for stopped process to release. Region: !AD.>/error/fao=2!/ansi=0
-TRIGMODINTP <Triggers for a given global cannot be both used and modified or removed in the same transaction>/error/fao=0!/ansi=0
+UNUSEDMSG776 <TRIGMODINTP last used in V6.2-000>/error/fao=0!/ansi=0
BCKUPBUFLUSH <Unable to flush buffer for online backup>/error/fao=0!/ansi=0
NOFORKCORE <Unable to fork off process to create core. Core creation postponed.>/warning/fao=0!/ansi=0
JNLREAD <Error reading from journal file !AD at offset [0x!XL]>/error/fao=3!/ansi=0
@@ -806,7 +806,7 @@ MUKILLIP <Kill in progress indicator is set for file !AD - this !AD operation is
JNLRDONLY <Journal file !AD read only>/error/fao=2!/ansi=0
ANCOMPTINC <Deviceparameter !AD is not compatible with any other deviceparameters in the !AD command>/error/fao=4!/ansi=0
ABNCOMPTINC <Deviceparameter !AD and deviceparameter !AD are not compatible in the !AD command>/error/fao=6!/ansi=0
-RECLOAD <Error loading record number: !UL!/>/error/fao=1!/ansi=0
+RECLOAD <Error loading record number: !@UQ!/>/error/fao=1!/ansi=0
SOCKNOTFND <Socket !AD not found>/error/fao=2!/ansi=0
CURRSOCKOFR <Current socket of index !UL is out of range. There are only !UL sockets.>/error/fao=2!/ansi=0
SOCKETEXIST <Socket !AD already exists>/error/fao=2!/ansi=79
@@ -895,7 +895,7 @@ SECONDAHEAD <Secondary ahead of primary. !/ Secondary database possibly updated
SCNDDBNOUPD <Database Updates not allowed on the secondary>/error/fao=0!/ansi=0
MUINFOUINT4 <!AD : !UL [0x!XL]>/info/fao=4!/ansi=0
NLMISMATCHCALC <Location of !AD expected at 0x!XL, but found at 0x!XL>/error/fao=4!/ansi=0
-UNUSEDMSG898 <GTMSECSHRLOGSWH last used in V5.5-000>/error/fao=0!/ansi=0
+RELINKCTLFULL <Relinkctl file for directory !AD is full (maximum entries !UL)>/error/fao=3!/ansi=0
UNUSEDMSG899 <GTMSECSHRDEFLOG last used in V5.5-000>/info/fao=0!/ansi=0
DBBADNSUB <!AD Bad numeric subscript>/error/fao=2!/ansi=0
DBBADKYNM <!AD Bad key name>/error/fao=2!/ansi=0
@@ -1364,13 +1364,13 @@ TCOMMITDISALLOW <TROLLBACK required after an unhandled error in trigger context>
SSATTACHSHM <Error while attaching to shared memory identifier !UL>/error/fao=1!/ansi=0
TRIGDEFNOSYNC <Global ^!AD has triggers defined on the !AD instance but none on the !AD instance. Current journal sequence number is 0x!16 at XQ>/warning/fao=7!/ansi=0
TRESTMAX <TRESTART not allowed in a final TP retry more than once>/error/fao=0!/ansi=0
-UNUSEDMSG1367 <TPLOCKRESTMAX : Last used in V5.5-000>/error/fao=0!/ansi=0
+ZLINKBYPASS <ZLINK of !AD bypassed - Identical routine already linked>/info/fao=2!/ansi=0
GBLEXPECTED <Global variable reference expected in this context>/error/fao=0!/ansi=0
GVZTRIGFAIL <ZTRIGGER of a global variable failed. Failure code: !AD.>/error/fao=2!/ansi=0
MUUSERLBK <Abnormal shutdown of replication-enabled database !AD detected>/error/fao=2!/ansi=0
SETINSETTRIGONLY <ISV !AD can only be modified in a 'SET' type trigger>/error/fao=2!/ansi=0
DZTRIGINTRIG <$ZTRIGGER() is not allowed inside trigger context. Trigger name: !AD>/error/fao=2!/ansi=0
-SECNODZTRIGINTP <Sequence number 0x!16 at XQ contains $ZTRIGGER() updates made inside a transaction which the current replicating instance does not support. The replicating instance must be upgraded to at least V5.4-002 to support this type of transaction. Cannot continue>/error/fao=1!/ansi=0
+UNUSEDMSG1373 <SECNODZTRIGINTP : Last used in V6.2-000>/error/fao=0!/ansi=0
BOOLSIDEFFECT <Extrinsic ($$), External call ($&) or $INCREMENT() with potential side effects in Boolean expression>/warning/fao=0!/ansi=0
DBBADUPGRDSTATE <Correcting conflicting values for fields describing database version upgrade state in the file header for region !AD (!AD) - make fresh backups with new journal files immediately.>/warning/fao=4!/ansi=0
WRITEWAITPID <PID !UL waited !UL minute(s) for PID !UL to finish writing block 0x!XL in database file !AD>/error/fao=6!/ansi=0
@@ -1382,7 +1382,7 @@ GTMSECSHRCHDIRF <gtmsecshr unable to chdir to its temporary directory (!AD)>/err
JNLORDBFLU <Error flushing database blocks to !AD. See related messages in the operator log>/error/fao=2!/ansi=0
ZCCLNUPRTNMISNG <External call: Cleanup routine name missing. Cannot continue>/error/fao=0!/ansi=0
ZCINVALIDKEYWORD <External call: Invalid keyword found. Cannot continue>/error/fao=0!/ansi=0
-REPLNOMULTILINETRG <Sequence number 0x!16 at XQ contains a trigger definition too large for transmission to the current replicating instance, which does not support multi-line triggers - stopping replication>/error/fao=1!/ansi=0
+UNUSEDMSG1385 <REPLNOMULTILINETRG : Last used in V6.2-000>/error/fao=0!/ansi=0
DBSHMNAMEDIFF <Database file !AD points to shared memory (id = !UL) which points to a different database file !AZ>/error/fao=4!/ansi=0
SHMREMOVED <Removed Shared Memory id !UL corresponding to file !AD>/info/fao=3!/ansi=0
DEVICEWRITEONLY <Cannot read from a write-only device>/error/fao=0!/ansi=0
@@ -1402,7 +1402,7 @@ LOCKSPACEUSE <Estimated free lock space: !UL% of !UL pages>/info/fao=2!/ansi=0
JIUNHNDINT <An error during $ZINTERRUPT processing was not handled: !AD>/error/fao=2!/ansi=0
GTMASSERT2 <!AD - Assert failed !AD line !UL for expression (!AD)>/fatal/fao=7!/ansi=0
ZTRIGNOTRW <ZTRIGGER cannot operate on read-only region !AD>/error/fao=2!/ansi=0
-TRIGMODREGNOTRW <Trigger(s) cannot be added/changed/deleted because region !AD is read-only>/error/fao=2!/ansi=0
+TRIGMODREGNOTRW <Trigger(s) cannot be added/changed/deleted/upgraded because region !AD is read-only>/error/fao=2!/ansi=0
INSNOTJOINED <Replicating Instance !AD is not a member of the same Group as Instance !AD>/error/fao=4!/ansi=0
INSROLECHANGE <Supplementary Instance !AD and non-Supplementary Instance !AD belong to the same Group>/error/fao=4!/ansi=0
INSUNKNOWN <Supplementary Instance !AD has no instance definition for non-Supplementary Instance !AD>/error/fao=4!/ansi=0
@@ -1536,7 +1536,7 @@ GBLNOMAPTOREG <Global !AD does not map to region !AD in current global directory
ISSPANGBL <Operation cannot be performed on global ^!AD as it spans multiple regions in current global directory>/error/fao=2!/ansi=0
TPNOSUPPORT <Operation cannot be performed while inside of a TP transaction>/error/fao=0!/ansi=0
GVSUBSERR <Invalid subscripted global name specification in $VIEW() function>/error/fao=0!/ansi=0
-TRIGNOSPANGBL <Triggers cannot be installed/deleted for global name !AD as it spans multiple regions in current global directory>/error/fao=2!/ansi=0
+UNUSEDMSG1539 <TRIGNOSPANBL : Last used in V6.2-000>/error/fao=0!/ansi=0
FILTERTIMEDOUT <Replication server timed out attempting to read seqno !16 at XQ from external filter>/error/fao=1!/ansi=0
TLSDLLNOOPEN <Failed to load GT.M TLS/SSL library for secure communication>/error/fao=0!/ansi=0
TLSINIT <Failed to initialize GT.M TLS/SSL library for secure communication>/error/fao=0!/ansi=0
@@ -1573,6 +1573,21 @@ CRYPTBADWRTPOS <Encrypted WRITE disallowed from a position different than where
LABELNOTFND <GOTO referenced a label that does not exist>/error/fao=0!/ansi=13
RELINKCTLERR <Error with relink control structure for $ZROUTINES directory !AD>/error/fao=2!/ansi=0
INVLINKTMPDIR <Value for $gtm_linktmpdir is either not found or not a directory: !AD>/error/fao=2!/ansi=0
+NOEDITOR <Can't find an executable editor: !AD>/error/fao=2!/ansi=0
+UPDPROC <Update Process error>/error/fao=0!/ansi=0
+HLPPROC <Helper Process error>/error/fao=0!/ansi=0
+REPLNOHASHTREC <Sequence number 0x!16 at XQ contains trigger definition updates. !AD side must be at least V6.2-000 for replication to continue>/error/fao=3!/ansi=0
+REMOTEDBNOTRIG <Trigger operations on global !AD not supported as it maps to database region !AD that points to a remote file>/error/fao=4!/ansi=0
+NEEDTRIGUPGRD <Cannot do trigger operation on database file !AD until it is upgraded; Run MUPIP TRIGGER -UPGRADE first>/error/fao=2!/ansi=0
+REQRLNKCTLRNDWN <Error accessing relinkctl file for $ZROUTINES directory !AD. Must be rundown>/error/fao=2!/ansi=0
+RLNKCTLRNDWNSUC <Relinkctl file for $ZROUTINES directory !AD successfully rundown>/info/fao=2!/ansi=0
+RLNKCTLRNDWNFL <Relinkctl file for $ZROUTINES directory !AD failed to rundown as it is open by !UL process(es)>/error/fao=3!/ansi=0
+MPROFRUNDOWN <Error during M-profiling rundown>/error/fao=0!/ansi=0
+ZPEEKNOJNLINFO <$ZPEEK() unable to access requested journal structure - region !AD is not currently journaled>/error/fao=2!/ansi=0
+TLSPARAM <TLS parameter !AD !AD>/error/fao=4!/ansi=0
+RLNKRECLATCH <Failed to get latch on relinkctl record for routine name !AZ in $ZROUTINES directory !AD>/error/fao=3!/ansi=0
+RLNKSHMLATCH <Failed to get latch on relinkctl shared memory for $ZROUTINES directory !AD>/error/fao=2!/ansi=0
+JOBLVN2LONG <The zwrite representation of a local variable transferred to a JOB'd process can not exceed !UL. Encountered size: !UL>/error/fao=2!/ansi=0
!
! If there are UNUSEDMSG* lines unused for more than one year and at least two non-patch releases, use them before adding new lines.
!
diff --git a/sr_port/mtables.c b/sr_port/mtables.c
index 900769f..2e3de5c 100644
--- a/sr_port/mtables.c
+++ b/sr_port/mtables.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -197,7 +197,6 @@ LITDEF boolean_t mvs_save[] =
LITDEF mval skiparg = DEFINE_MVAL_COMMON(0, 0, 0, 0, 0, 0, 0, 0);
static readonly unsigned char localpool[7] = {'1', '1', '1', '0', '1', '0', '0'};
-LITDEF mval literal_null = DEFINE_MVAL_LITERAL(MV_STR | MV_NM | MV_INT | MV_NUM_APPROX | MV_UTF_LEN, 0, 0, 0, 0, 0, 0);
LITDEF mval literal_zero = DEFINE_MVAL_LITERAL(MV_STR | MV_NM | MV_INT, 0, 0, 1, (char *)&localpool[3], 0, 0);
LITDEF mval literal_one = DEFINE_MVAL_LITERAL(MV_STR | MV_NM | MV_INT, 0, 0, 1, (char *)&localpool[0], 0, 1 * MV_BIAS);
LITDEF mval literal_ten = DEFINE_MVAL_LITERAL(MV_STR | MV_NM | MV_INT, 0, 0, 2, (char *)&localpool[2], 0, 10 * MV_BIAS);
@@ -214,26 +213,22 @@ LITDEF mval literal_oneeleven = DEFINE_MVAL_LITERAL(MV_STR | MV_NM | MV_INT, 0,
* try to set the MV_NUM_APPROX bit and that could cause a SIG-11 since these mvals are in the read-only data segment.
* --------------------------------------------------------------------------------------------------------------------------
*/
-
+LITDEF mval literal_null = DEFINE_MVAL_LITERAL(MV_STR | MV_NM | MV_INT | MV_NUM_APPROX | MV_UTF_LEN, 0, 0, 0, 0, 0, 0);
/* Create mval to hold batch type TSTART. "BA" or "BATCH" mean the same.
* We define the shorter version here to try reduce the time taken for comparison.
*/
LITDEF mval literal_batch = DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, TP_BATCH_SHRT, (char *)TP_BATCH_ID, 0, 0);
#ifdef GTM_TRIGGER
-LITDEF mval literal_hasht = DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, HASHT_GBLNAME_LEN , (char *)HASHT_GBLNAME , 0, 0); /* BYPASSOK */
LITDEF mval literal_hashlabel = DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, LITERAL_HASHLABEL_LEN, (char *)LITERAL_HASHLABEL, 0, 0); /* BYPASSOK */
LITDEF mval literal_hashcycle = DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, LITERAL_HASHCYCLE_LEN, (char *)LITERAL_HASHCYCLE, 0, 0); /* BYPASSOK */
LITDEF mval literal_hashcount = DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, LITERAL_HASHCOUNT_LEN, (char *)LITERAL_HASHCOUNT, 0, 0); /* BYPASSOK */
-LITDEF mval literal_cmd = DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, LITERAL_CMD_LEN , (char *)LITERAL_CMD , 0, 0); /* BYPASSOK */
-LITDEF mval literal_gvsubs = DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, LITERAL_GVSUBS_LEN , (char *)LITERAL_GVSUBS , 0, 0); /* BYPASSOK */
-LITDEF mval literal_options = DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, LITERAL_OPTIONS_LEN , (char *)LITERAL_OPTIONS , 0, 0); /* BYPASSOK */
-LITDEF mval literal_delim = DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, LITERAL_DELIM_LEN , (char *)LITERAL_DELIM , 0, 0); /* BYPASSOK */
-LITDEF mval literal_zdelim = DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, LITERAL_ZDELIM_LEN , (char *)LITERAL_ZDELIM , 0, 0); /* BYPASSOK */
-LITDEF mval literal_pieces = DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, LITERAL_PIECES_LEN , (char *)LITERAL_PIECES , 0, 0); /* BYPASSOK */
-LITDEF mval literal_trigname = DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, LITERAL_TRIGNAME_LEN , (char *)LITERAL_TRIGNAME , 0, 0); /* BYPASSOK */
-LITDEF mval literal_xecute = DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, LITERAL_XECUTE_LEN , (char *)LITERAL_XECUTE , 0, 0); /* BYPASSOK */
-LITDEF mval literal_chset = DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, LITERAL_CHSET_LEN , (char *)LITERAL_CHSET , 0, 0); /* BYPASSOK */
+
+#define TRIGGER_SUBSDEF(SUBSTYPE, SUBSNAME, LITMVALNAME, TRIGFILEQUAL, PARTOFHASH) \
+ LITDEF mval LITMVALNAME = DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, STR_LIT_LEN(SUBSNAME), (char *)SUBSNAME, 0, 0);
+
+#include "trigger_subs_def.h" /* BYPASSOK */
+#undef TRIGGER_SUBSDEF
LITDEF mval gvtr_cmd_mval[GVTR_CMDTYPES] = {
/* Define GVTR_CMD_SET, GVTR_CMD_KILL etc. */
@@ -251,10 +246,10 @@ LITDEF int4 gvtr_cmd_mask[GVTR_CMDTYPES] = {
};
/* The initialization order of this array matches enum trig_subs_t defined in triggers.h */
-#define TRIGGER_SUBDEF(SUBNAME) LITERAL_##SUBNAME
LITDEF char *trigger_subs[] = {
-#include "trigger_subs_def.h"
-#undef TRIGGER_SUBDEF
+#define TRIGGER_SUBSDEF(SUBSTYPE, SUBSNAME, LITMVALNAME, TRIGFILEQUAL, PARTOFHASH) SUBSNAME,
+#include "trigger_subs_def.h" /* BYPASSOK */
+#undef TRIGGER_SUBSDEF
};
#endif
diff --git a/sr_port/mu_extr_ident.c b/sr_port/mu_extr_ident.c
index e89928b..b9455fc 100644
--- a/sr_port/mu_extr_ident.c
+++ b/sr_port/mu_extr_ident.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -20,8 +20,16 @@
#include "gtm_facility.h"
#include "fileinfo.h"
#include "gdsbt.h"
-#include "gdsfhead.h" /* above includes needed for muextr.h */
-#include "muextr.h" /* needed for "mu_extr_ident" prototype */
+#include "gdsfhead.h" /* above includes needed for muextr.h */
+#include "muextr.h" /* needed for "mu_extr_ident" prototype */
+
+#ifdef EXTRACT_HASHT_GLOBAL
+#include "gv_trigger_common.h" /* for IS_GVKEY_HASHT_GBLNAME macro */
+/* $gtm_dist/mupip extract -select="^#t" is implemented as an internal debugging feature and only supports
+ * dumping ^#t. Using it with other globals won't work unless the ^#t is the last selected global because the
+ * macro IS_GVKEY_HASHT_GBLNAME checks (KEY_DELIMITER == ADDR[HASHT_GBLNAME_LEN]) which is true only when ^#t is
+ * the last parameter */
+#endif
#define IDENT_FCHAR(x) (((x) >= 'A' && (x) <= 'Z') || ((x) >= 'a' && (x) <= 'z') || (x) == '%')
#define IDENT_TAIL(x) (((x) >= 'A' && (x) <= 'Z') || ((x) >= 'a' && (x) <= 'z') || ((x) >= '0' && (x) <= '9'))
@@ -32,6 +40,10 @@ char *mu_extr_ident(mstr *a)
b = a->addr;
c = b + a->len;
+# ifdef EXTRACT_HASHT_GLOBAL
+ if (IS_GVKEY_HASHT_GBLNAME(a->len, b))
+ return (b + a->len);
+# endif
if (IDENT_FCHAR(*b))
while (++b < c)
if (!IDENT_TAIL(*b))
diff --git a/sr_port/muextr.h b/sr_port/muextr.h
index a6efe99..5aed941 100644
--- a/sr_port/muextr.h
+++ b/sr_port/muextr.h
@@ -24,17 +24,14 @@ typedef struct glist_struct
#define DO_ROOT_SEARCH_FALSE FALSE
#define DO_ROOT_SEARCH_TRUE TRUE
-#define RECORDSTAT_REGION_LIT " (region "
-#define RECORDSTAT_REGION_LITLEN STR_LIT_LEN(RECORDSTAT_REGION_LIT)
-
#define PRINT_REG_FALSE FALSE
#define PRINT_REG_TRUE TRUE
#define ISSUE_RECORDSTAT_MSG(GL_PTR, GBLSTAT, PRINT_REG) \
{ \
- char gbl_name_buff[MAX_MIDENT_LEN + 2 + RECORDSTAT_REGION_LITLEN + MAX_RN_LEN + 1]; \
+ char gbl_name_buff[MAX_MIDENT_LEN + 2 + SPANREG_REGION_LITLEN + MAX_RN_LEN + 1]; \
/* 2 for null and '^', MAX_RN_LEN for region name, \
- * RECORDSTAT_REGION_LITLEN for " (region " and 1 for ")" */ \
+ * SPANREG_REGION_LITLEN for " (region " and 1 for ")" */ \
int gbl_buff_index; \
\
gbl_name_buff[0]='^'; \
@@ -42,8 +39,8 @@ typedef struct glist_struct
gbl_buff_index = 1 + GNAME(GL_PTR).len; \
if (PRINT_REG && (NULL != GL_PTR->gvnh_reg->gvspan)) \
{ \
- MEMCPY_LIT(&gbl_name_buff[gbl_buff_index], RECORDSTAT_REGION_LIT); \
- gbl_buff_index += RECORDSTAT_REGION_LITLEN; \
+ MEMCPY_LIT(&gbl_name_buff[gbl_buff_index], SPANREG_REGION_LIT); \
+ gbl_buff_index += SPANREG_REGION_LITLEN; \
memcpy(&gbl_name_buff[gbl_buff_index], gl_ptr->reg->rname, gl_ptr->reg->rname_len); \
gbl_buff_index += gl_ptr->reg->rname_len; \
gbl_name_buff[gbl_buff_index++] = ')'; \
@@ -99,6 +96,7 @@ typedef struct coll_hdr_struct
unsigned char pad;
} coll_hdr;
+#define MU_FMT_UNRECOG -1
#define MU_FMT_GO 0
#define MU_FMT_BINARY 1
#define MU_FMT_GOQ 2
diff --git a/sr_port/mumps.hlp b/sr_port/mumps.hlp
index 23aa203..be6319d 100644
--- a/sr_port/mumps.hlp
+++ b/sr_port/mumps.hlp
@@ -390,7 +390,6 @@
GTM>kill A,B
GTM>set A=1,*B=A ; B & A are aliases
-
GTM>write B
1
GTM>
@@ -490,7 +489,6 @@
A=1 ;*
*B=A
GTM>Kill *A ; Remove the association for A - it now has no association and no array
-
GTM>ZWRite ; B is a traditional local variable
B=1
Example:
@@ -510,12 +508,9 @@
A=2 ;*
*B=A
GTM>Kill A ; Kill the array
-
GTM>ZWRite ; There's no data to show - only the association
*B=A
-
GTM>Set B=3 ; Create a new value
-
GTM>ZWRite ; The association was unaffected by the Kill
A=3 ;*
*B=A
@@ -571,13 +566,9 @@
GTM>ZWRite ; Verify that it's there
A=1 ;*
*B=A
-
GTM>Kill (A) ; Kill everything except A
-
GTM>ZWRite ; Demonstrate that A also has no array
-
GTM>Set A=2 ; Create an array
-
GTM>ZWRite ; The association survived the Kill
A=2 ;*
*B=A
@@ -615,7 +606,6 @@
zwrite
tcommit ; No global updates in this transaction!
quit
-
------------
Initial values & association
A="Malvern"
@@ -677,7 +667,6 @@
write "Rollback doesnt restore names and local arrays",!
zwrite
quit
-
------------
Only containers before transaction:
$ZWRTAC=""
@@ -808,10 +797,10 @@
In UTF-8 mode, string processing functions (such as $EXTRACT()) operate on
strings of multi-byte characters, and can therefore produce different
- results in M and UTF-8 modes, depending on the actual data processed,
- Each function has a "Z" alter ego (for example, $ZEXTRACT()) that can be
- used to operate on sequences of bytes identically in M and UTF-8 modes
- (that is, in M mode, $EXTRACT() and $ZEXTRACT() behave identically).
+ results in M and UTF-8 modes, depending on the actual data processed. Each
+ function has a "Z" alter ego (for example, $ZEXTRACT()) that can be used
+ to operate on sequences of bytes identically in M and UTF-8 modes (that
+ is, in M mode, $EXTRACT() and $ZEXTRACT() behave identically).
In M mode, the concept of an illegal character does not exist. In UTF-8
mode, a sequence of bytes may not represent a valid character, and
@@ -1601,6 +1590,20 @@
By default, the compiler produces object modules.
+4 [no]w[arning]
+ [no]w[arning]
+
+ Instructs the compiler to suppress error output; the default is -warning.
+
+ When used with the -list qualifier, the -nowarning qualifier does not
+ affect errors in the listing.
+
+ **Note**
+
+ When used with the -noobject qualifier, the -nowarning qualifier instructs
+ the compiler to produce no object with no indication of the fact or the
+ cause.
+
4 r[un]
r[un]
@@ -1851,18 +1854,13 @@
GTM>write $zgbldir
/usr/lib/fis-gtm/V5.4-002B_x86/mumps.gld
GTM>set $zgbldir="test.gld"
-
GTM>set a=10
-
GTM>set b=a
-
GTM>recall
-
1 set b=a
2 set a=10
3 set $zgbldir="test.gld"
4 write $zgbldir
-
GTM>
This REC[ALL] command displays the previously entered commands.
@@ -3612,19 +3610,15 @@
Wrong again
%GTM-I-BREAK, Break instruction encountered
At M source location break+2^br
-
GTM>ZCONTINUE
Iteration 3 x=1
OK
%GTM-I-BREAK, Break instruction encountered
At M source location break+2^br
-
GTM>ZCONTINUE
%GTM-I-BREAK, Break instruction encountered
At M source location break+2^br
-
GTM>ZCONTINUE
-
GTM>
This uses a BREAK with both command and argument postconditionals. The
@@ -3690,10 +3684,8 @@
if $view("undef") set revert=1 view "noundef"
if z="" write "Missing parameter.",! view:revert "undef" quit
else write z*z,! view:revert "undef" quit
-
GTM>do ^SQR(10)
100
-
GTM>do ^SQR
Missing parameter.
@@ -3942,9 +3934,7 @@
Example:
GTM>Set X=1,Y=1,Z=2 Kill UNDEF
-
GTM>If X=1,Y=1,Z=3,UNDEF=0 Write "HI"
-
GTM>
The IF command causes GT.M to cease executing the line after it determines
@@ -4070,6 +4060,24 @@
using a file extension of .mjo and the current default directory of the
process created by the JOB command.
+4 PASSCURLVN
+ PASSCURLVN
+
+ When a JOB command specifies the PASSCURLVN jobparameter, the new process
+ inherits the current collation, all locals, aliases, and alias containers
+ from the JOB'ng process' current stack level. As a result of this, a
+ ZWRITE issued in the JOB'd process has the same output, except for any out
+ of scope aliases, as a ZWRITE in the context of the JOB command. If the
+ JOB command finds a ZWRITE representation of any lvn, consisting of a its
+ full name, its subscripts, corresponding value, quotes and the "=" sign,
+ exceeding 1MiB, it produces an JOBLVN2LONG error both in the JOB'ng
+ process and in the JOB'd processes error output stream. If a JOB command
+ does not specify PASSCURLVN, the JOB'd process(es) inherits no local
+ variables from the parent. While not an inexpensive command, you can use
+ the "exclusive" NEW command to control the context passed to the JOB'd
+ process; for example, adding "NEW (LOCALA, LOCALB)" before the JOB command
+ would pass only LOCALA and LOCALB.
+
4 STA[RTUP]="/path/to/shell/script"
STA[RTUP]="/path/to/shell/script"
@@ -4140,13 +4148,10 @@
Example:
kill *
-
write !,"gtm_stdxkill=",+$ztrnlnm("gtm_stdxkill"),!
-
set (A,B,C,E)="input"
do X(.A,.B)
zwrite
-
write !,"____________",!
set (A,B,C,E)="input"
do Y(.A,.B)
@@ -4170,12 +4175,10 @@
A="output"
B="output"
C="input"
-
____________
A="output"
B="output"
C="input"
-
____________
A="base" ;*
B="base" ;*
@@ -4222,19 +4225,12 @@
GTM>Set ^gbl1="one"
GTM>Set ^gbl1(1,1)="oneone"
-
GTM>Set ^gbl1(1,1,3)="oneonethree"
-
GTM>Set ^gbl1(1,2,4)="onetwofour"
-
GTM>Set ^gbl2(2)="gbl2_2"
-
GTM>Set ^gbl2(2,1,3)="gbl2_2_1_3"
-
GTM>Set ^gbl2(2,1,4,5)="gbl2_2_1_4_5"
-
GTM>Merge ^gbl1(1)=^gbl2(2)
-
GTM>WRITE $Reference
^gbl1(1)
GTM>ZWRite ^gbl1
@@ -4269,11 +4265,8 @@
GTM>Kill
GTM>Set ^gbl(1,2)="1,2"
-
GTM>Merge lcl(3,4)=^gbl(1)
-
GTM>Set ^("naked")=2
-
GTM>ZWRite ^gbl
^gbl(1,2)="1,2"
^gbl("naked")=2
@@ -4577,11 +4570,9 @@
GTM>Set x="I love hotdogs"
GTM>Set $Extract(x,3,6)="want"
-
GTM>Write x
I want hotdogs
GTM>Set $Extract(x,7)=" many "
-
GTM>Write x
I want many hotdogs
GTM>
@@ -4595,14 +4586,11 @@
GTM>kill A,B
GTM>set A=1,A(1)=1,A(2)=2
-
GTM>set *B=A ; A & B are aliases.
-
GTM>zwrite B
B=1 ;*
B(1)=1
B(2)=2
-
GTM>
This SET * command creates an alias associated between A and B. It
@@ -4614,13 +4602,10 @@
GTM>kill A,B,C
GTM>set A=1,*C(2)=A ; C(2) is a container
-
GTM>zwrite
A=1 ;*
*C(2)=A
-
GTM>set *B=C(2) ; B is now an alias
-
GTM>write B,":",$length(C(2)),":" ; An alias variable provides access but a container doesn't
1:0:
GTM>
@@ -4923,6 +4908,17 @@
performance and exists primarily as a tool for use by FIS. The default is
GDSCERT:0.
+4 GVSRESET
+ GVSRESET
+
+ Resets the process-specific fields that are part of the ZSHOW "G" result
+ and database file header fields holding records reported by: GVSTAT, BG
+ trace, buffer pool accounting and the TP block modification details. Note
+ a VIEW "GVSRESET" performed by a process with read-only database access
+ changes only the process-specific information and has no effect on the
+ database file header. DSE CHANGE -FILEHEADER -GVSTATSRESET clears the same
+ database file header fields as VIEW "GVRESET";
+
4 GVDUPSETNOOP
GVDUPSETNOOP
@@ -5103,6 +5099,31 @@
the "?" operator. These pattern definitions can be used in place of, or in
addition to, the standard C, N, U, L, and P.
+4 POOLLIMIT
+ POOLLIMIT
+
+ VIEW "POOLLIMIT":<region>:expr, where expr is of the form n[%] provides a
+ mechanism for a process that has the potential to "churn" global buffers
+ to limit the potential impact on other processes by restricting the number
+ of global buffers it uses. If the expression ends with a per-cent sign
+ (%), the number is taken as an as a percentage of the configured global
+ buffers and otherwise as an ordinal number of preferred buffers; standard
+ M parsing and integer conversions apply. Preferred buffer values are
+ limited to between 32 and one less than half the buffer pool inclusive;
+ with the exception of zero (0) or 100 per cent, which turn off the
+ limitation; specifications exceeding those limits provide the value of the
+ nearer limit. If the argument specifies "*" for the region, the command
+ applies to all regions. $VIEW("POOLLIMIT",<region>) returns the current
+ value for the region as an ordinal number - zero (0) when there is no
+ limit in place. Note that this facility is designed for use by a
+ relatively small subset of processes. In addition, MUPIP REORG uses this
+ facility to limit its buffers to a value established by the UNIX
+ environment variable (or OpenVMS logical name) gtm_poollimit using the
+ syntax described for VIEW "POOLLIMIT" with a default of 64 if
+ gtm_poollimit is not specified. Note that this may slightly slow a
+ standalone REORG but can be overridden by defining gtm_poollimit as 0 or
+ "100%".
+
4 RCTLDUMP
RCTLDUMP
@@ -5370,7 +5391,6 @@
Line #4: for i=1:1:$order(merval(""),-1) do
Line #5: . kill:i#2 merval(i)
Line #6: quit
-
GTM>
This shows that merge^profiling has an elapsed time of 16231 and the
@@ -5414,7 +5434,6 @@
execute the following commands:
GTM>ZBREAK merge^profiling:"view ""TRACE"":1:""^mtrc"" write ""Trace"""
-
GTM>do ^profiling
Trace
GTM>view "TRACE":0:"^mtrc"
@@ -5522,45 +5541,29 @@
new i,j,k,v
set k=1
view "TRACE":1:"^trc"
-
for i=1:1:3 set v=i
-
for i=1:1 set v=0 quit:i=3
-
for i=1,2:1:4,6 set v=0
-
for i=1:1,2 set v=0 quit:i=3
-
for i=1:1:2 for j=1:1:3 set v=0
-
for i=1:1:2
. for j=1:1:1 do
.. set v=0
-
set j=5 for i=1:1:j do
. set j=(j-1)
-
for i=1:1:2 for j=1:1:3 do
. set v=0
-
for i=1:1:2 do
. for j=1:1:3 set v=0
-
for i=1:1:2 do
. for j=1:1:3 do
.. set v=0
-
for i="foo","bar",1:1 set v=0 quit:i=3
-
for set k=k+1 quit:k=3
-
for i=1:1:3 for j=1:1:(3-i) set v=0
-
for i=1:1:3 for j=1:1:(3-i) for k=1:1:(j+1) set v=0
-
set k=3 view "TRACE":0:"^trc"
zwrite ^trc
-
quit
On executing fortypes, the output looks something like the following:
@@ -5628,7 +5631,6 @@
GTM>Kill A
GTM>View "NOUNDEF"
-
GTM>Write A,?10,$L(A)
0
GTM>
@@ -5650,9 +5652,7 @@
LAB Write !,"THIS IS NOSENSE"
Quit
GTM>View "LABELS":"UPPER"
-
GTM>ZLink "NOSENSE.m"
-
GTM>Do ^NOSENSE
THIS IS NOSENSE
GTM>
@@ -5827,7 +5827,6 @@
SUB Write !,"This is ZBTEST"
Quit
GTM>ZBREAK SUB^ZBTEST
-
GTM>Do ^ZBTEST
%GTM-I-BREAKZBA, Break instruction encountered during ZBREAK action
At M source location SUB^ZBTEST
@@ -5843,9 +5842,7 @@
GTM>ZBREAK -*
GTM>ZGOTO
-
GTM>ZBREAK SUB^ZBTEST:"W !,""Trace"""
-
GTM>Do ^ZBTEST
Trace
This is ZBTEST
@@ -6006,7 +6003,6 @@
Example:
GTM>ZGOTO
-
GTM>ZSHow
+1^GTM$DMOD (Direct mode)
GTM>
@@ -6152,14 +6148,10 @@
GTM>zlink "sockexamplemulti2"
%GTM-E-LOADRUNNING, Cannot ZLINK an active routine sockexamplemulti2
-
GTM>zshow "S"
sockexamplemulti2+12^sockexamplemulti2 (Direct mode)
-
GTM>view "LINK":"RECURSIVE"
-
GTM>zlink "sockexamplemulti2"
-
GTM>
This example demonstrates how VIEW "LINK":"RECURSIVE" command ZLINKs a
@@ -6194,30 +6186,19 @@
3 Auto-ZLINK_setup
Auto-ZLINK setup
- This section describes the procedure to setup the field test grade
- auto-relink functionality that is available in V6.2-000. Although V6.2-000
- when used without auto-relink (i.e., without use of the ZRUPDATE command
- or the special syntax in $ZROUTINES) is a generally available, production
- grade release, use auto-relink only in development and test environments
- where field test grade functionality is acceptable.
-
- By suffixing one or more directory names in $ZROUTINES with a single
- asterisk (*), processes can subscribe to updates of object files published
- in those directories. At the invocation of DO, GOTO, or ZGOTO, extrinsic
- functions, $TEXT(), or ZPRINT that specify an entryref which includes a
- routine name (vs. a label without a routine name), mumps processes (and
- mupip processes executing trigger logic) automatically relink
- ("auto-relink") and execute published new versions of routines.
-
- o Label references (that is , without a routine name), whether direct or
- through indirection, always refer to the current routine, and do not
- invoke auto-relink logic.
- o Use shell quoting rules when appending asterisks to directory names in
- the gtmroutines environment variable - asterisks must be passed in to
- GT.M, and not expanded by the shell.
- o GT.M accepts but ignores asterisk suffixes to directory names on
- 32-bit Linux on x86 platforms, where it does not provide
- auto-relinking.
+ This section describes the procedure to setup the auto-relink
+ functionality. GT.M loads an object file linked from an object directory
+ (in $ZROUTINES) with a *-suffix (i.e. auto-relink-enabled) into a shared
+ memory segment (referred to henceforth as a Rtnobj shared memory segment).
+ At the invocation of DO, GOTO, or ZGOTO, extrinsic functions, ZBREAK,
+ ZPRINT or
+
+ $TEXT()
+
+ that specify an entryref which includes a routine name (in contrast to a
+ label without a routine name), mumps processes (and mupip processes
+ executing trigger logic) automatically relink ("auto-relink") and execute
+ published new versions of routines.
The ZRUPDATE command publishes of new versions of routines to subscribers.
To remove routines, delete the object files and publish the names of the
@@ -6226,59 +6207,64 @@
If the path to a file is non-existent, the request is ignored except in
the case where one desires a currently shared object file (one that was
- accessed before it was deleted) to no longer be shared. In V6.2-000, if
- the process executing the ZRUPDATE does not have read permission to any
- directory in the path to a file, ZRUPDATE ignores the request; FIS expect
- to correct this in the production release.
-
- To effect auto-relink, GT.M creates small temporary files in the directory
- referred to by $gtm_linktmpdir (defaulting to $gtm_tmp, which in turn
- defaults to /tmp, if unspecified). The names of these files are of the
- form gtm-relinkctl-<md5sum> where <md5sum> is a hash of the realpath() to
- an auto-relink directory. In the field test software, the permissions are
- determined by the umask of the process creating a file. In the production
- software, FIS intends for the group and permissions to match those for
- shared resources as described in the section Shared Resources
- Authorization Permissions in Appendix E (GT.M Security Philosophy) of the
- UNIX Administration and Operations Guide. FIS recommends that all
- processes that share a directory whose contents are subject to ZRUPDATE
- use the same value for $gtm_linktmpdir so that all processes see update
- notifications - with different values of $gtm_linktmpdir, a ZRUPDATE by a
- process with one value of $gtm_linktmpdir would not be observed by a
- process with a different value of that environment variable.
-
- When a process that has subscribed to updates to routines in a directory
- links to a routine from that directory, it maps the object file to its
- address space, sharing the object code with other processes that are so
- subscribed, and without requiring the object code to be placed in a shared
- library. Processes that have not subscribed to updates link using
- process-private heap space as they have in prior versions.
-
- AIX has known architectural limitations to scalability when large numbers
- of processes (thousands to tens of thousands) auto-relink large numbers of
- routines (again thousands to tens of thousands of routines). In the
- typical case where the number of dynamically modified routines is much
- smaller than the total number of routines in an enterprise scale
- application, a scalable way for large applications to use auto-relinking
- on AIX is to place all routines in shared libraries, and define $ZROUTINES
- with an auto-relink enabled patch directory preceding the shared library.
- Scalability on HP-UX and Solaris is not known: FIS is not aware of any
- inherent scalability issues other than those imposed by available hardware
- resources when the product of the number of processes and the number of
- auto-relinked remains well below the number of file descriptors made
- available by the OS.
-
- Changing $ZROUTINES currently causes all routines linked from
- auto-relink-enabled directories in the process to be re-linked. FIS
- intends for this to generate an error in the production release.
-
- VIEW "RCTLDUMP" displays the created relinkctl files and the routines
- looked for in their related directories. An entry in these files does not
- mean that a given routine was found there. It merely means it was looked
- for there and shows a cycle number (which ZRUPDATE bumps) whose change
- indicates a new published version of the given object file. As it is a
- diagnostic tool for the new feature, FIS may remove or modify this VIEW
- option in subsequent releases.
+ accessed before it was deleted) to no longer be shared.
+
+ For each auto-relink enabled directory which a GT.M process accesses while
+ searching through $ZROUTINES, GT.M creates a small control file
+ (Relinkctl) in the directory identified by $gtm_linktmpdir (defaulting to
+ $gtm_tmp, which in turn defaults to /tmp, if unspecified). The names of
+ these files are of the form gtm-relinkctl-<murmur> where <murmur> is a
+ hash of the realpath() to an auto-relink directory; for example:
+ /tmp/gtm-relinkctl-f0938d18ab001a7ef09c2bfba946f002). With each Relinkctl
+ file, GT.M creates and associates a block of shared memory that contains
+ associated control structures. Among the structures is a cycle number
+ corresponding to each routine found in the routine directory; a change in
+ the cycle number informs a process that it may need to determine whether
+ there is a new version of a routine. Although GT.M only creates relinkctl
+ records for routines that actually exist on disk, it may increment cycle
+ numbers for existing relinkctl records even if they no longer exist on
+ disk.
+
+ GT.M creates both the Relinkctl file and shared memory with permissions
+ based on the logic described in the "IPC Permissions" column of the
+ "Shared Resource Authorization Permissions" section in the Administration
+ and Operations Guide, except that the object directory, rather than the
+ database file, provides the base permissions.
+
+ The MUPIP RCTLDUMP command reports information related to relinkctl files
+ and their associated shared memory segments.
+
+ The environment variable gtm_autorelink_keeprtn if set to 1, t[rue], or
+ y[es] causes exiting processes to leave auto-relinked object code in the
+ shared memory repositories, while if undefined, 0, f[alse] or n[o] causes
+ exiting processes to purge any routines currently use by no processes. All
+ values are case-independent. When gtm_autorelink_keeprtn is defined and
+ TRUE:
+
+ FIS recommends that a directory in the $zroutines of a process be either
+ auto-relink-enabled or auto-relink-disabled for the life of the process.
+ Changing the auto-relink mode of the directory within a process is likely
+ to result in counter-intuitive results.
+
+ As arguments, ZRUPDATE takes object file names, including wild-cards of
+ the form accepted by $ZSEARCH(). If ZRUPDATE fails to find at least one
+ file to match an argument with a wild card, it issues an INFO message
+ (seen only if $PRINCIPAL has CENABLE). When an explicit name without a
+ wild card is specified, but there is no file in the directory or a
+ corresponding entry in the Relinkctl, ZRUPDATE produces an error. ZRUPDATE
+ issues most errors as FILEPARSE errors with a secondary error describing
+ the actual issue although some errors, depending on the reason and path by
+ which ZRUPDATE detects them, can be rather cryptic.
+
+ An explicit ZLINK or an auto-relink check the hash of an object and its
+ replacement. If they are identical, GT.M takes no action to replace the
+ current object, saving both memory and time.
+
+ An explicit ZLINK from an auto-relink directory acts as an implicit
+ ZRUPDATE.
+
+ Any ZBREAK in a routine disables that routine from auto-relinking by a
+ process until all ZBREAKs are removed.
3 ZLINK,_auto-ZLINK_and_Routine_Names
ZLINK, auto-ZLINK and Routine Names
@@ -6330,7 +6316,6 @@
Example:
GTM>ZMessage 2
-
%SYSTEM-E-ENO2, No such file or directory
This ZMESSAGE does not specify substitution text and the message does not
@@ -6389,7 +6374,6 @@
GTM>ZPRINT X^RTN:X+5
GTM>ZPRINT X+-5^RTN:X
-
GTM>ZPRINT X^RTN:X+-5^RTN
The first line displays the line beginning with the label X and the next 5
@@ -6407,6 +6391,13 @@
This command displays the trigger code for trigger name A#1#.
+ ZPRINT ^x#/BREG : Print trigger routine user-named "x" in region BREG
+ ZPRINT ^x#1#/BREG : Print trigger routine auto-named "x#1" in region BREG
+ ZPRINT ^x#1#A/BREG : Print trigger routine auto-named "x#1", runtime disambiguated by "#A", AND in region BREG
+ ZPRINT +1^x#1#A/BREG : Print line 1 of trigger routine auto-named "x#1", runtime disambiguated by "#A", AND in region BREG
+
+ These are some examples of disambiguator combinations.
+
2 ZRUPDATE
ZRUPDATE
@@ -6429,7 +6420,7 @@
was accessed before it was deleted) to no longer be shared. In
V6.2-000, if the process executing the ZRUPDATE does not have read
permission to any directory in the path to a file, ZRUPDATE ignores
- the request; FIS expects to correct this in the production release.
+ the request; FIS expect to correct this in the production release.
o To effect auto-relink, GT.M creates small temporary files in the
directory referred to by $gtm_linktmpdir (defaulting to $gtm_tmp,
which in turn defaults to /tmp, if unspecified). The names of these
@@ -6462,6 +6453,14 @@
A ZSHOW argument is an expression containing codes selecting one or more
types of information.
+ A: A stands for Autorelink and provides output in the same format as MUPIP
+ RCTLDUMP, but restricted to the routines linked by the process issuing the
+ command. ZSHOW "*" does not include ZSHOW "A" because of an expectation
+ that the typical volume of the information does not provide a good return
+ for its value. If you wish your error handling or INTRPT routines to dump
+ this information, ask for it explicitly, possibly by doing a ZSHOW "A"
+ into a local variable before doing a ZSHOW "*".
+
B: displays active ZBREAK breakpoints
D: displays device information
@@ -6473,8 +6472,8 @@
L: displays GT.M LOCKs and ZALLOCATEs held by the process
- R: displays the GT.M invocation stack and an MD5 checksum of M source code
- for each routine on the stack.
+ R: displays the GT.M invocation stack and a hash based on the MurmurHash3
+ algorithm of M source code for each routine on the stack.
S: displays the GT.M invocation stack
@@ -6506,6 +6505,14 @@
SET : # of SET operations (TP and non-TP)
KIL : # of KILl operations (kill as well as zwithdraw, TP and non-TP)
GET : # of GET operations (TP and non-TP)
+ CAT : total of critical section acquisitions successes
+ CFE : total attempts in CFT caused by epochs
+ CFS : sum of squares of blocked critical section acquisitions
+ CFT : total of blocked critical section acquisitions
+ CQS : sum of squares of critical section acquisition queued sleeps
+ CQT : total of critical section acquisition queued sleeps
+ CYS : sum of squares of critical section acquisition processor yields
+ CYT : total of critical section acquisition processor yields
DTA : # of DaTA operations (TP and non-TP)
ORD : # of $ORDer() operations (TP and non-TP). The count of $Order(xxx,1) operations are reported under this item.
ZPR : # of $ZPRevious() (reverse order) operations (TP and non-TP). The count of $Order(xxx,-1) operations are reported under this item.
@@ -6552,7 +6559,6 @@
JRO : # of all journal records other than logical, PBLK, AIMG and EPOCH records written to the journal file (for example, PINI, PFIN, and so on.)
JEX : # of times a process extends the journal file
DEX : # of times a process extends the database file
-
[NT]B[WR] mnemonics are satisfied by either disk access or, for databases that use the BG (buffered global) access method, global buffers in shared memory.
3 Examples
@@ -6603,12 +6609,10 @@
GLD:*,REG:*,SET:205,KIL:0,GET:1,DTA:0,ORD:0,ZPR:0,QRY:0,LKS:0,LKF:0,CTN:0,DRD:9,DWT:15,
NTW:203,NTR:4,NBW:212,NBR:414,NR0:0,NR1:0,NR2:0,NR3:0,TTW:1,TTR:0,TRB:0,TBW:2,TBR:6,
TR0:0,TR1:0,TR2:0,TR3:0,TR4:0,TC0:0,TC1:0,TC2:0,TC3:0,TC4:0
-
GLD:/home/gtmuser1/.fis-gtm/V5.4-002B_x86/g/mumps.gld,REG:DEFAULT,SET:205,KIL:0,GET:1,
DTA:0,ORD:0,ZPR:0,QRY:0,LKS:0,LKF:0,CTN:411,DRD:9,DWT:15,NTW:2
03,NTR:4,NBW:212,NBR:414,NR0:0,NR1:0,NR2:0,NR3:0,TTW:1,TTR:0,TRB:0,TBW:2,TBR:6,TR0:0,
TR1:0,TR2:0,TR3:0,TR4:0,TC0:0,TC1:0,TC2:0,TC3:0,TC4:0
-
GLD:/tmp/tst/test.gld,REG:DEFAULT,SET:205,KIL:0,GET:1,DTA:0,ORD:0,ZPR:0,QRY:0,LKS:0,LKF:0,
CTN:411,DRD:9,DWT:15,NTW:203,NTR:4,NBW:212,NBR:414,NR0:0,NR1:0,NR2:0,NR3:0,TTW:1,TTR:0,TRB:0,
TBW:2,TBR:6,TR0:0,TR1:0,TR2:0,TR3:0,TR4:0,TC0:0,TC1:0,TC2:0,TC3:0,TC4:0
@@ -6624,7 +6628,6 @@
GLD:*,REG:*,SET:0,KIL:0,GET:0,DTA:0,ORD:0,ZPR:0,QRY:0,LKS:0,LKF:0,CTN:0,DRD:0,DWT:0,NTW:0,
NTR:0,NBW:0,NBR:0,NR0:0,NR1:0,NR2:0,NR3:0,TTW:0,TTR:0,TRB:0,
TBW:0,TBR:0,TR0:0,TR1:0,TR2:0,TR3:0,TR4:0,TC0:0,TC1:0,TC2:0,TC3:0,TC4:0
-
GLD:/tmp/x1.gld,REG:REG1,SET:0,KIL:0,GET:0,DTA:0,ORD:0,ZPR:0,QRY:0,LKS:0,LKF:0,CTN:0,DRD:0,
DWT:0,NTW:0,NTR:0,NBW:0,NBR:0,NR0:0,NR1:0,NR2:0,NR3:0,TTW:0,
TTR:0,TRB:0,TBW:0,TBR:0,TR0:0,TR1:0,TR2:0,TR3:0,TR4:0,TC0:0,TC1:0,TC2:0,TC3:0,TC4:0
@@ -6651,9 +6654,7 @@
Example:
GTM>LOCK ^FAIL:10
-
GTM>lock (^SUCCESS1,^SUCCESS2)
-
GTM>zshow "L"
MLG:1,MLT:1
LOCK ^SUCCESS1 LEVEL=1
@@ -6721,7 +6722,6 @@
GTM>KILL SET a(1,"D",3,5)="stuff",a(1,"X",2)="",a(1)=1
GTM>ZSHow "d":a(1)
-
GTM>ZWRite
a(1)=1
a(1,"D",1)="/dev/pts/1 OPEN TERMINAL NOPAST NOESCA NOREADS TYPE WIDTH=80 LENG=24
@@ -6737,7 +6737,6 @@
GTM>KILL ^ZSHOW
GTM>ZB -*,lab^rout ZSH "B":^ZSHOW
-
GTM>ZWRite ^ZSHOW
^ZSHOW("B",1)="LAB^ROUT"
GTM>
@@ -7345,9 +7344,7 @@
for i=1:1:$length(x) quit:" "'=$extract(x,i)
for j=$length(x):-1:1 quit:" "'=$extract(x,j)
quit $extract(x,i,j)
-
GTM>set str=" MUMPS "
-
GTM>write $length(str)
7
GTM>write $length($$^trim(str))
@@ -7395,7 +7392,6 @@
Example:
GTM>set t=1 for set t=$find("BANANA","AN",t) quit:'t write !,t
-
4
6
GTM>
@@ -7798,9 +7794,7 @@
Example:
GTM>kill set (a(1),a(2000),a("CAT"),a("cat"),a("ALF"),a(12))=1
-
GTM>set x="" for set x=$order(a(x)) quit:x="" write !,x
-
1
12
2000
@@ -7808,9 +7802,7 @@
CAT
cat
GTM>kill a("CAT") set a(5,10)="woolworths",a("cat")="last"
-
GTM>set x="" for set x=$order(a(x),-1) quit:x="" write !,x
-
cat
ALF
2000
@@ -7832,7 +7824,6 @@
GTM>kill set (%(1),tiva(2),A(3),tiv(4),Q(5),%a(6))=""
GTM>set x="%"
GTM>write:$data(@x) !,x for set x=$order(@x) quit:x="" write !,x
-
%
%a
A
@@ -7842,7 +7833,6 @@
x
GTM>set $piece(x,"z",32)=""
GTM>write:$data(@x) !,x for set x=$order(@x,-1) quit:x="" write !,x
-
x
tiva
tiv
@@ -7944,7 +7934,6 @@
GTM>write $data(^|"XXX"|ABC(1,2,3,4))
0
GTM>set X=$name(^(5,6))
-
GTM>write $qlength(X)
5
@@ -8044,7 +8033,6 @@
lcl(1,2,"abc",5)=7
lcl("x")=1
GTM>set y="lcl"
-
GTM>for set y=$query(@y) quit:y="" write !,y,"=", at y
This example produces the results:
@@ -8144,12 +8132,10 @@
Example:
GTM>for i=3:-1:0 write !,$select(i=1:"here",i=2:"come",i=3:"Watson")
-
Watson
come
here
%GTM-E-SELECTFALSE, No argument to $SELECT was true
-
GTM>
This loop uses $SELECT() to WRITE a series of strings. Because there is no
@@ -8214,7 +8200,6 @@
DLabel
write !,$STACK
quit
-
0
1
1
@@ -8230,7 +8215,6 @@
for l=dsm1:-1:0 do
. write !,l
. for i="ecode","place","mcode" write ?5,i,?15,$stack(l,i),!
-
GTM>
The above example can be used to display a trace of the code path that led
@@ -8245,53 +8229,40 @@
if x>0 set $ecode=",U1," ; if condition
else set $ecode=",U2," ; else condition
quit
-
GTM>do ^dstacktst(0)
-
$stack(-1):2
2 ecode
place debugerr+3^debugerr
mcode for l=dsm1:-1:0 do
-
1 ecode ,U2,
place label+2^dstacktst
mcode else set $ecode=",U2," ; else condition
-
0 ecode
place +1^GTM$DMOD
mcode
%GTM-E-SETECODE, Non-empty value assigned to $ECODE (user-defined error trap)
-
GTM>do ^dstacktst(1)
-
$stack(-1):1
1 ecode ,U2,
place label+2^dstacktst
mcode else set $ecode=",U2," ; else condition
-
0 ecode
place +1^GTM$DMOD
mcode
%GTM-E-SETECODE, Non-empty value assigned to $ECODE (user-defined error trap)
-
GTM>set $ecode=""
-
GTM>do ^dstacktst(1)
-
$stack(-1):2
2 ecode
place debugerr+3^debugerr
mcode for l=dsm1:-1:0 do
-
1 ecode ,U1,
place label+1^dstacktst
mcode if x>0 set $ecode=",U1," ; if condition
-
0 ecode
place +1^GTM$DMOD
mcode
%GTM-E-SETECODE, Non-empty value assigned to $ECODE (user-defined error trap)
-
GTM>
This example shows how SETing $ECODE=.. makes $STACK() reports current
@@ -8458,13 +8429,11 @@
|"GVNEXT" |region |Name of the next database region after the given one in alphabetical order (or M collation sequence); "" for region|
| | |starts with the first region. A return value of "" means that the global directory defines no additional regions. |
|-----------------+--------------+-------------------------------------------------------------------------------------------------------------------|
- | | |Encoded information about database behavior since segment creation. It also includes SET operations even if they |
- | | |are inside a TP transaction. |
+ | | |When |
| | | |
- |"GVSTAT" |region |If you require completely accurate GVSTATS, you need to ensure the last process to close a database always has |
- | | |write access to the database files. If read-only processes are the active processes in a database, they cannot |
- | | |update the database and may delete the shared memory where they have stored the counts of their actions (for |
- | | |example, the number of blocks read). |
+ |"GVSTAT" |region |read-only processes are the active in a database, they cannot update the database including the file header where |
+ | | |GVSTATS are stored. Therefore their counts are only stored in associated shared memory and must be flushed to the |
+ | | |file header by a process with write access, which might be a MUPIP RUNDOWN. |
|-----------------+--------------+-------------------------------------------------------------------------------------------------------------------|
| | |Number of indirection cache hits since GT.M process startup. |
|"ICHITS" |none | |
@@ -8509,6 +8478,9 @@
| | |By default, GT.M ensures Isolation, that is, a $VIEW command will return 0. The isolation-status of a global |
| | |variable can be turned on and off by the VIEW "NOISOLATION" command. |
|-----------------+--------------+-------------------------------------------------------------------------------------------------------------------|
+ |"PROBECRIT" |region |Acquires and releases a critical section for the region (the "probe"), returning a string with the following |
+ | | |fields: |
+ |-----------------+--------------+-------------------------------------------------------------------------------------------------------------------|
| | |Name of the region(s) holding the specified gvn. |
| | | |
| | |If gvn spans more than one region, this function returns region name in an order where the first region is the |
@@ -8521,7 +8493,8 @@
|-----------------+--------------+-------------------------------------------------------------------------------------------------------------------|
|"PATCODE" |none |Name of the active patcode table; GT.M defaults this to "M". |
|-----------------+--------------+-------------------------------------------------------------------------------------------------------------------|
- |"RTNCHECKSUM" |routine name |Returns the source check-sum for the most recently ZLINK'd version of the specified routine name. |
+ |"RTNCHECKSUM" |routine name |Use a 128 bit hash based on the MurmurHash3 algorithm to returns the source check-sum for the most recently ZLINK'd|
+ | | |version of the specified routine name. |
|-----------------+--------------+-------------------------------------------------------------------------------------------------------------------|
|"RTNNEXT" |routine name |Name of the next routine in the image after the given one; "" (empty string) for routinename starts with the first |
| | |routine in ASCII collating sequence and a return value of the empty string indicates the end of the list. |
@@ -8558,11 +8531,10 @@
| | |Displays the global name or a global name with subscript(s) of a database representation gds. The option collnum |
| | |specifies the collnum specifies the alternate collation sequence number. If collnum is not specified, GT.M assumes |
| | |the default ASCII collation(collnum=0). This function is the inverse of the $VIEW("YGVN2GDS",<gvn>[,collnum]) |
- | | |function. For example: |
- |"YGDS2GVN" |gds[,collnum])| |
+ |"YGDS2GVN" |gds[,collnum])|function. For example: |
+ | | | |
| | |GTM>set y=$VIEW("YGDS2GVN",x) zwrite y |
| | |y="^A(1,""abcd"")" |
- | | | |
| | |GTM> |
|-----------------+--------------+-------------------------------------------------------------------------------------------------------------------|
|"ZDATE_FORM" |none |Integer value showing whether four digit year code is active for $ZDATE(); GT.M defaults to 0 (for "YY" format). |
@@ -8582,7 +8554,6 @@
Example:
GTM>Set a=1,*b(1)=a
-
GTM>write $view("LV_CREF","a")," ",$view("LV_CREF","b")
1 0
GTM>write $view("LV_REF","a")," ",$view("LV_REF","b")
@@ -8596,9 +8567,7 @@
Example:
GTM>Set *a(1)=b,*b(1)=a
-
GTM>kill *a,*b
-
GTM>write $view("LV_GCOL")
2
GTM>
@@ -8666,15 +8635,12 @@
Example:
GTM>set A=1,*B(1)=A
-
GTM>write "$zahandle(A)=""",$zahandle(A),""" $zahandle(B(1))=""",$zahandle(B(1)),""""
$zahandle(A)="17B8810" $zahandle(B(1))="17B8810"
GTM>set A("Subscript")="Value" ; Change array - but $ZAHandle() doesn't change
-
GTM>write "$zahandle(A)=""",$zahandle(A),""" $zahandle(B(1))=""",$zahandle(B(1)),""""
$zahandle(A)="17B8810" $zahandle(B(1))="17B8810"
GTM>merge D=A ; A copy of the data has a different $zahandle()
-
GTM>Write "$ZAHandle(A)=""",$ZAHandle(A),""" $ZAHandle(D)=""",$ZAHandle(D),""""
$zahandle(A)="17B8810" $zahandle(D)="17B8C10"
GTM>
@@ -8776,9 +8742,7 @@
; The binary representation of A is 01000001
GTM>Set BITSTRINGB=$zbitset($zbitset($zbitstr(8,0),2,1),7,1)
; The binary representation of B is 01000010
-
GTM>set BITSTRINGAB=$zbitand(BITSTRINGA,BITSTRINGB)
-
GTM>for i=1:1:8 write $zbitget(BITSTRINGAB,I)
01000000
@@ -8804,13 +8768,10 @@
GTM>set BITSTRINGA=$ZBITSET($ZBITSET($ZBITSTR(8,0),2,1),8,1)
; The binary representation of A is 01000001
-
GTM>set BITSTRINGB=$zbitset($zbitset($zbitstr(8,0),2,1),7,1)
; The binary representation of B is 01000010
-
GTM>Set BITSTRINGC=$zbitor(BITSTRINGA,BITSTRINGB)
; A OR B=01000011
-
GTM>write $zbitcount(BITSTRINGA)
2
GTM>write $zbitcount(BITSTRINGB)
@@ -8843,7 +8804,6 @@
GTM>Set BITSTRINGA=$ZBITSET($ZBITSET($ZBITSTR(8,0),2,1),8,1)
; The binary representation of A is 01000001
-
GTM>write $zbitfind(BITSTRINGA,1,3)
9
GTM>
@@ -8868,7 +8828,6 @@
GTM>set BITSTRINGA=$zbitset($zbitset($zbitstr(8,0),2,1),8,1)
; The binary representation of A is 01000001
-
GTM>for i=1:1:8 write $zbitget(BITSTRINGA,I)
01000001
GTM>
@@ -8909,7 +8868,6 @@
GTM>set BITSTRINGA=$zbitset($zbitset($zbitstr(8,0),2,1),8,1)
; The binary representation of A is 01000001
-
GTM>for i=1:1:8 write $zbitget($zbitnot(BITSTRINGA),I)
10111110
GTM>
@@ -8934,13 +8892,10 @@
GTM>set BITSTRINGA=$zbitset($zbitset($zbitstr(8,0),2,1),8,1)
; The binary representation of A is 01000001
-
GTM>set BITSTRINGB=$zbitset($zbitset($zbitstr(8,0),2,1),7,1)
; The binary representation of B is 01000010
-
GTM>set BITSTRINGC=$zbitor(BITSTRINGA,BITSTRINGB)
; A OR B=01000011
-
GTM>write BITSTRINGC
C
GTM>
@@ -9003,11 +8958,8 @@
Examples
GTM>set BITSTRINGA=$zbitset($zbitset($zbitstr(8,0),2,1),8,1) ; The binary representation of A is 01000001
-
GTM>set BITSTRINGB=$zbitset($zbitset($zbitstr(8,0),2,1),7,1); The binary representation of B is 01000010
-
GTM>set BITSTRINGC=$zbitor(BITSTRINGA,BITSTRINGB) ; A XOR B=00000011
-
GTM>for I=1:1:8 write $zbitget(BITSTRINGC,I)
00000011
GTM>
@@ -9149,11 +9101,9 @@
GTM>Write $Length(T8)
12
GTM>Set T16=$zconvert(T8,"UTF-8","UTF-16LE")
-
GTM>Write $length(T16)
%GTM-E-BADCHAR, $ZCHAR(129,137,232,150) is not a valid character in the UTF-8 encoding form
GTM>Set T16=$ZCOnvert(T16,"UTF-16LE","UTF-8")
-
GTM>Write $length(T16)
9
@@ -9193,7 +9143,6 @@
GTM>write $data(b(1))," ",$zdata(b(1))
1 101
GTM>set b(1,2)=2
-
GTM>write $data(b(1))," ",$zdata(b(1))
11 111
GTM>write $data(b(1,2))," ",$zdata(b(1,2))
@@ -9348,7 +9297,6 @@
Example:
GTM>write !,$zdate($H,"12:60:SS AM")
-
10:35:51 PM
GTM>
@@ -9358,7 +9306,6 @@
Example:
GTM>write !,$zdate(",36524","24-60")
-
10-08
GTM>
@@ -9373,7 +9320,6 @@
GTM>write $zdate($H)
01/18/11
GTM>set $zdateform=1
-
GTM>write $zdate($horolog)
01/18/2011
GTM>write $zdate($horolog,"MM/DD/YY")
@@ -9408,9 +9354,7 @@
GTM>Set A="************"
GTM>For i=0:1:$zlength(A)
-
GTM>write !,$zascii($zextract(A,i)),"|"
-
GTM>
This example displays the numeric byte sequence of the sequence of octets
@@ -9451,7 +9395,6 @@
Example:
GTM>set t=1 for set t=$zfind("***",$zchar(230,150,176),t) quit:'t write !,t
-
4
GTM>
@@ -9502,7 +9445,6 @@
to $ZPARSE(), as illustrated by the following M code:
set deffn="GTM_JOBEXAMINE.ZSHOW_DMP_"_$JOB_"_"_<cntr>
-
set filespec=$zparse(expr1,"",deffn)
The $ZJOBEXAM()does not trigger error processing except when there is a
@@ -9526,7 +9468,6 @@
GTM>write x
/home/gtmuser1/.fis-gtm/V5.4-002B_x86/r/GTM_JOBEXAM.ZSHOW_DMP_28760_1
GTM>set x=$zjobexam("test.file")
-
GTM>write x
/home/gtmuser1/.fis-gtm/V5.4-002B_x86/r/test.file
GTM>
@@ -9625,7 +9566,6 @@
Example:
GTM>write $zmessage(36)
-
Interrupted system call
GTM>
@@ -9768,7 +9708,6 @@
Example:
GTM>for i=0:1:3 write !,$zpiece("*"_$zchar(64)_"*",$zchar(64),i),"|"
-
|
*|
*|
@@ -9782,13 +9721,11 @@
Example:
GTM>for i=-1:1:3 write !,$zpiece("*"_$zchar(64)_"*",$zchar(64),i,i+1),"|"
-
|
*|
*@*|
*|
|
-
GTM>
This example is similar to the previous example except that it displays
@@ -9805,7 +9742,7 @@
Example:
GTM>Set $piece(x,$zchar(64),25)="" write x
- ***@@@@@@@@@@@@@@@@@@@@@@@@
+ ???@@@@@@@@@@@@@@@@@@@@@@@@
This SETs the 25th piece of the variable x to null, with delimiter
$ZCHAR(64). This produces a byte sequence of 24 at-signs (@) preceding the
@@ -9829,100 +9766,116 @@
$ZPEEK("mnemonic[:argument]",offset,length[,format])
- o mnemonic specifies the memory area $ZPEEK() is to access. Some
+ * mnemonic specifies the memory area $ZPEEK() is to access. Some
mnemonics have arguments separated from the mnemonic by a colon (":").
The mnemonics are case independent. Possible mnemonics, their possible
abbreviations and their arguments are:
- o CSA[REG] - returns a value from the sgmnt_addrs (process private)
+ * CSA[REG] - returns a value from the sgmnt_addrs (process private)
control block. Takes a case independent region name as an
argument.
- o FH[REG] - returns a value from the sgmnt_data (shared file
+ * FH[REG] - returns a value from the sgmnt_data (shared file
header) control block. Takes a case independent region name as an
argument.
- o GDR[REG] - returns a value from the gd_region (process private)
+ * GDR[REG] - returns a value from the gd_region (process private)
control block. Takes a case independent region name as an
argument.
- o GLF[REPL] - returns a value from the jnlpool.gtmsrc_lcl_array[n]
+ * GLF[REPL] - returns a value from the jnlpool.gtmsrc_lcl_array[n]
control block. Takes a numeric index (n) as an argument.
- o GRL[REPL] - returns a value from the recvpool.gtmrecv_local
+ * GRL[REPL] - returns a value from the recvpool.gtmrecv_local
control block. No argument allowed. Only available when run on a
non-primary instance.
- o GSL[REPL] - returns a value from the
+ * GSL[REPL] - returns a value from the
jnlpool.gtmsource_local_array[n] control block. Takes a numeric
index (n) as an argument.
- o JPC[REPL] - returns a value from the jnlpool.jnlpool_ctl control
+ * JBF[REG]:region[ -obtains fields in shared jnl_buffer structure.
+ * JNL[REG]:region[ - obtains fields in the jnl_private_control
+ structure.
+ * JPC[REPL] - returns a value from the jnlpool.jnlpool_ctl control
block. No argument allowed.
- o NL[REG] - returns a value from the node_local (shared) control
+ * NL[REG] - returns a value from the node_local (shared) control
block. Takes a case independent region name as an argument.
- o NLREPL - returns a value from the node_local (shared) control
+ * NLREPL - returns a value from the node_local (shared) control
block associated with replication. No argument allowed.
- o PEEK - returns a value based on the supplied argument. Argument
+ * PEEK - returns a value based on the supplied argument. Argument
is the base address of whatever is being fetched in 0xhhhhhhh
format where the h's are hex digits.
- o RIH[REPL] - returns a value from the jnlpool.repl_inst_filehdr
+ * RIH[REPL] - returns a value from the jnlpool.repl_inst_filehdr
control block. No argument allowed.
- o RPC[REPL] - returns a value from the recvpool.recvpool_ctl
+ * RPC[REPL] - returns a value from the recvpool.recvpool_ctl
control block. No argument allowed. Only available when run on a
non-primary instance.
- o UHC[REPL] - returns a value from the recvpool.upd_helper_ctl
+ * UHC[REPL] - returns a value from the recvpool.upd_helper_ctl
control block. No argument allowed. Only available when run on a
non-primary instance.
- o UPL[REPL] - returns a value from the recvpool.upd_proc_local
+ * UPL[REPL] - returns a value from the recvpool.upd_proc_local
control block. No argument allowed. Only available when run on a
non-primary instance.
- o offset (first integer expression) is a numeric value that specifies
+ * offset (first integer expression) is a numeric value that specifies
the offset from the address supplied or implied by the the mnemonic
and argument. Specifying a negative offset results in a BADZPEEKARG
error. Specifying too large an offset such that unavailable memory is
specified results in a BADZPEEKRANGE error.
- o length (second integer expression) is a numeric value that specifies
+ * length (second integer expression) is a numeric value that specifies
the length of the field to be fetched. Specifying a negative legnth
results in a BADZPEEKARG error. Specifying a length that exceeds the
maximum string length results in a MAXSTRLEN error. Specifying too
large a length such that unavailable memory is specified results in a
BADZPEEKRANGE error.
- o format is an optional single case independent character formatting
+ * format is an optional single case independent character formatting
code for the retrieved data. The formatting codes are:
- o C : returns a character representations of the memory locations;
+ * C : returns a character representations of the memory locations;
this is the DEFAULT if the fourth argument is not specified.
- o I : returns a signed integer value - negative values have a
+ * I : returns a signed integer value - negative values have a
preceding minus sign (-); the length can be 1, 2, 4, or 8 bytes.
- o U : returns an unsigned integer value - all bits are part of the
+ * U : returns an unsigned integer value - all bits are part of the
numeric value; the length can be 1, 2, 4, or 8 bytes.
- o S : returns a character representation of the memory locations
+ * S : returns a character representation of the memory locations
and the first NULL character found terminates the returned
string; that is: the specified length is a maximum.
- o X : returns a hexadecimal value as 0xXXXXXX where XXXXXX is twice
+ * T: Selects a $HOROLOG format for a field of 4 or 8 bytes which is
+ intended for use on fields in UNIX time format (seconds since
+ 01/01/1970)
+
+ X : returns a hexadecimal value as 0xXXXXXX where XXXXXX is twice
the specified length in bytes, so requested length 1 returns 0xXX
and length 4 returns 0xXXXXXXXX; the length can be 1, 2, 4, or 8
bytes.
- o Z : returns a hexadecimal representation of the memory locations
+
+ * Z : returns a hexadecimal representation of the memory locations
as 'X' does, without regard to endianness, and with no length
restriction other than max string length.
- o $ZPEEK() function generates an UNDEF error when VIEW UNDEF is not
+ * $ZPEEK() function generates an UNDEF error when VIEW UNDEF is not
set and format parameter is specified but is undefined.
**Note**s
- o $ZPEEK() has no UTF-8 checking. It is possible for values returned by
+ * $ZPEEK() has no UTF-8 checking. It is possible for values returned by
the 'C' and 'S' codes to have invalid UTF-8 values in them. Take care
when processing values obtained by these codes to either use "VIEW
NOBADCHAR" when dealing with such values and/or use the $Zxxx()
flavors of functions like $ZPIECE(), $ZEXTRACT(),etc which also do not
raise BADCHAR errors when encountering invalid UTF-8 encoded strings.
- o Note that $ZPEEK() with 8 byte numeric formatting can return numeric
+ * Note that $ZPEEK() with 8 byte numeric formatting can return numeric
string values that exceed GT.M's current limit of 18 digits of
precision. If the values are used as strings, the extra digits are
preserved, but if used arithmetically, the lower precision digits can
be lost.
- o When values from replication structures are requested and the
+ * When values from replication structures are requested and the
structures are not available due to replication not running or, in the
case of the gtmrecv.* control block base options, if not running on a
non-primary instance where the gtmrecv.* control are available, a
ZPEEKNOREPLINFO error is raised.
+ * The JNL[REG] and JBL[REG] mnemonics and characteristics are defined by
+ the running the GTMDefinedTypesInit.m utility, which produces a
+ cross-index in the form:
+
+ gtmtypfldindx(<structure-name>.<field-mnemonic>)=<n>
+
+ where gtmtypes(<structure-name>,<n>,*) nodes contain the field
+ characteristics
2 $ZPrevious()
$ZPrevious()
@@ -10168,11 +10121,9 @@
Example:
GTM>job ^Somejob
-
GTM>set ret=$>mposix.signalval("SIGUSR1",.sigusr1) zwrite
ret=0
sigusr1=10
-
GTM>write $zsigproc($zjob,sigusr1)
0
GTM>
@@ -10194,13 +10145,9 @@
GTM>write $ZCHSET
M
GTM>set char1="a" ; one byte character
-
GTM>set char2="c,"; two-byte character
-
GTM>set char3="*"; three-byte character
-
GTM>set y=char1_char2_char3
-
GTM>write $zsubstr(y,1,3)=$zsubstr(y,1,5)
0
@@ -10213,13 +10160,9 @@
GTM>write $zchset
UTF-8
GTM>set char1="a" ; one byte character
-
GTM>set char2="c,"; two-byte character
-
GTM>set char3="*"; three-byte character
-
GTM>set y=char1_char2_char3
-
GTM>write $zsubstr(y,1,3)=$zsubstr(y,1,5)
1
@@ -10266,13 +10209,9 @@
Example:
GTM>set hiraganaA=$char(12354) ; $zchar(227,129,130)
-
GTM>set temp1=$zchar(130)
-
GTM>set temp2=$zchar(140)
-
GTM>set tr=$ztranslate(hiraganaA,temp1,temp2)
-
GTM>w $ascii(tr)
12364
GTM>
@@ -10289,6 +10228,15 @@
$ZTRIgger(expr1[,expr2])
+ **Note**
+
+ A $ZTRIGGER() action (delete or select) applies to all triggers in all
+ regions matching the specified signature. If the argument specifies an
+ incomplete trigger signature, for example, only the name, the
+ specification may match multiple triggers and apply the delete or select
+ to all of them. FIS recommends you run a select and analyze the scope of
+ the signature before any signature limited delete.
+
3 Examples_of_$ZTRIGGER()
Examples of $ZTRIGGER()
@@ -10327,8 +10275,8 @@
definition:
+^a -commands=S -xecute=<<
- do ^twork1
- do ^twork2
+ do ^twork1
+ do ^twork2
>>
Unlike $ztrigger("ITEM"), $ztrigger("FILE") usages require the trigger
@@ -10404,7 +10352,6 @@
GTM>set NG=$char($$FUNC^%HD("200B"))
GTM>set S=$char(26032)_NG_$CHAR(26033)
-
GTM>W $ZWidth(STR)
4
GTM>
@@ -10418,7 +10365,6 @@
GTM>write $zwidth("The rain in Spain stays mainly in the plain.")
44
GTM>set A="************"
-
GTM>write $length(A)
12
GTM>write $zwidth(A)
@@ -11087,7 +11033,6 @@
set $etrap="" ; exit if the input isn't valid
if $length($zcmdline) do @$zcmdline quit
quit
-
$ mumps -run foo 'BAR^FOOBAR("hello")'
In this example, GT.M processes the shell command line up to foo and puts
@@ -11430,7 +11375,6 @@
Example:
set $zinterrupt="do ^interrupthandler($io)"
-
interrupthandler(currentdev)
do ^handleinterrupt ; handle the interrupt
use currentdev ; restore the device which was current when the interrupt was recognized
@@ -11610,10 +11554,8 @@
D
set X=$ZLEVEL
quit
-
GTM>do ^zleve
4
-
GTM>
This program, executed from Direct Mode, produces a value of 4 for
@@ -11683,20 +11625,14 @@
Results:
Start with $ZMAXTPTIME=6:
-
^X=1,will set ^Y to 3 in 3 seconds...^Y=3...committed.
-
^X=2,will set ^Y to 5 in 5 seconds...^Y=5...committed.
-
^X=3,will set ^Y to 7 in 7 seconds...
In $ZTRAP handler. Error was:
150377322,longtran+7^tptime,%GTM-E-TPTIMEOUT, Transaction timeoutRolled back transaction.
-
^X=3,will set ^Y to 9 in 9 seconds...
-
In $ZTRAP handler. Error was:
150377322,longtran+7^tptime,%GTM-E-TPTIMEOUT, Transaction timeoutRolled back transaction.
-
Done TP Timeout test.
2 $ZMOde
@@ -12239,7 +12175,6 @@
.
.
GTM>WRITE $ZSOURCE
-
subr
Example:
@@ -12249,7 +12184,6 @@
.
.
GTM>WRITE $ZSOURCE
-
"test"
Example:
@@ -12259,7 +12193,6 @@
.
.
GTM>WRITE $ZSOURCE
-
/usr/smith/report.txt
Example:
@@ -12353,7 +12286,6 @@
$ export sigusrval=10
$ /usr/lib/fis-gtm/V6.1-000_x86_64/gtm
-
GTM>zprint ^ztran
foo;
set $ztexit=1
@@ -12382,19 +12314,16 @@
write "End Transaction",!
;do ^srv
quit
-
GTM>zprint ^throwint
throwint
set $zinterrupt="write !,""interrupt occurred at : "",$stack($stack-1,""PLACE""),! set $ztexit=1"
if '$zsigproc($job,$ztrnlnm("sigusrval")) write "interrupt sent to process"
write "***************************************",!!
quit
-
GTM>do foo^ztran
interrupt sent to process
interrupt occurred at : throwint+3^throwint
***************************************
-
interrupt occurred at : foo+13^ztran
GTM>
@@ -12409,16 +12338,12 @@
"IF $ZJOBEXAM()"
GTM>zsystem "ls GTM*"
ls: No match.
-
GTM>do bar^ztran
Begin Transaction
interrupt sent...
-
End Transaction
-
GTM>zsystem "ls GTM*"
GTM_JOBEXAM.ZSHOW_DMP_3951_1 GTM_JOBEXAM.ZSHOW_DMP_3951_2
-
GTM>
This uses the default value of $ZINTERRUPT to service interrupts issued to
@@ -13799,7 +13724,6 @@
Example:
GTM>kill ^a
-
GTM>zprint ^indepserver
indepserver;
read x
@@ -13808,30 +13732,20 @@
for do quit:^quit
. if $data(^a) write "^a = ",^a,!
. Hang 5
-
GTM>set a="test"
-
GTM>open a:(command="mumps -run ^indepserver>indout":independent)::"pipe"
-
GTM>use a
-
GTM>write "instructions",!
-
GTM>close a
-
GTM>zsystem "cat indout"
received = instructions
-
GTM>set ^a=1
-
GTM>zsystem "cat indout"
received = instructions
^a = 1
^a = 1
^a = 1
-
GTM>s ^quit=1
-
GTM>zsystem "cat indout"
received = instructions
^a = 1
@@ -14182,18 +14096,18 @@
CONNSOCKREQ or LOCALSOCKREQ errors, respectively, when those conditions
are not met.
- o If a numeric targetpid is specified, GT.M matches the value against
+ * If a numeric targetpid is specified, GT.M matches the value against
the process id ($JOB) of the process receiving the sockets. GT.M uses
a system service to perform this check on platforms that support it -
currently: Linux, AIX, and Solaris. On platforms which do not
implement the service (HP-UX), GT.M ignores the targetpid. If the pids
do not match, GT.M issues a PEERPIDMISMATCH error and does not
transfer the sockets.
- o If a numeric timeout is specified, GT.M sets $TEST to 1 if the
+ * If a numeric timeout is specified, GT.M sets $TEST to 1 if the
transfer completes within the specified time, and otherwise sets $TEST
to 0 and does not transfer any of the sockets.
- o Each handle specifies the name of a socket in the socket pool.
- o On a successful transfer, GT.M closes the connection of the sending
+ * Each handle specifies the name of a socket in the socket pool.
+ * On a successful transfer, GT.M closes the connection of the sending
process to the specified and sent sockets. In any case where the
transfer does not complete, GT.M retains all the sockets in the socket
pool of the sender.
@@ -14208,22 +14122,22 @@
CONNSOCKREQ or LOCALSOCKREQ errors, respectively, when those conditions
are not met.
- o lvar is an unsubscripted local variable name (lvn) which must be
+ * lvar is an unsubscripted local variable name (lvn) which must be
passed by reference indicated with a period (".") prefix. On
successful completion, the specified unsubscripted lvn contains the
handles of the received socket, in the order they were sent, delimited
with a vertical bar ("|"). GT.M places the sockets in the socket pool,
so the process can ATTACH them to an appropriate SOCKET device for
subsequent use.
- o If a numeric sourcepid is specified, GT.M matches the value against
+ * If a numeric sourcepid is specified, GT.M matches the value against
the process id ($JOB) of the process sending the sockets. On platforms
which do not implement the service (HP-UX), GT.M ignores the
targetpid. If the pids do not match, GT.M issues a PEERPIDMISMATCH
error and does not transfer the sockets.
- o If a numeric timeout is specified, GT.M sets $TEST to 1 if the
+ * If a numeric timeout is specified, GT.M sets $TEST to 1 if the
transfer completes within the specified time, and otherwise sets $TEST
to 0 and does not transfer the sockets.
- o If any handles are specified, GT.M assigns the provided handle names
+ * If any handles are specified, GT.M assigns the provided handle names
to the received sockets in the order in which they appear in the WRITE
/PASS of the sending process; empty items in the comma delimited
handle list act to preserve ordering. Where the list provides no
@@ -14249,6 +14163,86 @@
socket connection itself, the socket handle, and buffered socket data (if
any).
+ WRITE /TLS(option[,[timeout][,tlsid]])
+
+ SOCKET devices support encrypt connections with TLS using an encryption
+ plugin. GT.M ships with a reference implementation of the plugin which
+ uses OpenSSL and also supports TLS of replication stream. OpenSSL options
+ are controlled by a configuration file. The WRITE /TLS command activates
+ this feature for connected sockets. Because this functionality has a wide
+ variety of user stories (use cases) and has substantial complexity,
+ although the code appears robust, we are not confident that we have
+ exercised a sufficient breadth of use cases in testing. Also we may make
+ changes in future releases that are not entirely backwards compatible. We
+ encourage you to use with this facility in development and testing, and to
+ provide us with feedback. If you are an FIS customer and wish to use this
+ in production, please contact us beforehand to discuss your use case(s).
+
+ * option is "server" or "client" indicating which TLS role to assume or
+ "renegotiate" which is used by a server to request a new handshake to
+ reevaluate the client credentials. The server role requires a
+ certificate specified in the configuration file section with the label
+ matching tlsid. The client role may require a certificate depending on
+ the OpenSSL options. If the argument specifies a timeout, GT.M sets
+ $TEST to 1 if the command successfully completed or to 0 if it timed
+ out. $DEVICE provides status information in case of an error. ZSHOW
+ "D" includes "TLS" in the second line of the output for an encrypted
+ socket.
+ * Note that SOCKET device actions may produce the following errors:
+ TLSDLLOPEN, TLSINIT, TLSCONVSOCK, TLSHANDSHAKE, TLSCONNINFO,
+ TLSIOERROR, and TLSRENEGOTIATE.
+
+ The TLS plugin uses OpenSSL options in the configuration file specified
+ under the tls: label as the default for all TLS connections and under the
+ specific labels to override the defaults for corresponding connections.
+ GT.M recognizes the following for both sockets:
+
+ * The cipher-list option specifies which cryptographic algorithms to
+ use. The format of this option is described by the OpenSSL ciphers man
+ page. An empty string uses a default value of
+ "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH" for replication connections and
+ the OpenSSL default cipher list for socket connections.
+ * The ssl_options, documented in the man page for SSL_set_options,
+ modify the default behavior of OpenSSL. When specifying multiple
+ options, separate them with acolons (:) delimiter. The ssl-options
+ specified in a labeled section add to, or override, those specified at
+ the "tls" level. An exclamation mark ("!") preceding an option in a
+ labeled section disables any default for that option specified at the
+ tls: level; for example:
+
+ tls: {
+ ssl-options: "SSL_OP_CIPHER_SERVER_PREFERENCE";
+ mylabel: {
+ ssl-options: "!SSL_OP_CIPHER_SERVER_PREFERENCE";
+ };
+ }
+
+ * The verify-mode option specifies how OpenSSL verifies certificates. If
+ no verify-mode is specified, a socket connection defaults to
+ SSL_VERIFY_NONE. We have tested with SSL_VERIFY_PEER and
+ SSL_VERIFY_NONE See the man page for SSL_set_verify for details.
+ SSL_VERIFY_PEER has two additional flags which modify verification
+ only for the server role; when adding them to the option string, use
+ the colon (:) delimiter.
+ * A verify-depth option specified in a labeled section applies to
+ connections associated with that section.
+
+ When placing the private key for a certificate at the beginning of the
+ certificate file, you may omit the "key" item from the configuration file.
+ The format of the combined file is:
+
+ -----BEGIN RSA PRIVATE KEY-----
+ [encoded key]
+ -----END RSA PRIVATE KEY-----
+ [empty line]
+ -----BEGIN CERTIFICATE-----
+ [encoded certificate]
+ -----END CERTIFICATE-----
+ [empty line]
+
+ GT.M buffers WRITEs to TLS enabled sockets until a subsequent USE :FLUSH,
+ WRITE !, WRITE #, or an internal 400 millisecond timer expires.
+
3 Socket_Device_Operation
Socket Device Operation
@@ -14971,7 +14965,6 @@
GTM>file1="foo.txt"
GTM>open file1:newversion:recordsize=5000
-
GTM>
This example creates a new version of sequential file foo.txtwith
@@ -15166,6 +15159,10 @@
REWIND positions the file pointer of a sequential disk.
+ When $PRINCIPAL identifies a device that supports REWIND, the REWIND or
+ INREWIND device parameters perform a REWIND of the input and OUTREWIND
+ performs a REWIND of the output.
+
By default, OPEN does not REWIND.
Example:
@@ -15954,15 +15951,12 @@
Example:
GTM>set tcp="seerv" open tcp:(listen="6321:TCP":attach="serv")::"SOCKET"
-
GTM>zshow "D"
/dev/pts/9 OPEN TERMINAL NOPAST NOESCA NOREADS TYPE WIDTH=80 LENG=24
seerv OPEN SOCKET TOTAL=1 CURRENT=0
SOCKET[0]=serv DESC=3 LISTENING PASSIVE NOTRAP PORT=6321
ZDELAY ZBFSIZE=1024 ZIBFSIZE=87380 NODELIMITER
-
GTM>set tcp="seerv" o tcp:(listen="6322:TCP":attach="serv2")::"SOCKET"
-
GTM>zshow "D"
/dev/pts/9 OPEN TERMINAL NOPAST NOESCA NOREADS TYPE WIDTH=80 LENG=24
seerv OPEN SOCKET TOTAL=2 CURRENT=1
@@ -15977,7 +15971,6 @@
The following command moves the "serv" socket to the "socketpool" device.
GTM>use tcp:detach="serv"
-
GTM>use 0 zshow "D"
/dev/pts/9 OPEN TERMINAL NOPAST NOESCA NOREADS TYPE WIDTH=80 LENG=24
seerv OPEN SOCKET TOTAL=1 CURRENT=0
@@ -16346,9 +16339,7 @@
Example:
GTM>set tcp="seerv" open tcp:(listen="6321:TCP":attach="serv")::"SOCKET"
-
GTM>use tcp:listen="6322:TCP"
-
GTM>use 0 zshow "D"
/dev/pts/9 OPEN TERMINAL NOPAST NOESCA NOREADS TYPE WIDTH=80 LENG=24
seerv OPEN SOCKET TOTAL=2 CURRENT=1
@@ -17861,7 +17852,6 @@
#include <stdio.h>
#include <string.h>
#include "gtmxc_types.h"
-
void gtm_pre_alloc_a (int count, char *arg_prealloca)
{
strcpy(arg_prealloca, "New Message");
@@ -17953,21 +17943,15 @@
% cat /usr/joe/callback.xc
/usr/lib/callback.sl
init: void init_callbacks(I:gtm_pointertofunc_t, I:gtm_pointertofunc_t)
-
% gtm
GTM> do &.init(4,5)
GTM>
-
% cat /usr/joe/callback.c
#include <stdio.h>
#include <stdlib.h>
-
#include "gtmxc_types.h"
-
void* (*malloc_fn)(int);
-
void (*free_fn)(void*);
-
void init_callbacks(int count, void* (*m)(int), void (*f)(void*))
{
malloc_fn = m;
@@ -18817,7 +18801,6 @@
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
};
-
long
gtm_ac_xform (in, level, out, outlen)
gtm_descriptor *in; /* the input string */
@@ -18881,7 +18864,6 @@
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
};
-
long gtm_ac_xback (in, level, out, outlen)
gtm_descriptor *in; /* the input string */
int level; /* the subscript level */
@@ -18958,7 +18940,6 @@
Example:
#include "gtm_descript.h"
#define MYAPP_WRONGVERSION 20406080 /* User condition */
-
gtm_ac_verify (type, ver)
unsigned char type, ver;
{
@@ -19028,7 +19009,6 @@
Example:
GTM>kill ^G
-
GTM>write $select($$set^%GBLDEF("^G",0,3):"ok",1:"failed")
ok
GTM>
@@ -19277,7 +19257,6 @@
compile-time error with the message:
S =B+C ^-----
-
At column 4, line 7, source module ADD2
Variable expected in this context
@@ -20044,3 +20023,20 @@
each KILL command. GT.M does not check nodes in sub-trees to see whether
they have matching triggers.
+3 Accessing_Xecute_Source_Code
+ Accessing Xecute Source Code
+
+ ZPRINT/$TEXT()/ZBREAK recognize both a runtime-disambiguator, delimited
+ with a hash-sign (#), and a region-disambiguator, delimited by a slash(/);
+ previously they supported only the runtime-disambiguator. ZPRINT and
+ ZBREAK treat a trigger-not-found case as a TRIGNAMENF error, while $TEXT()
+ returns the empty string. When their argument contains a
+ region-disambiguator, these features ignore a null runtime-disambiguator.
+ When their argument does not contain a region-disambiguator, these
+ features act as if runtime-disambiguator is specified, even if it has an
+ empty value. When an argument specifies both runtime-disambiguator and
+ region-disambiguator and the runtime-disambiguator identifies a trigger
+ loaded from a region different from the specified region, or the
+ region-disambiguator identifies a region which holds a trigger that is not
+ mapped by $ZGBLDIR, these features treat the trigger as not found.
+
diff --git a/sr_port/mupip.hlp b/sr_port/mupip.hlp
index ae174d9..2516519 100644
--- a/sr_port/mupip.hlp
+++ b/sr_port/mupip.hlp
@@ -546,7 +546,6 @@
$ mupip backup -database -noonline "*" bkup
DB file /home/gtmnode1/gtmuser1/mumps.dat backed up in file bkup/mumps.dat
Transactions up to 0x00000000000F42C3 are backed up.
-
BACKUP COMPLETED.
This command creates a disk-to-disk backup copy of all regions of the
@@ -572,7 +571,6 @@
$ mupip backup -online DEFAULT bkup
DB file /gtmnode1/gtmuser1/mumps.dat backed up in file bkup/mumps.dat
Transactions up to 0x00000000483F807C are backed up.
-
BACKUP COMPLETED.
This command creates a backup copy of the DEFAULT region of the current
@@ -599,7 +597,6 @@
DB file /home/reptiles/mumps.dat incrementally backed up in file bkup1921onwards/mumps.dat
6 blocks saved.
Transactions from 0x00000000000F4351 to 0x00000000000F4352 are backed up.
-
BACKUP COMPLETED.
The first command sets a reference point and creates a backup copy of the
@@ -614,7 +611,6 @@
DB file /gtmnode1/gtmuser1/mumps.dat incrementally backed up in file bkup/mumps.dat
5 blocks saved.
Transactions from 0x0000000000000001 to 0x0000000000000003 are backed up.
-
BACKUP COMPLETED.
This command copies all in-use blocks of the DEFAULT region of the current
@@ -765,9 +761,7 @@
$ mupip endiancvt mumps.dat -outdb=mumps_cvt.dat
Converting database file mumps.dat from LITTLE endian to BIG endian on a LITTLE endian system
-
Converting to new file mumps_cvt.dat
-
Proceed [yes/no] ?
This command detects the endian format of mumps.dat and converts it to the
@@ -807,7 +801,9 @@
Specifies the number of GDS database blocks by which MUPIP should extend
the file. GDS files use additional blocks for bitmaps. MUPIP EXTEND adds
the specified number of blocks plus the bitmap blocks required as
- overhead. The format of the BLOCK qualifier is:
+ overhead.
+
+ The format of the BLOCK qualifier is:
-BLOCKS=data-blocks-to-add
@@ -1256,6 +1252,16 @@
Specifies that the reported key is for the Receive Pool of the instance
created by the current Global Directory.
+2 HASH
+ HASH
+
+ Uses a 128 bit hash based on the MurmurHash3 algorithm to provide provides
+ the hash of source files from the command line.
+
+ The format of the MUPIP HASH command is:
+
+ MUPIP HASH <file-names>
+
2 INTEG
INTEG
@@ -1394,9 +1400,6 @@
-BL[OCK]=block-number
- o Block numbers are displayed in an INTEG error report or by using DSE.
- o Incompatible with: -SUBSCRIPT and -TN_RESET
-
3 BRief
BRief
@@ -1712,7 +1715,6 @@
A sample output from the above command follows:
Type Blocks Records % Used Adjacent
-
Directory 2 5 4.150 NA
Index 18 1151 77.018 1
Data 1137 94189 97.894 1030
@@ -1733,9 +1735,7 @@
sample output from the above command follows:
No errors detected by integ.
-
Type Blocks Records % Used Adjacent
-
Directory 2 2 2.490 NA
Index 1 1 2.343 1
Data 1 3 6.738 1
@@ -1753,7 +1753,6 @@
No errors detected by fast integ.
Type Blocks Records % Used Adjacent
-
Directory 2 2 2.490 NA
Index 1 1 2.343 1
Data 1 NA NA NA
@@ -1771,16 +1770,12 @@
Level Blocks Records % Used Adjacent
1 1 1 2.343 NA
0 1 1 2.636 NA
-
Global variable ^Dinosaur
Level Blocks Records % Used Adjacent
1 1 6 8.398 1
0 6 500 83.902 6
-
No errors detected by integ.
-
Type Blocks Records % Used Adjacent
-
Directory 2 2 2.490 NA
Index 1 6 8.398 1
Data 6 500 83.902 6
@@ -1855,15 +1850,11 @@
The format of the LOAD command is:
L[OAD]
- [
- -BE[GIN]=integer
- -E[ND]=integer
- -FI[LLFACTOR]=integer
- -FO[RMAT]={GO|B[INARY]|Z[WR]]}
- -[O]NERROR={STOP|PROCEED|INTERACTIVE}
- -S[TDIN]
- ]
- file-name
+ [-BE[GIN]=integer -E[ND]=integer
+ -FI[LLFACTOR]=integer
+ -FO[RMAT]={GO|B[INARY]|Z[WR]]}
+ -[O]NERROR={STOP|PROCEED|INTERACTIVE}
+ -S[TDIN]] file-name
**Caution**
@@ -1871,21 +1862,21 @@
an application is running may result in an inconsistent application state
for the database.
- o MUPIP LOAD uses the Global Directory to determine which database files
+ * MUPIP LOAD uses the Global Directory to determine which database files
to use.
- o LOAD supports user collation routines.
- o LOAD takes its input from the file defined by the file-name
- o LOAD may take its input from a UNIX file on any device that supports
+ * LOAD supports user collation routines.
+ * LOAD takes its input from the file defined by the file-name
+ * LOAD may take its input from a UNIX file on any device that supports
such files.
- o MUPIP LOAD command considers a sequential file as encoded in UTF-8 if
+ * MUPIP LOAD command considers a sequential file as encoded in UTF-8 if
the environment variable gtm_chset is set to UTF-8. Ensure that MUPIP
EXTRACT commands and corresponding MUPIP LOAD commands execute with
the same setting for the environment variable gtm_chset.
- o For information on loading with an M "percent utility," refer to the
+ * For information on loading with an M "percent utility," refer to the
%GI section of the "M Utility Routines" chapter in GT.M Programmer's
Guide. LOAD is typically faster, but the %GI utility can be
customized.
- o Press <CTRL-C> to produce a status message from LOAD. Entering
+ * Press <CTRL-C> to produce a status message from LOAD. Entering
<CTRL-C> twice in quick succession stops LOAD. A LOAD that is manually
stopped or stops because of an internal error is incomplete and may
lack application level integrity, but will not adversely affect the
@@ -1911,8 +1902,11 @@
3 FOrmat
FOrmat
- Specifies the format of the input file. The format must match the actual
- format of the input file for LOAD to operate.
+ Specifies the format of the input file. If the format of the input file is
+ not specified, MUPIP LOAD automatically detects file format
+ (BINARY/ZWR/GO) based on the file header of the input file. If format is
+ specified, it must match the actual format of the input file for LOAD to
+ operate.
The format codes are:
@@ -1920,15 +1914,17 @@
B[INARY] - Binary format
Z[WR] - ZWRITE format
- o By default, LOAD uses FORMAT=ZWR.
- o -FORMAT=GO expects the data in record pairs. Each global node requires
+ * By default, LOAD uses FORMAT=ZWR.
+ * -FORMAT=GO expects the data in record pairs. Each global node requires
one record for the key and one for the data.
- o -FORMAT=ZWR expects the data for each global node in a single record.
- o -FORMAT=BINARY only applies to Greystone Database Structure (GDS)
+ * -FORMAT=ZWR expects the data for each global node in a single record.
+ * -FORMAT=BINARY only applies to Greystone Database Structure (GDS)
files. A BINARY format file loads significantly faster than a GO or
ZWR format file. -FORMAT=BINARY works with data in a proprietary
format. -FORMAT=BINARY has one header record, therefore LOAD
-FORMAT=BINARY starts active work with record number two (2).
+ * MUPIP LOAD detects file format (BINARY/ZWR/GO) based on the file
+ header of extract files from MUPIP EXTRACT, ^%GO and DSE.
3 BEgin
BEgin
@@ -1944,14 +1940,14 @@
Always consider the number of header records for choosing a -BEGIN point.
See FORMAT qualifier for more information.
- o For -FORMAT=GO input, the value is usually an odd number. As
+ * For -FORMAT=GO input, the value is usually an odd number. As
-FORMAT=BINARY requires important information from the header, this
type of load requires an intact file header regardless of the -BEGIN
value.
- o For -FORMAT = ZWR input, each record contains a complete set of
+ * For -FORMAT = ZWR input, each record contains a complete set of
reference and data information. The beginning values are not
restricted, except to allow two records for the header.
- o By default, LOAD starts at the beginning of the input file.
+ * By default, LOAD starts at the beginning of the input file.
3 End
End
@@ -1977,14 +1973,14 @@
-FI[LL_FACTOR]=integer
- o Reserves room and avoid unnecessary block split to accommodate the
+ * Reserves room and avoid unnecessary block split to accommodate the
forecasted growth in a global variable that may experience significant
rate of additions over a period.
- o Users having database performance issues or a high rate of database
+ * Users having database performance issues or a high rate of database
updates must examine the defined FILL_FACTORs. Unless the application
only uses uniform records, which is not typical for most applications,
FILL_FACTORs do not work precisely.
- o By default, LOAD uses -FILL_FACTOR=100 for maximum data density.
+ * By default, LOAD uses -FILL_FACTOR=100 for maximum data density.
**Note**
@@ -2001,9 +1997,9 @@
-[O]NERROR={STOP|PROCEED|INTERACTIVE}
- o STOP causes MUPIP LOAD to exit immediately.
- o PROCEED proceeds to the next record.
- o PROMPTS prompts to continue or stop.
+ * STOP causes MUPIP LOAD to exit immediately.
+ * PROCEED proceeds to the next record.
+ * PROMPTS prompts to continue or stop.
By default MUPIP LOAD exits on encountering an error.
@@ -2040,10 +2036,11 @@
output from the above command follows:
GT.M MUPIP EXTRACT
- 02-MAR-2011 18:25:47 ZWR
+ 02-MAR-2011 18:25:47 ZWR
Beginning LOAD at record number: 5
-
- LOAD TOTAL Key Cnt: 6 Max Subsc Len: 7 Max Data Len: 1
+ LOAD TOTAL Key Cnt: 6
+ Max Subsc Len: 7
+ Max Data Len: 1
Last LOAD record number: 10
Example:
@@ -2060,6 +2057,65 @@
These commands loads the extract file big.glo using -stdin.
+2 RCTLDUMP
+ RCTLDUMP
+
+ Reports information related to relinkctl files and their associated shared
+ memory segments. The format of the MUPIP RCTLDUMP command is:
+
+ MUPIP RCTLDUMP [dir1]
+
+ If the optional parameter dir1 is not specified, MUPIP RCTLDUMP dumps
+ information on all its active auto-relink-enabled directories (those with
+ with a *-suffix) identified by $gtmroutines. With a directory path
+ specified for dir1, MUPIP RCTLDUMP reports information on the one
+ directory. An example output follows. It lists the full path of the Object
+ directory; its corresponding relinkctl file name; the number of routines
+ currently loaded in this relinkctl file; the number of processes including
+ the reporting MUPIP process that have this Relinkctl file open; the shared
+ memory id and length of the Relinkctl shared memory segment; one or more
+ Rtnobj shared memory segment(s); and a listing of all the routine names
+ loaded in this file (lines starting with rec#...).
+
+ o The Rtnobj shared memory line : All the length fields are displayed in
+ hexadecimal. shmlen is the length of the allocated shared memory
+ segment in bytes. shmused is the length that is currently used.
+ shmfree is the length available for use. objlen is the total length of
+ all the objects currently loaded in this shared memory. As GT.M
+ allocates blocks of memory with sizes rounded-up to an integer power
+ of two bytes, shmused is always greater than objlen; for example with
+ an objlen of 0x1c0, the shmused is 0x200.
+ o Lines of the form rec#... indicate the record # in the relinkctl file.
+ Each relinkctl file can store a maximum of 1,000,000 records, i.e.,
+ the maximum number of routines in a directory with auto-relink enabled
+ is one million. Each record stores a routine name (rtnname:), the
+ current cycle # for this object file record entry (cycle:) which gets
+ bumped on every ZLINK or ZRUPDATE command, the hash of the object file
+ last loaded for this routine name (objhash:), the # of different
+ versions of object files loaded in the Rtnobj shared memory segments
+ with this routine name (numvers:), the total byte-length of the one or
+ more versions of object files currently loaded with this routine name
+ (objlen:), the total length used up in shared memory for these object
+ files where GT.M allocates each object file a rounded-up perfect
+ 2-power block of memory (shmlen:).
+
+ Given a relinkctl file name, one can find the corresponding directory path
+ using the Unix "strings" command on the Relinkctl file. For example,
+ "strings /tmp/gtm-relinkctl-f0938d18ab001a7ef09c2bfba946f002",
+ corresponding to the above MUPIP RCTLDUMP output example, would output
+ "/obj" the corresponding directory name.
+
+ Example:
+
+ $ mupip rctldump .
+ Object Directory : /obj
+ Relinkctl filename : /tmp/gtm-relinkctl-f0938d18ab001a7ef09c2bfba946f002
+ # of routines : 1
+ # of attached processes : 2
+ Relinkctl shared memory : shmid: 11534344 shmlen: 0x57c6000
+ Rtnobj shared memory # 1 : shmid: 11567113 shmlen: 0x100000 shmused: 0x200 shmfree: 0xffe00 objlen: 0x1c0
+ rec#1: rtnname: abcd cycle: 1 objhash: 0xedbfac8c7f7ca357 numvers: 1 objlen: 0x1c0 shmlen: 0x200
+
2 REORG
REORG
@@ -2140,11 +2196,8 @@
This command produces an output like the following:
Integ of region DEFAULT
-
No errors detected by integ.
-
Type Blocks Records % Used Adjacent
-
Directory 2 2 2.490 NA
Index 29 2528 95.999 1
Data 2500 10000 82.811 2499
@@ -2159,7 +2212,6 @@
At the GT.M prompt, execute the following command sequence:
GTM>for i=1:2:10000 s ^x(i)=$justify(i,200)
-
GTM>for i=2:2:10000 set ^x(i)=$justify(i,200)
Then, execute the following command:
@@ -2169,11 +2221,8 @@
This command produces an output like the following:
Integ of region DEFAULT
-
No errors detected by integ.
-
Type Blocks Records % Used Adjacent
-
Directory 2 2 2.490 NA
Index 153 3902 29.211 57
Data 3750 10000 55.856 1250
@@ -2500,6 +2549,7 @@
-F[ile]
-R[egion]=region-list
+ -RELinkctl [dir1]
If the RUNDOWN command does not specify either -File or -Region, it checks
all the IPC resources (shared memory) on the system and if they are
@@ -2515,6 +2565,24 @@
Incompatible with: -REGION
+3 Relinkctl
+ Relinkctl
+
+ Cleans up orphaned Relinkctl files. FIS strongly recommends avoiding
+ actions that tend to make such cleanup necessary - for example, kill -9 of
+ GT.M processes or ipcrm -m of active Relinkctl and/or Rtnobj shared memory
+ segments.
+
+ If the optional dir1 is not specified, MUPIP RUNDOWN -RELINKCTL examines
+ the environment variable $gtmroutines, attempts to verify and correct
+ their attach counts and runs down all its inactive auto-relink-enabled
+ directories (those with with a *-suffix). Alternatively, one can specify a
+ directory path for the parameter dir1 and MUPIP RUNDOWN -RELINKCTL treats
+ it as an auto-relink-enabled directory and runs down the resources
+ associated with this one directory. It prints a RLNKCTLRNDWNSUC message on
+ a successful rundown and a RLNKCTLRNDWNFL message on a failure (usually
+ because live processes are still accessing the Relinkctl file).
+
3 Region
Region
@@ -2799,7 +2867,6 @@
all regions.
$ mupip set -version=V4 -file mumps.dat
-
Database file mumps.dat now has desired DB format V4
This example sets the block format to V4 for all subsequent new blocks in
@@ -2808,7 +2875,6 @@
Example:
$ mupip set -version=v6 -file mumps.dat
-
Database file mumps.dat now has desired DB format V5
This example sets the block format to V6 for all subsequent new blocks in
@@ -2999,8 +3065,8 @@
Examines or loads trigger definitions. The format of the MUPIP TRIGGER
command is:
- TRIGGER {-TRIG[GERFILE]=<trigger_definitions_file> [-NOPR[OMPT]]|
- [-SELE[CT][=name-list|*][<select-output-file>]}
+ TRIGGER {-TRIG[GERFILE]=<trigger_definitions_file>
+ [-NOPR[OMPT]]|[-SELE[CT][=name-list|*][<select-output-file>]|-UPGRADE}
Before you run the MUPIP TRIGGER command:
@@ -3020,19 +3086,19 @@
-TRIG[GERFILE]=<trigger_definitions_file> [-NOPR[OMPT]]
- o
- o A MUPIP TRIGGER -TRIGGERFILE operation occurs within a transaction
+ *
+ * A MUPIP TRIGGER -TRIGGERFILE operation occurs within a transaction
boundary, therefore, if even one trigger from the trigger definition
file fails to parse correctly, MUPIP TRIGGER rolls back the entire
trigger definition file load. MUPIP TRIGGER operations have an
implicit timeout of zero (0), meaning the read must succeed on the
first try or the command will act as if it received no input.
- o MUPIP TRIGGER -TRIGGERFILE ignores blank lines and extra whitespace
+ * MUPIP TRIGGER -TRIGGERFILE ignores blank lines and extra whitespace
within lines. It treats lines with a semi-colon in the first position
as comments and ignores their content.
- o MUPIP TRIGGER compiles the XECUTE action string and rejects the load
+ * MUPIP TRIGGER compiles the XECUTE action string and rejects the load
if the compilation has errors.
- o Always specify the same value for the environment variable gtm_chset
+ * Always specify the same value for the environment variable gtm_chset
during loading and executing triggers. If you specify different values
of gtm_chset during loading and executing triggers, MUPIP TRIGGER
generates a run-time error (TRIGINVCHSET). GT.M does not prevent a
@@ -3042,13 +3108,17 @@
for all database updates, should be to ensure that you provide the
same value for gtm_chset during load compilation and run-time
compilation.
- o MUPIP TRIGGER replicate trigger definitions as logical actions from an
+ * MUPIP TRIGGER replicate trigger definitions as logical actions from an
originating/primary instance to a replicating/secondary instance based
on LGTRIG journal records. This permits the instances to have
different sets of triggers and differing database layouts (for
example, different # of regions, different block sizes, different
maximum-record-size, and so on).
- o Incompatible with: -SELECT
+ * MUPIP TRIGGER limits trigger expression source lines to 80 characters
+ including a trailing ellipsis to indicate there was more text, and
+ they also replace any non-graphic characters with a dot (.)
+
+ * Incompatible with: -SELECT
**Note**
@@ -3063,17 +3133,21 @@
produces a list of the current triggers for a comma-separate list of
global variables or trigger names. The format of the SELECT qualifier is:
- -SELE[CT][=name-list[*]|*][ <select-output-file>]
+ -SELE[CT][=name-list*][ <select-output-file>]
- 1. Name-list can include global names, delimited with a leading caret
+ * Name-list can include global names, delimited with a leading caret
(^), and/or trigger names (user-defined or auto-generated) with no
leading caret. You can specify a trailing asterisk(*) with either.
- 2. With no arguments specified, GT.M treats -SELECT as -SELECT="*" and
+ * With no arguments specified, GT.M treats -SELECT as -SELECT="*" and
extracts a list of all current triggers.
- 3. Optionally, you can specify a file name to redirect the output of the
+ * Optionally, you can specify a file name to redirect the output of the
command. If you do not specify a file name, MUPIP TRIGGER prompts for
a file name. If you respond with an empty string (RETURN), MUPIP
TRIGGER directs the output to STDOUT.
+ * MUPIP TRIGGER -SELECT displays all output including errors on STDOUT.
+ * For Trigger definition reporting operations, $ZTRIGGER("SELECT") and
+ MUPIP TRIGGER -SELECT, return a non-zero exit status when their
+ selection criteria encounter an error in the middle of the select.
**Note**
@@ -3094,6 +3168,28 @@
pound-sign (#) starts with a 0 (which is an impossible auto-generated
trigger name).
+ UPGRADE
+
+ Upgrades older trigger definitions into current format.
+
+ The format of the UPGRADE qualifier is:
+
+ -UPGRADE
+
+ If GT.M encounters an old trigger definition it produces a NEEDTRIGUPGRD
+ message. To preserve the possibility of a straightforward downgrade to an
+ earlier version, perform a select "*" action with MUPIP TRIGGER (or
+ $ZTRIGGER() and save the result. Note that TRIGGER -UPGRADE assumes that
+ the existing trigger definitions are properly defined; if the prior
+ release has produced defective triggers delete them with a wild-card
+ ("*"), do the MUPIP TRIGGER -UPGRADE and redefine the triggers in the new
+ release. In the event of a downgrade, delete "*" all triggers before the
+ downgrade and insert the saved version from before the upgrade. Attempting
+ to perform a MUPIP TRIGGER -UPGRADE on a database without write
+ authorization to the database produces a TRIGMODREGNOTRW error. The
+ -UPGRADE qualifier is not compatible with any other MUPIP TRIGGER
+ qualifier.
+
3 Examples
Examples
@@ -3136,7 +3232,7 @@
This command displays the triggers. A sample output looks like the
following:
- ;trigger name: ValidateAccount# cycle: 1
+ ;trigger name: ValidateAccount# cycle: 1
+^Acct("ID") -name=ValidateAccount -commands=S -xecute="Write ""Hello Earth!"""
To modify an existing trigger for global node ^Acct("ID"):
@@ -3159,7 +3255,7 @@
2. Specify trigger_mod.trg as the output file. This file contains entries
like the following:
- ;trigger name: ValidateAccount# cycle: 1
+ ;trigger name: ValidateAccount# cycle: 1
+^Acct("ID") -name=ValidateAccount -commands=S -xecute="Write ""Hello Earth!"""
3. Using your editor, open trigger_mod.trg and change + (plus) to -
@@ -3169,8 +3265,10 @@
new one in the same transaction (Atomic). The trigger_mod.trg file
should have entries like:
- ;trigger name: ValidateAccount# cycle: 1-^Acct("ID") -name=ValidateAccount -commands=Set -xecute="Write ""Hello Earth!"""
- ;trigger name: ValidateAccount#+^Acct("ID") -name=ValidateAccount -commands=Set -xecute="Write ""Hello Mars!"""
+ ;trigger name: ValidateAccount# cycle: 1
+ -^Acct("ID") -name=ValidateAccount -commands=Set -xecute="Write ""Hello Earth!"""
+ ;trigger name: ValidateAccount#
+ +^Acct("ID") -name=ValidateAccount -commands=Set -xecute="Write ""Hello Mars!"""
4. Execute a command like the following:
@@ -3200,7 +3298,7 @@
2. Specify trigger_delete.trg as the output file. This file contains
entries like the following:
- ;trigger name: ValidateAccount# cycle: 3
+ ;trigger name: ValidateAccount# cycle: 3
+^Acct("ID") -name=ValidateAccount -commands=S -xecute="Write ""Hello Mars!"""
3. Using your editor, change + (plus) to - (minus) for the trigger
@@ -3240,7 +3338,7 @@
3. Respond with an empty string (Press Enter). Confirm that the trigger
summary report contains an entry like the following:
- ;trigger name: ValidateAccount# cycle: 3
+ ;trigger name: ValidateAccount# cycle: 3
+^Acct("ID") -name=ValidateAccount -commands=S -xecute="Write ""Hello Mars!"""
4. Now, execute a command like the following:
@@ -4098,7 +4196,7 @@
To avoid broken transaction or lost transaction processing and instead
extract all journal records into one file, use the control qualifier
- -FENCES=NONE. FIS strongly recommended against using -FENCES=NONE if
+ -FENCES=NONE. FIS strongly recommended against using -FENCES=NONE if
-RECOVER/-ROLLBACK is also specified.
4 RECover
@@ -4377,13 +4475,11 @@
-------------------------------------------------------------------------------
SHOW output for journal file /home/jdoe/.fis-gtm/V6.0-000_x86/g/gtm.mjl
-------------------------------------------------------------------------------
-
Journal file name /home/jdoe/.fis-gtm/V6.0-000_x86/g/gtm.mjl
Journal file label GDSJNL23
Database file name /home/jdoe/.fis-gtm/V6.0-000_x86/g/gtm.dat
Prev journal file name /home/jdoe/.fis-gtm/V6.0-000_x86/g/gtm.mjl_2012310190106
Next journal file name
-
Before-image journal ENABLED
Journal file header size 65536 [0x00010000]
Virtual file size 2048 [0x00000800] blocks
@@ -4411,15 +4507,11 @@
Turn Around Point Time 0
Start Region Sequence Number 1 [0x0000000000000001]
End Region Sequence Number 1 [0x0000000000000001]
-
Process That Created the Journal File:
-
PID NODE USER TERM JPV_TIME
---------------------------------------------------------
0000006706 jdoe-laptop jdoe 0 2012/11/06 17:30:33
-
Process That First Opened the Journal File:
-
PID NODE USER TERM JPV_TIME
---------------------------------------------------------
0000006706 jdoe-laptop jdoe 0 2012/11/06 17:30:33
@@ -4438,7 +4530,6 @@
-------------------------------------------------------------------------------
SHOW output for journal file /home/jdoe/.fis-gtm/V6.0-000_x86/g/gtm.mjl
-------------------------------------------------------------------------------
-
Record type Count
----------------------
*BAD* 0
@@ -4473,7 +4564,6 @@
TZTRI 0
UZTRI 0
TRUNC 0
-
%GTM-S-JNLSUCCESS, Show successful
%GTM-S-JNLSUCCESS, Verify successful
%GTM-I-MUJNLSTAT, End processing at Tue Nov 6 17:42:21 2012
@@ -4482,7 +4572,6 @@
stored in the journal file header (the output is one long line).
$ mupip journal -show -backward mumps.mjl 2>&1 | grep hash
-
Journal file hash F226703EC502E975784
8EEC733E1C3CABE5AC146C60F922D0E7D7CB5E
2A37ABA005CE98D908B219249A0464F5BB622B72F5FDA
@@ -5667,6 +5756,7 @@
<soft tries period>, <alert time>, <heartbeat period>,
<max heartbeat wait>]
-instsecondary=<replicating instance name>
+ [-[no]jnlf[ileonly]]
-log=<log file name> [-log_interval=<integer>]
{-rootprimary|-propagateprimary} [{-updok|-updnotok}]
[-cmplvl=<compression level>]
@@ -5880,6 +5970,16 @@
This command starts the Source Server for the originating instance with
instance B as its replicating instance.
+ -[no]jnlfileonly
+
+ Forces the Source Server to read transactions from journal files instead
+ of journal pool shared memory. When combined with the SYNC_IO journal
+ option, this feature delays replication of transactions until their
+ journal records are hardened to disk. This may be useful when replicating
+ to a supplementary instance, as a crash and rollback on the primary could
+ otherwise necessitate a rollback of local updates on the receiving
+ instance. The default is -NOJNLFILEONLY.
+
-rootprimary
Assign the current instance as the originating instance. You can specify
@@ -6137,9 +6237,10 @@
-timeout=<timeout in seconds>
- Specifies the time (in seconds) the Source Server should wait before
- shutting down. If you do not specify -timeout, the default timeout period
- is 120 seconds. If you specify -timeout=0 , shutdown occurs immediately.
+ Specifies the time (in seconds) the shutdown command should wait before
+ signaling the Source Server to shut down. If you do not specify -timeout,
+ the default timeout period is 120 seconds. If you specify -timeout=0 ,
+ shutdown occurs immediately.
2 Activate_Passive_Source_Server
Activate Passive Source Server
@@ -6283,13 +6384,10 @@
Example:
$ mupip replic -source -checkhealth -inst=INSTB
-
Fri May 21 15:26:18 2010 : Initiating CHECKHEALTH operation on source server pid [15511] for secondary
instance name [INSTB]
PID 15511 Source server is alive in ACTIVE mode
-
$ mupip replic -source -checkhealth -inst=INSTB
-
Fri May 21 15:29:52 2010 : Initiating CHECKHEALTH operation on source server pid [0] for secondary
instance name [INSTB]
PID 0 Source server is NOT alive
@@ -7314,15 +7412,16 @@
Copyright 2014
- Fidelity Information Services, Inc. All rights reserved.
+ Fidelity National Information Services, Inc. and/or its subsidiaries. All
+ rights reserved.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or any
later version published by the Free Software Foundation; with no Invariant
Sections, no Front-Cover Texts and no Back-Cover Texts.
- GT.M(TM) is a trademark of Fidelity Information Services, Inc. Other
- trademarks are the property of their respective owners.
+ GT.M(TM) is a trademark of Fidelity National Information Services, Inc.
+ Other trademarks are the property of their respective owners.
This document contains a description of GT.M and the operating
instructions pertaining to the various functions that comprise the system.
@@ -7333,7 +7432,7 @@
**Note**
- This help file is a concise representation of revision V6.2-000 of the
+ This help file is a concise representation of revision V6.2-001 of the
UNIX Administration and Operations Guide. To obtain a copy of the current
revision, go to www.fis-gtm.com and then click on the User Documentation
tab.
diff --git a/sr_port/mupip_cvtgbl.h b/sr_port/mupip_cvtgbl.h
index 9f4deb8..453ae07 100644
--- a/sr_port/mupip_cvtgbl.h
+++ b/sr_port/mupip_cvtgbl.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -13,5 +13,7 @@
#define MUPIP_CVTGBL_INCLUDED
void mupip_cvtgbl(void);
-
+#ifdef UNIX
+int get_file_format(char **line1_ptr, char **line2_ptr, int *line1_len, int *line2_len);
+#endif
#endif /* MUPIP_CVTGBL_INCLUDED */
diff --git a/sr_port/mupip_reorg.c b/sr_port/mupip_reorg.c
index 227ffa8..9a71307 100644
--- a/sr_port/mupip_reorg.c
+++ b/sr_port/mupip_reorg.c
@@ -1,6 +1,6 @@
/***************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -82,8 +82,6 @@ error_def(ERR_NOEXCLUDE);
error_def(ERR_REORGCTRLY);
error_def(ERR_REORGINC);
-GTMTRIG_ONLY(LITREF mval literal_hasht;)
-
GBLREF bool mu_ctrlc_occurred;
GBLREF bool mu_ctrly_occurred;
GBLREF boolean_t mu_reorg_process;
@@ -297,19 +295,19 @@ void mupip_reorg(void)
if (truncate)
{ /* Reorg ^#t in this region to move it out of the way. */
SET_GVTARGET_TO_HASHT_GBL(cs_addrs); /* sets gv_target */
+ inctn_opcode = inctn_invalid_op; /* needed for INITIAL_HASHT_ROOT_SEARCH */
+ INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED; /* sets gv_target->root */
+ DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE);
hasht_gl.next = NULL;
hasht_gl.reg = gv_cur_region;
hasht_gl.gvt = gv_target;
- inctn_opcode = inctn_invalid_op; /* needed for *ROOT_SEARCH */
- INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED; /* sets gv_target->root */
- DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE);
if (0 != gv_target->root)
{
util_out_print(" ", FLUSH);
util_out_print("Global: !AD (region !AD)", FLUSH,
GNAME(&hasht_gl).len, GNAME(&hasht_gl).addr,
REG_LEN_STR(gv_cur_region));
- reorg_gv_target->gvname.var_name = literal_hasht.str;
+ reorg_gv_target->gvname.var_name = gv_target->gvname.var_name;
cur_success = mu_reorg(&hasht_gl, &exclude_gl_head, &resume,
index_fill_factor, data_fill_factor, reorg_op);
reorg_success &= cur_success;
diff --git a/sr_port/mupip_set_journal_parse.c b/sr_port/mupip_set_journal_parse.c
index 58272c2..18008aa 100644
--- a/sr_port/mupip_set_journal_parse.c
+++ b/sr_port/mupip_set_journal_parse.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -91,7 +91,8 @@ boolean_t mupip_set_journal_parse(set_jnl_options *jnl_options, jnl_create_info
return FALSE;
if ((jnl_info->alloc < JNL_ALLOC_MIN) || (jnl_info->alloc > JNL_ALLOC_MAX))
{
- gtm_putmsg(VARLSTCNT(5) ERR_JNLINVALLOC, 3, jnl_info->alloc, JNL_ALLOC_MIN, JNL_ALLOC_MAX);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_JNLINVALLOC, 3,
+ jnl_info->alloc, JNL_ALLOC_MIN, JNL_ALLOC_MAX);
return FALSE;
}
}
@@ -101,7 +102,7 @@ boolean_t mupip_set_journal_parse(set_jnl_options *jnl_options, jnl_create_info
return FALSE;
if (alignsize < JNL_MIN_ALIGNSIZE)
{
- gtm_putmsg(VARLSTCNT(4) ERR_JNLMINALIGN, 2, alignsize, JNL_MIN_ALIGNSIZE);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_JNLMINALIGN, 2, alignsize, JNL_MIN_ALIGNSIZE);
return FALSE;
}
if (alignsize > JNL_MAX_ALIGNSIZE)
@@ -109,11 +110,12 @@ boolean_t mupip_set_journal_parse(set_jnl_options *jnl_options, jnl_create_info
util_out_print("ALIGNSIZE cannot be greater than !UL", TRUE, JNL_MAX_ALIGNSIZE);
return FALSE;
}
- LOG2_OF_INTEGER(alignsize, bits_of_alignsize);
+ assert(4 == SIZEOF(alignsize)); /* so we can use the 32bit version of ceil_log2 */
+ bits_of_alignsize = ceil_log2_32bit(alignsize);
if ((1 << bits_of_alignsize) != alignsize)
{
alignsize = 1 << bits_of_alignsize; /* This will make alignsize power of two */
- gtm_putmsg(VARLSTCNT(3) ERR_JNLALIGNSZCHG, 1, alignsize);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_JNLALIGNSZCHG, 1, alignsize);
}
jnl_info->alignsize = alignsize * DISK_BLOCK_SIZE;
}
@@ -124,7 +126,7 @@ boolean_t mupip_set_journal_parse(set_jnl_options *jnl_options, jnl_create_info
if (JNL_AUTOSWITCHLIMIT_MIN > jnl_info->autoswitchlimit
|| JNL_ALLOC_MAX < jnl_info->autoswitchlimit)
{
- gtm_putmsg(VARLSTCNT(5) ERR_JNLINVSWITCHLMT, 3, jnl_info->autoswitchlimit,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_JNLINVSWITCHLMT, 3, jnl_info->autoswitchlimit,
JNL_AUTOSWITCHLIMIT_MIN, JNL_ALLOC_MAX);
return FALSE;
}
@@ -163,7 +165,7 @@ boolean_t mupip_set_journal_parse(set_jnl_options *jnl_options, jnl_create_info
}
if (jnl_info->extend > JNL_EXTEND_MAX)
{
- gtm_putmsg(VARLSTCNT(4) ERR_JNLINVEXT, 2, jnl_info->extend, JNL_EXTEND_MAX);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_JNLINVEXT, 2, jnl_info->extend, JNL_EXTEND_MAX);
return FALSE;
}
}
diff --git a/sr_port/mv_stent.h b/sr_port/mv_stent.h
index cf1a26c..adb3e5b 100644
--- a/sr_port/mv_stent.h
+++ b/sr_port/mv_stent.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -91,6 +91,7 @@ typedef struct
mval *ztvalue_save; /* Save it once per trigger level */
mstr *ztname_save;
mval *ztdata_save;
+ mval *ztdelim_save;
mval *ztoldval_save;
mval *ztriggerop_save;
mval *ztupdate_save;
@@ -237,24 +238,24 @@ void push_stck(void* val, int val_size, void** addr, int mvst_stck_type);
#define MVST_LAST 18 /* update this, mvs_size and mvs_save in mtables.c, and switches in unw_mv_ent.c,
* stp_gcol_src.h, and get_ret_targ.c when adding a new MVST type */
-/* Variation of ROUND_UP2 macro that doesn't have the checking that generates a GTMASSERT. This is necessary because the
- * MV_SIZE macro is used in a static table initializer so cannot have executable (non-constant) code in it
+/* Variation of ROUND_UP2 macro that doesn't have the checking that generates an assertpro. This is necessary because
+ * the MV_SIZE macro is used in a static table initializer so cannot have executable (non-constant) code in it
*/
#define ROUND_UP2_NOCHECK(VALUE,MODULUS) (((VALUE) + ((MODULUS) - 1)) & ~((MODULUS) - 1))
#define MV_SIZE(X) \
ROUND_UP2_NOCHECK(((SIZEOF(*mv_chain) - SIZEOF(mv_chain->mv_st_cont) + SIZEOF(mv_chain->mv_st_cont.X))), NATIVE_WSIZE)
-#define PUSH_MV_STENT(T) (((msp -= mvs_size[T]) <= stackwarn) ? \
- ((msp <= stacktop) ? (msp += mvs_size[T]/* fix stack */, rts_error(VARLSTCNT(1) ERR_STACKOFLOW)) : \
- rts_error(VARLSTCNT(1) ERR_STACKCRIT)) : \
- (((mv_stent *)msp)->mv_st_type = T , \
- ((mv_stent *)msp)->mv_st_next = (int)((unsigned char *) mv_chain - msp)), \
+#define PUSH_MV_STENT(T) (((msp -= mvs_size[T]) <= stackwarn) ? \
+ ((msp <= stacktop) ? (msp += mvs_size[T]/* fix stack */, rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKOFLOW)) : \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKCRIT)) : \
+ (((mv_stent *)msp)->mv_st_type = T , \
+ ((mv_stent *)msp)->mv_st_next = (int)((unsigned char *) mv_chain - msp)), \
mv_chain = (mv_stent *)msp)
#define PUSH_MV_STCK(size, st_type) (((msp -= ROUND_UP(mvs_size[st_type] + (size), SIZEOF(char *))) <= stackwarn) ? \
((msp <= stacktop) ? (msp += ROUND_UP(mvs_size[st_type] + (size), SIZEOF(char *)) /* fix stack */, \
- rts_error(VARLSTCNT(1) ERR_STACKOFLOW)) : \
- rts_error(VARLSTCNT(1) ERR_STACKCRIT)) : \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKOFLOW)) : \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKCRIT)) : \
(((mv_stent *)msp)->mv_st_type = st_type, \
((mv_stent *)msp)->mv_st_next = (int)((unsigned char *) mv_chain - msp)), \
mv_chain = (mv_stent *)msp)
diff --git a/sr_port/obj_file.h b/sr_port/obj_file.h
index 33606c4..f0d5c24 100644
--- a/sr_port/obj_file.h
+++ b/sr_port/obj_file.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -14,21 +14,9 @@
#include <obj_filesp.h>
-void emit_immed(char *source, uint4 size);
-void emit_literals(void);
-void emit_linkages(void);
-int literal_offset(UINTPTR_T offset);
-int4 find_linkage(mstr* name);
-void drop_object_file(void);
-UNIX_ONLY(void close_object_file(void);)
-VMS_ONLY(void close_object_file(rhdtyp *rhead);)
-void create_object_file(rhdtyp *rhead);
-void obj_init(void);
-DEBUG_ONLY(int output_symbol_size(void);)
-
#define OUTPUT_SYMBOL_SIZE (SIZEOF(int4) + sym_table_size)
-
#define PADCHARS "PADDING PADDING"
+#define RENAME_TMP_OBJECT_FILE(FNAME) rename_tmp_object_file(FNAME)
#ifndef SECTION_ALIGN_BOUNDARY
#if defined(GTM64)
# define SECTION_ALIGN_BOUNDARY 16
@@ -37,7 +25,6 @@ DEBUG_ONLY(int output_symbol_size(void);)
#endif /* GTM64 */
#endif /* SECTION_ALIGN_BOUNDARY */
#define OBJECT_SIZE_ALIGNMENT 16
-
#ifdef DEBUG
#define MAX_CODE_COUNT 10000
/* This structure holds the size of the code generated for every triple */
@@ -48,4 +35,21 @@ struct inst_count
};
#endif /* DEBUG */
+/* Prototypes */
+#ifdef UNIX
+int mk_tmp_object_file(const char *object_fname, int object_fname_len);
+void rename_tmp_object_file(const char *object_fname);
+void init_object_file_name(void);
+void finish_object_file(void);
+#endif
+void emit_immed(char *source, uint4 size);
+void emit_literals(void);
+void emit_linkages(void);
+int literal_offset(UINTPTR_T offset);
+int4 find_linkage(mstr* name);
+void drop_object_file(void);
+void create_object_file(rhdtyp *rhead);
+void obj_init(void);
+VMS_ONLY(void close_object_file(rhdtyp *rhead);)
+DEBUG_ONLY(int output_symbol_size(void);)
#endif /* OBJ_FILE_INCLUDED */
diff --git a/sr_port/objlabel.h b/sr_port/objlabel.h
index 18e0a25..84abe5f 100644
--- a/sr_port/objlabel.h
+++ b/sr_port/objlabel.h
@@ -33,7 +33,7 @@
* Note that OBJ_UNIX_LABEL and OBJ_PLATFORM_LABEL should not exceed 255.
*/
-#define OBJ_UNIX_LABEL 28 /* When changed, be sure to zero the platform specific numbers below (if any non-0) */
+#define OBJ_UNIX_LABEL 29 /* When changed, be sure to zero the platform specific numbers below (if any non-0) */
#if defined(__osf__)
# define OBJ_PLATFORM_LABEL 0 /* Alpha/Tru64 */
diff --git a/sr_port/one_job_param.c b/sr_port/one_job_param.c
index 9bdf0be..8238828 100644
--- a/sr_port/one_job_param.c
+++ b/sr_port/one_job_param.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -43,9 +43,9 @@ const static readonly unsigned char job_param_index[27] =
{
/* A(2) B(0) C(2) D(4) E(2) F(0) G(2) H(0) I(4) J(0) K(0) L(2) M(0) */
0, 2, 2, 4, 8, 10, 10, 12, 12, 16, 16, 16, 18,
- /* N(6) O(2) P(4) Q(0) R(0) S(6) T(0) U(0) V(0) W(0) X(0) Y(0) Z(0) */
- 18, 24, 26, 30, 30, 30, 37, 37, 37, 37, 37, 37, 37,
- 37
+ /* N(6) O(2) P(6) Q(0) R(0) S(6) T(0) U(0) V(0) W(0) X(0) Y(0) Z(0) */
+ 18, 24, 26, 32, 32, 32, 39, 39, 39, 39, 39, 39, 39,
+ 39
};
#else
const static readonly unsigned char job_param_index[27] =
diff --git a/sr_port/op_exp.c b/sr_port/op_exp.c
index 3ab2c46..0e41515 100644
--- a/sr_port/op_exp.c
+++ b/sr_port/op_exp.c
@@ -28,6 +28,7 @@ LITREF mval literal_zero;
STATICFNDEF void op_exp_flgchk(mval *mv);
+error_def(ERR_DIVZERO);
error_def(ERR_NEGFRACPWR);
error_def(ERR_NUMOFLOW);
@@ -39,47 +40,38 @@ void op_exp(mval *u, mval* v, mval *p)
int im0, im1, ie, i, j, j1;
boolean_t fraction = FALSE, in = FALSE;
boolean_t neg = FALSE, even = TRUE;
- mval w, zmv;
- int4 n, n1;
+ mval w, zmv;
+ int4 n, n1;
int4 z1_rnd, z2_rnd, pten;
u1_p = &u1;
memcpy(u1_p, u, SIZEOF(mval));
MV_FORCE_NUM(u1_p);
MV_FORCE_NUM(v);
- if ((0 == v->m[1]) && (0 == v->m[0]))
- { /* 0**0 = 1 */
- *p = literal_one;
- return;
- }
+ n = v->m[1];
if (0 != (v->mvtype & MV_INT))
{ /* Integer-ish exponent (could have up to 3 digits to right of decimal pt) */
- n = v->m[1];
if (0 == n)
- { /* anything**0 = 1 where anything != 0 */
+ { /* anything**0 = 1 */
*p = literal_one;
return;
}
if (0 != (u1_p->mvtype & MV_INT))
{ /* Integer-ish base */
if (0 == u1_p->m[1])
- { /* 0**anything = 0 */
- *p = literal_zero;
- return;
+ {
+ if (0 <= n)
+ { /* 0**anything non-negative = 0 */
+ *p = literal_zero;
+ return;
+ }
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DIVZERO);
}
- } else if ((0 == u1_p->m[1]) && (0 == u1_p->m[0]))
- { /* 0**anything = 0 */
- *p = literal_zero;
- return;
- }
+ } else
+ assert((0 != u1_p->m[1]) || (0 != u1_p->m[0]));
n1 = n / MV_BIAS;
if ((n1 * MV_BIAS) == n)
{ /* True non-fractional exponent */
- if (0 == v->m[1])
- { /* Duplicate of check on line 58? */
- *p = literal_one;
- return;
- }
if (0 > n1)
{ /* Create inverse due to negative exponent */
op_div((mval *)&literal_one, u1_p, &w);
@@ -102,7 +94,7 @@ void op_exp(mval *u, mval* v, mval *p)
{ /* Have non-integer exponent (has fractional component) */
if (0 != (u1_p->mvtype & MV_INT))
{ /* Base is integer-ish */
- if (0 > u1_p->m[1])
+ if (0 > u1_p->m[1])
{ /* Base is negative, invalid exponent expression */
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NEGFRACPWR);
return;
@@ -115,31 +107,35 @@ void op_exp(mval *u, mval* v, mval *p)
return;
}
}
- }
- } else
+ }
+ } else
{ /* Exponent NOT integer-ish */
- if (0 != (u1_p->mvtype & MV_INT))
- { /* Base is integer-ish */
- if (0 > u1_p->m[1])
- { /* Base is negative - make positive but record was negative */
- u1_p->m[1] = -u1_p->m[1];
- neg = TRUE;
- }
+ assert((0 != v->m[1]) || (0 != v->m[0]));
+ if (0 != (u1_p->mvtype & MV_INT))
+ { /* Base is integer-ish */
if (0 == u1_p->m[1])
- { /* 0**anything is 0 */
- *p = literal_zero;
- return;
+ {
+ if (!v->sgn)
+ { /* 0**anything non-negative = 0 */
+ *p = literal_zero;
+ return;
+ }
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DIVZERO);
}
- } else if (u1_p->sgn)
- { /* Base is NOT integer-ish and is negative - clear sign and record with flag */
- u1_p->sgn = 0;
- neg = TRUE;
- if ((0 == u1_p->m[1]) && (0 == u1_p->m[0]))
- { /* 0**anything is zero */
- *p = literal_zero;
- return;
+ if (0 > u1_p->m[1])
+ { /* Base is negative - make positive but record was negative */
+ u1_p->m[1] = -u1_p->m[1];
+ neg = TRUE;
}
- }
+ } else
+ { /* Base is NOT integer-ish */
+ assert((0 != u1_p->m[1]) || (0 != u1_p->m[0]));
+ if (u1_p->sgn)
+ { /* and is negative - clear sign and record with flag */
+ u1_p->sgn = 0;
+ neg = TRUE;
+ }
+ }
if (NUM_DEC_DG_2L > (ie = (v->e - MV_XBIAS))) /* Note assignment */
{ /* Need to determine 2 things:
* 1. Whether this exponent has a fractional part (vs just being large)
@@ -208,7 +204,7 @@ void op_exp(mval *u, mval* v, mval *p)
if (HUGE_VAL == z) /* Infinity return value check */
{
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NUMOFLOW);
- return;
+ return;
}
# endif
p->sgn = (neg && !even); /* Positive numbers only from here on out */
@@ -252,14 +248,14 @@ void op_exp(mval *u, mval* v, mval *p)
* Could add checks for zero/infinity here to avoid lengthy (300ish iterations) while loops below.
*/
n = 0;
- while (1e16 <= z)
+ while (1e16 <= z)
{
- n += 5;
+ n += 5;
z *= 1e-5;
}
- while (1e1 > z)
+ while (1e1 > z)
{
- n -= 5;
+ n -= 5;
z *= 1e5;
}
while (1e9 <= z)
diff --git a/sr_port/op_fntext.c b/sr_port/op_fntext.c
index 4874294..cba475c 100644
--- a/sr_port/op_fntext.c
+++ b/sr_port/op_fntext.c
@@ -20,14 +20,20 @@
#include "op.h"
#include "stringpool.h"
#include "compiler.h"
+#include "min_max.h"
#ifdef GTM_TRIGGER
# include "gtm_trigger_trc.h"
+#else
+# define DBGIFTRIGR(x)
+# define DBGTRIGR(x)
+# define DBGTRIGR_ONLY(x)
#endif
#include "stack_frame.h"
GBLREF spdesc stringpool;
GBLREF stack_frame *frame_pointer;
-GBLREF uint4 dollar_tlevel;
+GTMTRIG_ONLY(GBLREF uint4 dollar_tlevel);
+DBGTRIGR_ONLY(GBLREF unsigned int t_tries;)
error_def(ERR_ZLINKFILE);
error_def(ERR_ZLMODULE);
@@ -37,13 +43,14 @@ void op_fntext(mval *label, int int_exp, mval *rtn, mval *ret)
/* int_exp contains label offset or line number to reference */
/* ret is used to return the correct string to caller */
{
- char *cp;
- int i, lbl, letter;
- mval *temp_rtn, temp_mval;
- mstr *sld;
- uint4 stat;
- rhdtyp *rtn_vector;
- boolean_t is_trigger, current_rtn = FALSE;
+ char *cp;
+ int i, lbl, letter;
+ mval *temp_rtn, temp_mval;
+ mstr *sld;
+ uint4 stat;
+ rhdtyp *rtn_vector;
+ boolean_t current_rtn = FALSE;
+ GTMTRIG_ONLY(boolean_t is_trigger;)
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
@@ -58,19 +65,20 @@ void op_fntext(mval *label, int int_exp, mval *rtn, mval *ret)
sld = (mstr *)NULL;
ESTABLISH(fntext_ch); /* to swallow errors and permit an emptystring result */
GTMTRIG_ONLY(IS_TRIGGER_RTN(&temp_rtn->str, is_trigger));
+ DBGIFTRIGR((stderr, "op_fntext: entering $tlevel=%d $t_tries=%d\n", dollar_tlevel, t_tries));
if ((0 == int_exp) && ((0 == label->str.len) || (0 == *label->str.addr)))
stat = ZEROLINE;
else
{
#ifdef GTM_TRIGGER
+ DBGIFTRIGR((stderr, "op_fntext: fetching $TEXT() source for a trigger\n"));
if (is_trigger)
{
- DBGTRIGR((stderr, "op_fntext: fetching $TEXT() source for a trigger\n"));
assert(0 == TREF(op_fntext_tlevel));
TREF(op_fntext_tlevel) = 1 + dollar_tlevel;
}
#endif
- stat = get_src_line(temp_rtn, label, int_exp, &sld, VERIFY);
+ stat = get_src_line(temp_rtn, label, int_exp, &sld, &rtn_vector);
GTMTRIG_ONLY(TREF(op_fntext_tlevel) = 0);
}
if (0 == (stat & (CHECKSUMFAIL | NEGATIVELINE)))
@@ -128,5 +136,6 @@ void op_fntext(mval *label, int int_exp, mval *rtn, mval *ret)
ret->str.addr = (char *)stringpool.free;
stringpool.free += ret->str.len;
}
+ DBGIFTRIGR((stderr, "op_fntext: exiting\n\n"));
return;
}
diff --git a/sr_port/op_fnview.c b/sr_port/op_fnview.c
index 16d4c4a..ff34057 100644
--- a/sr_port/op_fnview.c
+++ b/sr_port/op_fnview.c
@@ -86,13 +86,15 @@ LITREF mval literal_zero;
LITREF mval literal_one;
LITREF mval literal_null;
-#define MM_RES "MM"
-#define BG_RES "BG"
-#define CM_RES "CM"
-#define USR_RES "USR"
-#define GTM_BOOL_RES "GT.M Boolean short-circuit"
-#define STD_BOOL_RES "Standard Boolean evaluation side effects"
-#define WRN_BOOL_RES "Standard Boolean with side-effect warning"
+#define MM_RES "MM"
+#define BG_RES "BG"
+#define CM_RES "CM"
+#define USR_RES "USR"
+#define GTM_BOOL_RES "GT.M Boolean short-circuit"
+#define STD_BOOL_RES "Standard Boolean evaluation side effects"
+#define WRN_BOOL_RES "Standard Boolean with side-effect warning"
+#define STATS_MAX_DIGITS MAX_DIGITS_IN_INT8
+#define STATS_KEYWD_SIZE (3 + 1 + 1) /* 3 character mnemonic, colon and comma */
STATICFNDCL unsigned char *gvn2gds(mval *gvn, gv_key *gvkey, int act);
@@ -110,6 +112,16 @@ STATICFNDCL unsigned char *gvn2gds(mval *gvn, gv_key *gvkey, int act);
stringpool.free += keylen; \
}
+#define STATS_PUT_PARM(TXT, CNTR, BASE) \
+{ \
+ MEMCPY_LIT(stringpool.free, TXT); \
+ stringpool.free += STR_LIT_LEN(TXT); \
+ *stringpool.free++ = ':'; \
+ stringpool.free = i2ascl(stringpool.free, BASE.CNTR); \
+ *stringpool.free++ = ','; \
+ assert(stringpool.free <= stringpool.top); \
+}
+
void op_fnview(UNIX_ONLY_COMMA(int numarg) mval *dst, ...)
{
VMS_ONLY(int numarg;)
@@ -337,18 +349,42 @@ void op_fnview(UNIX_ONLY_COMMA(int numarg) mval *dst, ...)
s2pool(&tmpstr);
dst->str = tmpstr;
break;
-#ifdef DEBUG
+ case VTK_POOLLIMIT:
+ assert(NULL != gd_header); /* view_arg_convert would have done this for VTK_POOLLIMIT */
+ reg = parmblk.gv_ptr;
+ if (!reg->open)
+ gv_init_reg(reg);
+ csa = &FILE_INFO(reg)->s_addrs;
+ n = csa->gbuff_limit;
+ break;
case VTK_PROBECRIT:
- if (!gd_header)
- gvinit();
- if (!parmblk.gv_ptr->open)
- gv_init_reg(parmblk.gv_ptr);
+ assert(NULL != gd_header); /* view_arg_convert would have done this for VTK_POOLLIMIT */
reg = parmblk.gv_ptr;
- grab_crit(reg);
- if (!WBTEST_ENABLED(WBTEST_HOLD_CRIT_ENABLED))
- rel_crit(reg);
+ if (!reg->open)
+ gv_init_reg(reg);
+ csa = &FILE_INFO(reg)->s_addrs;
+ if (NULL != csa->hdr)
+ {
+ UNIX_ONLY(csa->crit_probe = TRUE);
+ grab_crit(reg);
+ UNIX_ONLY(csa->crit_probe = FALSE);
+ if (!WBTEST_ENABLED(WBTEST_HOLD_CRIT_ENABLED))
+ rel_crit(reg);
+ dst->str.len = 0;
+# ifdef UNIX
+ ENSURE_STP_FREE_SPACE(n_probecrit_rec_types * (STATS_MAX_DIGITS + STATS_KEYWD_SIZE));
+ dst->str.addr = (char *)stringpool.free;
+ /* initialize csa->proberit_rec.p_crit_success field from cnl->gvstats_rec */
+ csa->probecrit_rec.p_crit_success = csa->nl->gvstats_rec.n_crit_success;
+# define TAB_PROBECRIT_REC(CNTR,TEXT1,TEXT2) STATS_PUT_PARM(TEXT1, CNTR, csa->probecrit_rec)
+# include "tab_probecrit_rec.h"
+# undef TAB_PROBECRIT_REC
+ assert(stringpool.free < stringpool.top);
+ /* subtract one to remove extra trailing comma delimiter */
+ dst->str.len = INTCAST((char *)stringpool.free - dst->str.addr - 1);
+# endif
+ }
break;
-#endif
case VTK_REGION:
gblnamestr = &parmblk.str;
assert(NULL != gd_header); /* "view_arg_convert" call done above would have set this (for VTP_DBKEY case) */
@@ -450,23 +486,11 @@ void op_fnview(UNIX_ONLY_COMMA(int numarg) mval *dst, ...)
csa = &FILE_INFO(parmblk.gv_ptr)->s_addrs;
if (NULL != csa->hdr)
{
-# define GVSTATS_MAX_DIGITS MAX_DIGITS_IN_INT8
-# define GVSTATS_KEYWORD_SIZE 5 /* THREE PLUS TWO DELIMITERS */
-# define GVSTATS_KEYWORD_COUNT n_gvstats_rec_types
-# define GVSTATS_MAX_SIZE (GVSTATS_KEYWORD_COUNT * (GVSTATS_MAX_DIGITS + GVSTATS_KEYWORD_SIZE))
- ENSURE_STP_FREE_SPACE(GVSTATS_MAX_SIZE);
+ ENSURE_STP_FREE_SPACE(n_gvstats_rec_types * (STATS_MAX_DIGITS + STATS_KEYWD_SIZE));
dst->str.addr = (char *)stringpool.free;
/* initialize cnl->gvstats_rec.db_curr_tn field from file header */
csa->nl->gvstats_rec.db_curr_tn = csa->hdr->trans_hist.curr_tn;
-# define GVSTATS_PUT_PARM(TXT, CNTR, cnl) \
- { \
- MEMCPY_LIT(stringpool.free, TXT); \
- stringpool.free += STR_LIT_LEN(TXT); \
- *stringpool.free++ = ':'; \
- stringpool.free = i2ascl(stringpool.free, cnl->gvstats_rec.CNTR); \
- *stringpool.free++ = ','; \
- }
-# define TAB_GVSTATS_REC(COUNTER,TEXT1,TEXT2) GVSTATS_PUT_PARM(TEXT1, COUNTER, csa->nl)
+# define TAB_GVSTATS_REC(CNTR,TEXT1,TEXT2) STATS_PUT_PARM(TEXT1, CNTR, csa->nl->gvstats_rec)
# include "tab_gvstats_rec.h"
# undef TAB_GVSTATS_REC
assert(stringpool.free < stringpool.top);
diff --git a/sr_port/op_fnztrigger.c b/sr_port/op_fnztrigger.c
index 9347884..d9efb4d 100644
--- a/sr_port/op_fnztrigger.c
+++ b/sr_port/op_fnztrigger.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2013 Fidelity Information Services, Inc *
+ * Copyright 2010, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -142,7 +142,7 @@ CONDITION_HANDLER(op_fnztrigger_ch)
void op_fnztrigger(mval *func, mval *arg1, mval *arg2, mval *dst)
{
int inparm_len, index;
- uint4 dummy_stats[NUM_STATS], filename_len;
+ uint4 filename_len;
boolean_t failed;
char filename[MAX_FN_LEN + 1];
DCL_THREADGBL_ACCESS;
@@ -211,25 +211,25 @@ void op_fnztrigger(mval *func, mval *arg1, mval *arg2, mval *dst)
switch(ztrprm_data[index])
{
case ZTRP_FILE:
- if (0 == arg1->str.len)
- /* 2nd parameter is missing */
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_ZTRIGINVACT, 1, 2);
- if (MAX_FN_LEN < arg1->str.len)
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_FILENAMETOOLONG);
- /* The file name is in string pool so make a local copy in case GC happens */
- strncpy(filename, arg1->str.addr, arg1->str.len);
- filename_len = arg1->str.len;
- filename[filename_len] = '\0';
- failed = trigger_trgfile_tpwrap(filename, filename_len, TRUE);
+ /* If 2nd parameter is empty, do nothing (but dont issue error) */
+ if (arg1->str.len)
+ {
+ if (MAX_FN_LEN < arg1->str.len)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_FILENAMETOOLONG);
+ /* The file name is in string pool so make a local copy in case GC happens */
+ strncpy(filename, arg1->str.addr, arg1->str.len);
+ filename_len = arg1->str.len;
+ filename[filename_len] = '\0';
+ failed = trigger_trgfile_tpwrap(filename, filename_len, TRUE);
+ } else
+ failed = FALSE;
break;
case ZTRP_ITEM:
- if (0 == arg1->str.len)
- /* 2nd parameter is missing */
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_ZTRIGINVACT, 1, 2);
- failed = trigger_update(arg1->str.addr, arg1->str.len);
+ /* If 2nd parameter is empty, do nothing (but dont issue error) */
+ failed = (arg1->str.len) ? trigger_update(arg1->str.addr, arg1->str.len) : FALSE;
break;
case ZTRP_SELECT:
- failed = (TRIG_FAILURE == trigger_select(arg1->str.addr, arg1->str.len, NULL, 0));
+ failed = trigger_select_tpwrap(arg1->str.addr, arg1->str.len, NULL, 0);
break;
default:
assertpro(FALSE && ztrprm_data[index]); /* Should never happen with checks above */
diff --git a/sr_port/op_hang.c b/sr_port/op_hang.c
index 28ace8f..8304def 100644
--- a/sr_port/op_hang.c
+++ b/sr_port/op_hang.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -60,6 +60,10 @@
#ifdef DEBUG
#include "have_crit.h" /* for the TPNOTACID_CHECK macro */
#endif
+#ifdef UNIX
+#include "sleep.h"
+#include "time.h"
+#endif
GBLREF uint4 dollar_trestart;
GBLREF mv_stent *mv_chain;
@@ -176,7 +180,10 @@ void op_hang(mval* num)
return; /* done HANGing */
}
# ifdef UNIX
- hiber_start(ms);
+ if (ms < 10)
+ SLEEP_USEC(ms * 1000, TRUE); /* Finish the sleep if it is less than 10ms. */
+ else
+ hiber_start(ms);
# elif defined(VMS)
time[0] = -time_low_ms(ms);
time[1] = -time_high_ms(ms) - 1;
diff --git a/sr_port/op_indpat.c b/sr_port/op_indpat.c
index d01b8f2..63fe8a0 100644
--- a/sr_port/op_indpat.c
+++ b/sr_port/op_indpat.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -19,7 +19,7 @@
#include "compile_pattern.h"
#include "op.h"
-GBLREF short int source_column;
+GBLREF int source_column;
void op_indpat(mval *v, mval *dst)
{
diff --git a/sr_port/op_indtext.c b/sr_port/op_indtext.c
index 4533996..57f0356 100644
--- a/sr_port/op_indtext.c
+++ b/sr_port/op_indtext.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -29,7 +29,7 @@
#include "stack_frame.h"
GBLREF unsigned char *source_buffer;
-GBLREF short int source_column;
+GBLREF int source_column;
GBLREF spdesc stringpool;
GBLREF mv_stent *mv_chain;
GBLREF unsigned char *msp, *stackwarn, *stacktop;
diff --git a/sr_port/op_lvpatwrite.c b/sr_port/op_lvpatwrite.c
index ff0440a..379172e 100644
--- a/sr_port/op_lvpatwrite.c
+++ b/sr_port/op_lvpatwrite.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -48,7 +48,6 @@ void op_lvpatwrite(UNIX_ONLY_COMMA(int4 count) UINTPTR_T arg1, ...)
MAXSTR_BUFF_DECL(buff);
SETUP_THREADGBL_ACCESS;
- TREF(in_zwrite) = TRUE;
VAR_START(var, arg1);
VMS_ONLY(va_count(count));
assert(1 < count);
@@ -115,7 +114,7 @@ void op_lvpatwrite(UNIX_ONLY_COMMA(int4 count) UINTPTR_T arg1, ...)
lvzwr_arg(flag, (mval *)arg1, (mval *)0);
break;
default:
- GTMASSERT;
+ assertpro(FALSE);
break;
}
}
diff --git a/sr_port/op_lvzwrite.c b/sr_port/op_lvzwrite.c
index 26d6390..ef55cd9 100644
--- a/sr_port/op_lvzwrite.c
+++ b/sr_port/op_lvzwrite.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -48,7 +48,6 @@ void op_lvzwrite(UNIX_ONLY_COMMA(int4 count) long arg1, ...)
MAXSTR_BUFF_DECL(buff);
SETUP_THREADGBL_ACCESS;
- TREF(in_zwrite) = TRUE;
VAR_START(var, arg1);
VMS_ONLY(va_count(count));
MAXSTR_BUFF_INIT;
@@ -105,7 +104,7 @@ void op_lvzwrite(UNIX_ONLY_COMMA(int4 count) long arg1, ...)
lvzwr_arg(flag, (mval *)arg1, (mval *)0);
break;
default:
- GTMASSERT;
+ assertpro(FALSE);
break;
}
}
diff --git a/sr_port/op_merge.c b/sr_port/op_merge.c
index 845dcf1..048e421 100644
--- a/sr_port/op_merge.c
+++ b/sr_port/op_merge.c
@@ -469,6 +469,7 @@ void op_merge(void)
lvzwr_init(zwr_patrn_mident, &mglvnp->lclp[IND2]->v);
lvzwr_arg(ZWRITE_ASTERISK, 0, 0);
lvzwr_var(mglvnp->lclp[IND2], 0);
+ TREF(in_zwrite) = FALSE;
# ifdef DEBUG
/* assert that destination got all data of the source and its descendants */
op_fndata(mglvnp->lclp[IND2], value);
@@ -495,6 +496,7 @@ void op_merge(void)
lvzwr_init(zwr_patrn_mident, &mglvnp->lclp[IND2]->v);
lvzwr_arg(ZWRITE_ASTERISK, 0, 0);
lvzwr_var(mglvnp->lclp[IND2], 0);
+ TREF(in_zwrite) = FALSE;
gvname_env_restore(gblp1); /* store destination as naked indicator in gv_currkey */
}
}
diff --git a/sr_port/op_rhdaddr.c b/sr_port/op_rhdaddr.c
index c008eef..9199162 100644
--- a/sr_port/op_rhdaddr.c
+++ b/sr_port/op_rhdaddr.c
@@ -19,7 +19,7 @@
GBLREF mident_fixed zlink_mname;
GBLREF rtn_tabent *rtn_names;
-#ifdef USHBIN_SUPPORTED
+#ifdef AUTORELINK_SUPPORTED
LITDEF mval literal_null;
#endif
@@ -29,7 +29,7 @@ error_def(ERR_ZLMODULE);
/* For routine name given, return routine header address if rhd not already set */
rhdtyp *op_rhdaddr(mval *name, rhdtyp *rhd)
{
-# ifdef USHBIN_SUPPORTED
+# ifdef AUTORELINK_SUPPORTED
return op_rhd_ext(name, (mval *)&literal_null, rhd, NULL);
# else
return (NULL != rhd) ? rhd : op_rhdaddr1(name);
@@ -64,7 +64,7 @@ rhdtyp *op_rhdaddr1(mval *name)
ERR_ZLMODULE, 2, strlen(&zlink_mname.c[0]), zlink_mname.c);
# endif
}
-# ifdef USHBIN_SUPPORTED
+# ifdef AUTORELINK_SUPPORTED
/* In this (autorelink) context, no need to pass 4th arg (*lnr) since other opcodes used in conjunction with
* op_rhdaddr1 will handle label offset if necessary.
*/
diff --git a/sr_port/op_setzbrk.c b/sr_port/op_setzbrk.c
index 7720e3e..aa6cf1f 100644
--- a/sr_port/op_setzbrk.c
+++ b/sr_port/op_setzbrk.c
@@ -30,9 +30,14 @@
#include "gtm_text_alloc.h"
#include "srcline.h"
#include "compiler.h"
+#include "min_max.h"
#ifdef GTM_TRIGGER
# include "trigger_source_read_andor_verify.h"
# include "gtm_trigger_trc.h"
+#else
+# define DBGIFTRIGR(x)
+# define DBGTRIGR(x)
+# define DBGTRIGR_ONLY(x)
#endif
GBLREF z_records zbrk_recs;
@@ -57,7 +62,7 @@ void op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
char *cp, zbloc_buff[MAX_ENTRYREF_LEN], *zbloc_end;
mident *lab_name, *dummy;
mident rname, lname;
- mstr *obj;
+ mstr *obj, tmprtnname;
rhdtyp *routine;
zb_code *addr, tmp_xf_code;
int4 *line_offset_addr, *next_line_offset_addr;
@@ -67,7 +72,8 @@ void op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
uint4 status;
int sstatus;
icode_str indir_src;
- boolean_t deleted, is_trigger;
+ boolean_t deleted;
+ GTMTRIG_ONLY(boolean_t is_trigger);
MV_FORCE_STR(rtn);
MV_FORCE_STR(lab);
@@ -83,18 +89,26 @@ void op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
else
{
GTMTRIG_ONLY(IS_TRIGGER_RTN(&rtn->str, is_trigger));
- GTMTRIG_ONLY(if (is_trigger) DBGTRIGR((stderr, "op_setzbrk: Setting/clearing a zbreak in a trigger\n")));
+ DBGIFTRIGR((stderr, "op_setzbrk: Setting/clearing a zbreak in a trigger\n"));
flush_pio();
if (WANT_CURRENT_RTN(rtn))
routine = CURRENT_RHEAD_ADR(frame_pointer->rvector);
else if (NULL == (routine = find_rtn_hdr(&rtn->str))) /* Note assignment */
{
# ifdef GTM_TRIGGER
+ /* trigger_source_read_andor_verify may alter the length part of the mstr to remove the +BREG
+ * region-name specification (the string component is unmodified). Pass in a copy of the mstr
+ * struct to avoid modification to routine->str as it affects the caller which relies on this
+ * variable being untouched.
+ */
+ tmprtnname = rtn->str;
if (is_trigger)
{
- sstatus = trigger_source_read_andor_verify(&rtn->str, TRIGGER_COMPILE);
- if ((0 != sstatus) || (NULL == (routine = find_rtn_hdr(&rtn->str)))) /* Note assignment */
+ DEBUG_ONLY(routine = NULL;)
+ sstatus = trigger_source_read_andor_verify(&tmprtnname, TRIGGER_COMPILE, &routine);
+ if (0 != sstatus)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TRIGNAMENF, 2, rtn->str.len, rtn->str.addr);
+ assert(NULL != routine);
} else
# endif
{
@@ -108,26 +122,26 @@ void op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
lab_name = NULL;
if (NULL == (line_offset_addr = find_line_addr(routine, &lab->str, offset, &lab_name)))
dec_err(VARLSTCNT(1) ERR_NOPLACE);
- else if (CANCEL_ONE == cnt) /* cancel zbreak */
+ else if (CANCEL_ONE == cnt) /* Cancel ZBREAK */
{
addr = (zb_code *)LINE_NUMBER_ADDR(CURRENT_RHEAD_ADR(routine), line_offset_addr);
addr = find_line_call(addr);
if (NULL != (z_ptr = zr_find(&zbrk_recs, addr)))
- zr_put_free(&zbrk_recs, z_ptr);
+ zr_remove_zbreak(&zbrk_recs, z_ptr);
else
dec_err(VARLSTCNT(1) ERR_NOZBRK);
- } else if (0 <= cnt) /* set zbreak */
+ } else if (0 <= cnt) /* Set ZBREAK */
{
# ifdef ZB_AT_COMMENT_INFO
dummy = NULL;
next_line_offset_addr = find_line_addr(routine, &lab->str, offset + 1, &dummy);
if (NULL != next_line_offset_addr && *next_line_offset_addr == *line_offset_addr)
- { /* we don't recognize the case of last line comment 'coz that line generates LINESTART, RET code */
+ { /* We don't recognize the case of last line comment 'coz that line generates LINESTART, RET code */
dec_err(VARLSTCNT(1) ERR_COMMENT);
assert(lab_name == dummy);
}
# endif
- op_commarg(act, indir_linetail); /* This puts entry in stack and also increments refcnt field */
+ op_commarg(act, indir_linetail); /* This puts entry in stack and also increments refcnt field */
indir_src.str = act->str;
indir_src.code = indir_linetail;
obj = cache_get(&indir_src);
@@ -146,14 +160,14 @@ void op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
{
# ifdef USHBIN_SUPPORTED
if ((NULL != routine->shared_ptext_adr) && (routine->shared_ptext_adr == routine->ptext_adr))
- { /* setting a breakpoint in a shared routine, need to make a private copy */
+ { /* Setting a breakpoint in a shared routine, need to make a private copy */
addr_off = (unsigned char *)addr - routine->ptext_adr;
if (SS_NORMAL == (status = cre_private_code_copy(routine)))
addr = (zb_code *)(routine->ptext_adr + addr_off);
else
{
assert(UNIX_ONLY(ERR_MEMORY) VMS_ONLY(ERR_VMSMEMORY) == status);
- /* convert to label+offset^routine to be presented to the user */
+ /* Convert to label+offset^routine to be presented to the user */
rname.len = rtn->str.len;
rname.addr = rtn->str.addr;
lname.len = lab->str.len;
@@ -164,15 +178,21 @@ void op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
}
}
# endif
- z_ptr = zr_get_free(&zbrk_recs, addr);
+ z_ptr = zr_add_zbreak(&zbrk_recs, addr);
NON_USHBIN_ONLY(fix_pages((unsigned char *)addr, (unsigned char *)addr));
-
- /* save for later restore while cancelling breakpoint */
+ /* Modify the instruction at the ZBREAK site. See zbreaksp.h for description of how this works
+ * on a given platform.
+ *
+ * Save original instruction for later restore when cancelling this breakpoint.
+ */
# ifdef COMPLEX_INSTRUCTION_UPDATE
EXTRACT_OFFSET_TO_M_OPCODE(z_ptr->m_opcode, addr);
# else
- z_ptr->m_opcode = *addr; /* save for later restore while cancelling breakpoint */
+ z_ptr->m_opcode = *addr;
# endif
+ /* Modify op_linestart or op_linefetch transfer table reference instruction to the appropriate
+ * ZBREAK related flavor of instruction instead.
+ */
tmp_xf_code = (z_ptr->m_opcode & ZB_CODE_MASK) >> ZB_CODE_SHIFT;
if (xf_linefetch * SIZEOF(UINTPTR_T) == tmp_xf_code)
{
@@ -194,18 +214,21 @@ void op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
assertpro( ((xf_zbstart * SIZEOF(UINTPTR_T)) == tmp_xf_code)
|| ((xf_zbfetch * SIZEOF(UINTPTR_T)) == tmp_xf_code));
z_ptr->rtn = &(CURRENT_RHEAD_ADR(routine))->routine_name;
- assert(lab_name != NULL);
+ assert(NULL != lab_name);
z_ptr->lab = lab_name;
z_ptr->offset = offset;
z_ptr->mpc = (zb_code *)((unsigned char *)addr - SIZEOF_LA);
+ z_ptr->rtnhdr = routine;
+ USHBIN_ONLY(routine->has_ZBREAK = TRUE); /* USHBIN platforms know which rtns have ZBREAK */
inst_flush(addr, SIZEOF(INST_TYPE));
}
if (z_ptr->action)
- { /* A zbreak command was already set for this line */
- /* Note when new action is same as old action, no resultant changes in zb_refcnt */
- assert(z_ptr->action->zb_refcnt > 0);
+ { /* A ZBREAK command was already set for this line. Note when new action is same as
+ * old action, no resultant changes in zb_refcnt.
+ */
+ assert(0 <z_ptr->action->zb_refcnt);
z_ptr->action->zb_refcnt--;
- assert(z_ptr->action != csp || z_ptr->action->zb_refcnt > 0);
+ assert((z_ptr->action != csp) || (0 <z_ptr->action->zb_refcnt));
}
z_ptr->action = csp;
z_ptr->count = cnt;
diff --git a/sr_port/op_svget.c b/sr_port/op_svget.c
index 15f1544..b2b022a 100644
--- a/sr_port/op_svget.c
+++ b/sr_port/op_svget.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -36,6 +36,7 @@
#include "op.h"
#include "mvalconv.h"
#include "zroutines.h"
+#include "zshow.h"
#include "getstorage.h"
#include "get_command_line.h"
#include "getzposition.h"
@@ -98,6 +99,7 @@ GBLREF boolean_t dollar_zquit_anyway;
#ifdef GTM_TRIGGER
GBLREF mstr *dollar_ztname;
GBLREF mval *dollar_ztdata;
+GBLREF mval *dollar_ztdelim;
GBLREF mval *dollar_ztoldval;
GBLREF mval *dollar_ztriggerop;
GBLREF mval dollar_ztslate;
@@ -453,6 +455,17 @@ void op_svget(int varnum, mval *v)
# else
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP);
# endif
+ case SV_ZTDELIM:
+# ifdef GTM_TRIGGER
+ assert(!dollar_ztdelim || MV_DEFINED(dollar_ztdelim));
+ if (NULL == dollar_ztdelim || !(MV_STR & dollar_ztdelim->mvtype) || (0 == dollar_ztdelim->str.len))
+ memcpy(v, &literal_null, SIZEOF(mval));
+ else
+ memcpy(v, dollar_ztdelim, SIZEOF(mval));
+ break;
+# else
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP);
+# endif
case SV_ZTOLDVAL:
# ifdef GTM_TRIGGER
/* Value comes from GT.M, but it might be numeric and need conversion to a string */
diff --git a/sr_port/op_tcommit.c b/sr_port/op_tcommit.c
index aa1d546..8f564ea 100644
--- a/sr_port/op_tcommit.c
+++ b/sr_port/op_tcommit.c
@@ -473,7 +473,7 @@ enum cdb_sc op_tcommit(void)
GTMTRIG_ONLY(DBGTRIGR((stderr, "op_tcommit: Return status = %d\n", status));)
return status; /* return status to caller who cares about it */
}
- assert(UNIX_ONLY(jgbl.onlnrlbk ||) (0 == have_crit(CRIT_HAVE_ANY_REG)));
+ assert(UNIX_ONLY(jgbl.onlnrlbk || TREF(in_trigger_upgrade) || ) (0 == have_crit(CRIT_HAVE_ANY_REG)));
csa = jnl_fence_ctl.fence_list;
if ((JNL_FENCE_LIST_END != csa) && jgbl.wait_for_jnl_hard && !is_updproc && !mupip_jnl_recover)
{ /* For mupip journal recover all transactions applied during forward phase are treated as
@@ -498,7 +498,7 @@ enum cdb_sc op_tcommit(void)
rel_crit(tr->reg);
}
}
- assert(UNIX_ONLY(jgbl.onlnrlbk ||) (0 == have_crit(CRIT_HAVE_ANY_REG)));
+ assert(UNIX_ONLY(jgbl.onlnrlbk || TREF(in_trigger_upgrade) || ) (0 == have_crit(CRIT_HAVE_ANY_REG)));
/* Commit was successful */
dollar_trestart = 0;
t_tries = 0;
diff --git a/sr_port/op_tstart.c b/sr_port/op_tstart.c
index 337fc61..aca4604 100644
--- a/sr_port/op_tstart.c
+++ b/sr_port/op_tstart.c
@@ -215,9 +215,9 @@ void op_tstart(int implicit_flag, ...) /* value of $T when TSTART */
t_tries = (FALSE == mupip_jnl_recover) ? 0 : CDB_STAGNATE;
t_fail_hist[t_tries] = cdb_sc_normal;
/* ensure that we don't have crit on any region at the beginning of a TP transaction (be it GT.M or MUPIP).
- * The only exception is ONLINE ROLLBACK which holds crit for the entire duration
+ * The only exception is ONLINE ROLLBACK or MUPIP TRIGGER -UPGRADE which holds crit for the entire duration
*/
- assert(0 == have_crit(CRIT_HAVE_ANY_REG) UNIX_ONLY(|| jgbl.onlnrlbk));
+ assert(0 == have_crit(CRIT_HAVE_ANY_REG) UNIX_ONLY(|| jgbl.onlnrlbk || TREF(in_trigger_upgrade)));
}
# ifdef GTM_TRIGGER
else
@@ -403,10 +403,16 @@ void op_tstart(int implicit_flag, ...) /* value of $T when TSTART */
tf->restartable = (NORESTART != prescnt);
tf->old_locks = (NULL != mlk_pvt_root);
# ifdef DEBUG
- if (!jgbl.forw_phase_recovery)
- { /* In case of forward phase of journal recovery, gv_currkey is set by caller (mur_forward) only
- * after the call to op_tstart so avoid doing gv_currkey check.
- */
+ /* Do check that gv_currkey and gv_target are in sync.
+ * In case of forward phase of journal recovery, gv_currkey is set by caller (mur_forward) only
+ * after the call to op_tstart so avoid doing gv_currkey check. Also in case of trigger_upgrade,
+ * we could start a TP transaction from almost anywhere (e.g. inside name-level $order in op_gvorder)
+ * and so we are not guaranteed this check will succeed. Since this check is not necessary anymore
+ * (see comment before macro definition) we skip this check in that case. A broad (but not accurate)
+ * way to check for trigger_upgrade is if gv_target is directory-tree (i.e. gvname is "").
+ */
+ if (!jgbl.forw_phase_recovery && (NULL != gv_target) && gv_target->gvname.var_name.len)
+ {
DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE);
}
# endif
@@ -599,6 +605,7 @@ void op_tstart(int implicit_flag, ...) /* value of $T when TSTART */
assert((NULL != first_ua) && (NULL != curr_ua)); /* Since first_sgm_info is NOT NULL, database activity existed */
new_gtli->curr_ua = (struct ua_list *)(curr_ua);
new_gtli->upd_array_ptr = update_array_ptr;
+ GTMTRIG_ONLY(new_gtli->ztrigbuffLen = TREF(ztrigbuffLen);)
new_gtli->next_global_tlvl_info = NULL;
if (prev_gtli)
{
diff --git a/sr_port/op_unwind.c b/sr_port/op_unwind.c
index fde72e1..09d7b8c 100644
--- a/sr_port/op_unwind.c
+++ b/sr_port/op_unwind.c
@@ -33,6 +33,7 @@
#include "gdsbt.h"
#include "gdsfhead.h"
#include "alias.h"
+#include "zr_unlink_rtn.h"
#ifdef GTM_TRIGGER
# include "gtm_trigger_trc.h"
#endif
@@ -59,7 +60,9 @@ error_def(ERR_TPQUIT);
/* This has to be maintained in parallel with unw_retarg(), the unwind with a return argument (extrinisic quit) routine. */
void op_unwind(void)
{
+ rhdtyp *rtnhdr;
mv_stent *mvc;
+ stack_frame *fp;
DBGEHND_ONLY(stack_frame *prevfp;)
DCL_THREADGBL_ACCESS;
@@ -116,6 +119,7 @@ void op_unwind(void)
# endif
DRAIN_GLVN_POOL_IF_NEEDED;
PARM_ACT_UNSTACK_IF_NEEDED;
+ USHBIN_ONLY(rtnhdr = frame_pointer->rvector); /* Save rtnhdr for cleanup call below */
frame_pointer = frame_pointer->old_frame_pointer;
DBGEHND((stderr, "op_unwind: Stack frame 0x"lvaddr" unwound - frame 0x"lvaddr" now current - New msp: 0x"lvaddr"\n",
prevfp, frame_pointer, msp));
@@ -128,6 +132,7 @@ void op_unwind(void)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKUNDERFLO);
assert((frame_pointer < frame_pointer->old_frame_pointer) || (NULL == frame_pointer->old_frame_pointer));
}
+ USHBIN_ONLY(CLEANUP_COPIED_RECURSIVE_RTN(rtnhdr));
/* We just unwound a frame. May have been either a zintrupt frame and/or may have unwound a NEW'd ZTRAP or even cleared
* our error state. If we have a deferred timeout and none of the deferral conditions are anymore in effect, release
* the hounds.
diff --git a/sr_port/op_view.c b/sr_port/op_view.c
index f6dc9c3..78a5f33 100644
--- a/sr_port/op_view.c
+++ b/sr_port/op_view.c
@@ -69,12 +69,12 @@
# include "gtmsecshr.h"
# endif
#endif
-#if defined(DEBUG) && defined(USHBIN_SUPPORTED)
+#ifdef AUTORELINK__SUPPORTED
# include "relinkctl.h"
#endif
#include "gtmimagename.h"
-STATICFNDCL void view_dbflushop(unsigned char keycode, viewparm *parmblkptr, mval *thirdarg);
+STATICFNDCL void view_dbop(unsigned char keycode, viewparm *parmblkptr, mval *thirdarg);
GBLREF volatile int4 db_fsync_in_prog;
GBLREF boolean_t certify_all_blocks;
@@ -144,54 +144,50 @@ error_def(ERR_ZDEFACTIVE);
void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
{
- int4 testvalue, tmpzdefbufsiz;
- uint4 jnl_status, dummy_errno;
- int status, lcnt, icnt, recnum;
- gd_region *reg, *r_top, *save_reg;
- gv_namehead *gvnh;
- mval *arg, *nextarg, outval;
- mstr tmpstr;
- va_list var;
- viewparm parmblk, parmblk2;
- viewtab_entry *vtp;
+ boolean_t dbgdmpenabled, was_crit, was_skip_gtm_putmsg;
+ char *chptr;
+ collseq *new_lcl_collseq;
gd_addr *addr_ptr;
+ gd_region *reg, *r_top, *save_reg;
gvnh_reg_t *gvnh_reg;
gvnh_spanreg_t *gvspan;
+ gv_namehead *gvnh;
+ hash_table_mname *table;
+ ht_ent_mname *tabent, *table_base_orig, *topent;
+ int clrlen, lcnt, lct, icnt, ncol, nct, status, table_size_orig;
+ int4 testvalue, tmpzdefbufsiz;
+ jnl_buffer_ptr_t jb;
+ lv_blk *lvbp;
+ lv_val *lv, *lvp, *lvp_top;
+ mstr tmpstr;
+ mval *arg, *nextarg, outval;
noisolation_element *gvnh_entry;
- int lct, ncol, nct;
- collseq *new_lcl_collseq;
- ht_ent_mname *tabent, *topent;
- lv_val *lv;
- symval *cstab;
sgmnt_addrs *csa;
sgmnt_data_ptr_t csd;
- jnl_buffer_ptr_t jb;
- int table_size_orig;
- ht_ent_mname *table_base_orig;
- hash_table_mname *table;
- boolean_t dbgdmpenabled, was_crit, was_skip_gtm_putmsg;
- symval *lvlsymtab;
- lv_blk *lvbp;
- lv_val *lvp, *lvp_top;
-# if defined(DEBUG) && defined(USHBIN_SUPPORTED)
+ symval *cstab, *lvlsymtab;
+ uint4 jnl_status, dummy_errno;
+ va_list var;
+ viewparm parmblk, parmblk2;
+ viewtab_entry *vtp;
+# ifdef AUTORELINK_SUPPORTED
open_relinkctl_sgm *linkctl;
relinkrec_t *linkrec;
+ int recnum;
# endif
VMS_ONLY(int numarg;)
-
static readonly char msg1[] = "Caution: Database Block Certification Has Been ";
- static readonly char msg2[] = "Disabled";
- static readonly char msg3[] = "Enabled";
static readonly char lv_msg1[] =
"Caution: GT.M reserved local variable string pointer duplicate check diagnostic has been";
- static readonly char upper[] = "UPPER";
+ static readonly char msg2[] = "Disabled";
+ static readonly char msg3[] = "Enabled";
static readonly char lower[] = "LOWER";
+ static readonly char upper[] = "UPPER";
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
VAR_START(var, keyword);
VMS_ONLY(va_count(numarg));
- jnl_status = 0;
+ jnl_status = 0;
assertpro(1 <= numarg);
MV_FORCE_STR(keyword);
numarg--; /* remove keyword from count */
@@ -232,13 +228,15 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
outval.mvtype = MV_STR;
view_debug4 = (0 != MV_FORCE_INT(parmblk.value));
break;
+ case VTK_DBFLUSH:
case VTK_DBSYNC:
case VTK_EPOCH:
case VTK_FLUSH:
+ case VTK_GVSRESET:
case VTK_JNLFLUSH:
- case VTK_DBFLUSH:
+ case VTK_POOLLIMIT:
arg = (numarg > 1) ? va_arg(var, mval *) : NULL;
- view_dbflushop(vtp->keycode, &parmblk, arg);
+ view_dbop(vtp->keycode, &parmblk, arg);
break;
# ifdef UNIX
case VTK_DMTERM:
@@ -443,7 +441,8 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
}
was_skip_gtm_putmsg = TREF(skip_gtm_putmsg);
TREF(skip_gtm_putmsg) = TRUE; /* to avoid ready_collseq from doing gtm_putmsg in case of errors.
- * not doing so will cause GDECHECK errors in caller (GDE). */
+ * not doing so will cause GDECHECK errors in caller (GDE).
+ */
new_lcl_collseq = ready_collseq(lct);
TREF(skip_gtm_putmsg) = was_skip_gtm_putmsg;
if (0 == new_lcl_collseq)
@@ -619,9 +618,9 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
tmpzdefbufsiz = MV_FORCE_INT(parmblk.value);
if (1 == tmpzdefbufsiz)
tmpzdefbufsiz = ZDEFDEF;
- else if (tmpzdefbufsiz < ZDEFMIN)
+ else if (tmpzdefbufsiz < ZDEFMIN)
tmpzdefbufsiz = ZDEFMIN;
- else if (tmpzdefbufsiz > ZDEFMAX)
+ else if (tmpzdefbufsiz > ZDEFMAX)
tmpzdefbufsiz = ZDEFMAX;
zdefbufsiz = (unsigned short)tmpzdefbufsiz;
break;
@@ -682,7 +681,8 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
break;
case VTK_LVREHASH:
/* This doesn't actually expand or contract the local variable hash table but does cause it to be
- * rebuilt. Then we need to do the same sort of cleanup that add_hashtab_mname_symval does. */
+ * rebuilt. Then we need to do the same sort of cleanup that add_hashtab_mname_symval does.
+ */
/* Step 1: remember table we started with */
table = &curr_symval->h_symtab;
table_base_orig = table->base;
@@ -702,7 +702,7 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
case VTK_STORDUMP:
# if defined(DEBUG) && defined(UNIX)
if (gtm_white_box_test_case_enabled
- && (WBTEST_HOLD_CRIT_TILL_LCKALERT == gtm_white_box_test_case_number))
+ && (WBTEST_HOLD_CRIT_TILL_LCKALERT == gtm_white_box_test_case_number))
{ /* Hold crit for a long enough interval to generate lock alert which then does a continue_proc */
grab_crit(gv_cur_region);
icnt = TREF(continue_proc_cnt);
@@ -796,36 +796,15 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
lv = (lv_val *)parmblk.value;
util_out_print("", RESET); /* Reset the buffer */
util_out_print("LV: !AD addr: 0x!XJ mvtype: 0x!4XW sign: !UB exp: !UL m[0]: !UL [0x!XL] "
- "m[1]: !UL [0x!XL] str.len: !UL str.addr: 0x!XJ", SPRINT, arg->str.len, arg->str.addr,
- lv, lv->v.mvtype, lv->v.sgn, lv->v.e, lv->v.m[0], lv->v.m[0], lv->v.m[1], lv->v.m[1],
- lv->v.str.len, lv->v.str.addr);
+ "m[1]: !UL [0x!XL] str.len: !UL str.addr: 0x!XJ", SPRINT, arg->str.len, arg->str.addr,
+ lv, lv->v.mvtype, lv->v.sgn, lv->v.e, lv->v.m[0], lv->v.m[0], lv->v.m[1], lv->v.m[1],
+ lv->v.str.len, lv->v.str.addr);
outval.str.addr = TREF(util_outptr);
outval.str.len = STRLEN(TREF(util_outptr));
op_write(&outval);
op_wteol(1);
break;
# endif
-# if defined(DEBUG) && defined(USHBIN_SUPPORTED)
- case VTK_RCTLDUMP:
- util_out_print("", RESET); /* Reset output buffer */
- for (linkctl = TREF(open_relinkctl_list); NULL != linkctl; linkctl = linkctl->next)
- {
- util_out_print_gtmio("relinkctl: 0x!XJ entryname: !AD records: !UL hdr: 0x!XJ base: 0x!XJ"
- " locked: !UL", FLUSH, linkctl, linkctl->zro_entry_name.len,
- linkctl->zro_entry_name.addr, linkctl->n_records, linkctl->hdr,
- linkctl->rec_base, linkctl->locked);
- util_out_print_gtmio(" hdr: records: !UL nattached: !UL", FLUSH, linkctl->hdr->n_records,
- linkctl->hdr->nattached);
- for (linkrec = linkctl->rec_base, recnum = 1; recnum <= linkctl->hdr->n_records;
- linkrec++, recnum++)
- {
- util_out_print_gtmio(" rec#!4UL: rtnname: !AD cycle: !UL", FLUSH, recnum,
- mid_len(&linkrec->rtnname_fixed), &linkrec->rtnname_fixed.c,
- linkrec->cycle);
- }
- }
- break;
-# endif
default:
va_end(var);
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_VIEWCMD);
@@ -834,17 +813,16 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
return;
}
-void view_dbflushop(unsigned char keycode, viewparm *parmblkptr, mval *thirdarg)
+void view_dbop(unsigned char keycode, viewparm *parmblkptr, mval *thirdarg)
{
- uint4 jnl_status, dummy_errno;
- int4 nbuffs;
- int save_errno;
- int status, lcnt, icnt;
+ boolean_t was_crit;
gd_region *reg, *r_top, *save_reg;
+ int icnt, lcnt, save_errno, status;
+ int4 nbuffs;
+ jnl_buffer_ptr_t jb;
sgmnt_addrs *csa;
sgmnt_data_ptr_t csd;
- jnl_buffer_ptr_t jb;
- boolean_t was_crit;
+ uint4 jnl_status, dummy_errno;
UNIX_ONLY(unix_db_info *udi;)
if (NULL == gd_header) /* open gbldir */
@@ -863,6 +841,14 @@ void view_dbflushop(unsigned char keycode, viewparm *parmblkptr, mval *thirdarg)
gv_cur_region = reg;
switch(keycode)
{
+ case VTK_DBFLUSH:
+ if (!reg->read_only)
+ {
+ change_reg(); /* for jnl_ensure_open */
+ nbuffs = (NULL != thirdarg) ? MV_FORCE_INT(thirdarg) : cs_addrs->nl->wcs_active_lvl;
+ JNL_ENSURE_OPEN_WCS_WTSTART(cs_addrs, reg, nbuffs, dummy_errno);
+ }
+ break;
case VTK_DBSYNC:
# ifdef UNIX
if (!reg->read_only)
@@ -880,8 +866,8 @@ void view_dbflushop(unsigned char keycode, viewparm *parmblkptr, mval *thirdarg)
}
# endif
break;
- case VTK_FLUSH:
case VTK_EPOCH:
+ case VTK_FLUSH:
if (!reg->read_only)
{
change_reg(); /* for jnl_ensure_open */
@@ -896,6 +882,12 @@ void view_dbflushop(unsigned char keycode, viewparm *parmblkptr, mval *thirdarg)
wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH | WCSFLU_IN_COMMIT | WCSFLU_SPEEDUP_NOBEFORE);
}
break;
+ case VTK_GVSRESET:
+ change_reg();
+ if (!reg->read_only)
+ CLRGVSTATS(cs_addrs);
+ memset((char *)&cs_addrs->gvstats_rec, 0, SIZEOF(gvstats_rec_t)); /* always process-private */
+ break;
case VTK_JNLFLUSH:
change_reg();
csa = cs_addrs;
@@ -932,13 +924,18 @@ void view_dbflushop(unsigned char keycode, viewparm *parmblkptr, mval *thirdarg)
rel_crit(reg);
}
break;
- case VTK_DBFLUSH:
- if (!reg->read_only)
- {
- change_reg(); /* for jnl_ensure_open */
- nbuffs = (NULL != thirdarg) ? MV_FORCE_INT(thirdarg) : cs_addrs->nl->wcs_active_lvl;
- JNL_ENSURE_OPEN_WCS_WTSTART(cs_addrs, reg, nbuffs, dummy_errno);
- }
+ case VTK_POOLLIMIT:
+ change_reg();
+ csa = cs_addrs;
+ csd = csa->hdr;
+ nbuffs = MV_FORCE_INT(thirdarg);
+ if ((MV_STR & thirdarg->mvtype) && ('%' == thirdarg->str.addr[thirdarg->str.len - 1]))
+ nbuffs = (100 == nbuffs) ? 0 : (csd->n_bts * nbuffs) / 100; /* percentage */
+ csa->gbuff_limit = (0 == nbuffs) ? 0 : MAX(MIN(nbuffs, csd->n_bts * .5), MIN_GBUFF_LIMIT);
+ /* to pick the current "hand" as a pseudo-random spot for our area see dbg code in gvcst_init
+ * but for the first release of this always pick the end of the buffer
+ */
+ csa->our_midnite = csa->acc_meth.bg.cache_state->cache_array + csd->bt_buckets + csd->n_bts;
break;
}
}
diff --git a/sr_port/op_zprint.c b/sr_port/op_zprint.c
index 187d627..044ca77 100644
--- a/sr_port/op_zprint.c
+++ b/sr_port/op_zprint.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -19,12 +19,19 @@
#include "error.h"
#include "op.h"
#include "outofband.h"
+#include "min_max.h"
#ifdef GTM_TRIGGER
# include "gtm_trigger_trc.h"
+#else
+# define DBGIFTRIGR(x)
+# define DBGTRIGR(x)
+# define DBGTRIGR_ONLY(x)
#endif
#define INFO_MSK(error) (error & ~SEV_MSK | INFO)
+DBGTRIGR_ONLY(GBLREF uint4 dollar_tlevel;)
+DBGTRIGR_ONLY(GBLREF unsigned int t_tries;)
GBLREF int4 outofband;
GBLREF mident_fixed zlink_mname;
@@ -43,67 +50,63 @@ void op_zprint(mval *rtn, mval *start_label, int start_int_exp, mval *end_label,
/* parser makes the second label the duplicate */
/* of the first. (not so vice versa) */
{
- mval print_line, null_str;
- mstr *src1, *src2;
- uint4 stat1, stat2;
- rhdtyp *rtn_vector;
- boolean_t is_trigger;
+ mval print_line, null_str;
+ mstr *src1, *src2;
+ uint4 stat1, stat2;
+ rhdtyp *rtn_vector, *rtn_vector2;
+ GTMTRIG_ONLY(boolean_t is_trigger;)
MV_FORCE_STR(start_label);
MV_FORCE_STR(end_label);
MV_FORCE_STR(rtn);
- /* This first call to get_src_line() for our entry "locks-in" the source we will be extracting. If the rtn
- * in question in a trigger, it would be possible for the further get_src_line() calls we do to cause the
- * trigger to be reloaded making our earlier fetches irrelevant. After this first call, all following calls
- * to get_src_line() for this operation will tell get_src_line() to NOT verify or reload the triggers so
- * we get a consistent (if no longer current) view of the trigger.
- */
GTMTRIG_ONLY(IS_TRIGGER_RTN(&rtn->str, is_trigger));
- GTMTRIG_ONLY(if (is_trigger) DBGTRIGR((stderr, "op_zprint: Performing zprint of a trigger\n")));
- stat1 = get_src_line(rtn, start_label, start_int_exp, &src1, VERIFY);
+ DBGIFTRIGR((stderr, "op_zprint: Performing zprint of a trigger $tlevel=%d $trestart=%d\n", dollar_tlevel, t_tries));
+ stat1 = get_src_line(rtn, start_label, start_int_exp, &src1, &rtn_vector);
+ DBGIFTRIGR((stderr, "op_zprint: get_src_line returned %d\n", stat1));
if (OBJMODMISS == stat1)
{
# ifdef GTM_TRIGGER
if (is_trigger)
- rts_error(VARLSTCNT(4) ERR_TRIGNAMENF, 2, rtn->str.len, rtn->str.addr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TRIGNAMENF, 2, rtn->str.len, rtn->str.addr);
# endif
/* get_src_line did not find the object file to load */
- rts_error(VARLSTCNT(8) ERR_ZLINKFILE, 2, rtn->str.len, rtn->str.addr,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZLINKFILE, 2, rtn->str.len, rtn->str.addr,
ERR_ZLMODULE, 2, mid_len(&zlink_mname), &zlink_mname.c[0]);
}
- if (NULL == (rtn_vector = find_rtn_hdr(&rtn->str)))
- {
-# ifdef GTM_TRIGGER
- if (is_trigger)
- rts_error(VARLSTCNT(4) ERR_TRIGNAMENF, 2, rtn->str.len, rtn->str.addr);
-# endif
- GTMASSERT; /* If couldn't find module, should have returned OBJMODMISS */
- }
+ /* In case of GTM_TRIGGER, rtn_vector would have been initialized in the call to get_src_line above.
+ * We need to use that and not do a find_rtn_hdr as rtn->str might contain region-name disambiguator
+ * which find_rtn_hdr has no clue about. Even in case of no GTM_TRIGGER, we should be able to use rtn_vector
+ * from "get_src_line". Assert that below before using.
+ */
+ DEBUG_ONLY(NON_GTMTRIG_ONLY(rtn_vector2 = find_rtn_hdr(&rtn->str);))
+ NON_GTMTRIG_ONLY(assert(rtn_vector2 == rtn_vector);)
+ assertpro(NULL != rtn_vector); /* If couldn't find module, should have returned OBJMODMISS */
if (stat1 & LABELNOTFOUND)
- rts_error(VARLSTCNT(1) ERR_ZPRTLABNOTFND);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZPRTLABNOTFND);
if (stat1 & SRCNOTFND)
- rts_error(VARLSTCNT(4) ERR_FILENOTFND, 2, rtn_vector->src_full_name.len, rtn_vector->src_full_name.addr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_FILENOTFND, 2,
+ rtn_vector->src_full_name.len, rtn_vector->src_full_name.addr);
if (stat1 & (SRCNOTAVAIL | AFTERLASTLINE))
return;
if (stat1 & (ZEROLINE | NEGATIVELINE))
{
null_str.mvtype = MV_STR;
null_str.str.len = 0;
- stat1 = get_src_line(rtn, &null_str, 1, &src1, NOVERIFY);
+ stat1 = get_src_line(rtn, &null_str, 1, &src1, NULL);
if (stat1 & AFTERLASTLINE) /* the "null" file */
return;
}
if (end_int_exp == 0 && (end_label->str.len == 0 || *end_label->str.addr == 0))
stat2 = AFTERLASTLINE;
- else if ((stat2 = get_src_line(rtn, end_label, end_int_exp, &src2, NOVERIFY)) & LABELNOTFOUND)
- rts_error(VARLSTCNT(1) ERR_ZPRTLABNOTFND);
+ else if ((stat2 = get_src_line(rtn, end_label, end_int_exp, &src2, NULL)) & LABELNOTFOUND)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZPRTLABNOTFND);
if (stat2 & (ZEROLINE | NEGATIVELINE))
return;
if (stat2 & AFTERLASTLINE)
{
null_str.mvtype = MV_STR;
null_str.str.len = 0;
- stat2 = get_src_line(rtn, &null_str, 1, &src2, NOVERIFY);
+ stat2 = get_src_line(rtn, &null_str, 1, &src2, NULL);
/* number of lines less one for duplicated zero'th line and one due
to termination condition being <=
*/
@@ -112,13 +115,14 @@ void op_zprint(mval *rtn, mval *start_label, int start_int_exp, mval *end_label,
}
if (stat1 & CHECKSUMFAIL)
{
- rts_error(VARLSTCNT(1) INFO_MSK(ERR_TXTSRCMAT));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) INFO_MSK(ERR_TXTSRCMAT));
op_wteol(1);
}
print_line.mvtype = MV_STR;
+ DBGIFTRIGR((stderr, "op_zprint: printing the trigger from 0x%lx to 0x%lx\n", src1, src2));
for ( ; src1 <= src2 ; src1++)
{ /* Note outofband check currently disabled. This routine (op_zprint) needs to be rewritten to provide
- * a TP wrapper (if not already in place) and to buffer the lines obtained from get_src_line() completely
+ * a TP wrapper (if not already in place) and to buffer the lines obtained from "get_src_line" completely
* before outputting anything because obtaining these source lines is subject to TP restarts when we are
* accessing triggers. In addition, for the case of "normal" routine source fetches, an outofband could
* invoke a job interrupt which could relink an entry point so an out-of-band interrupt of any kind means
@@ -132,5 +136,6 @@ void op_zprint(mval *rtn, mval *start_label, int start_int_exp, mval *end_label,
op_write(&print_line);
op_wteol(1);
}
+ DBGIFTRIGR((stderr, "op_zprint: exiting\n\n"));
return;
}
diff --git a/sr_port/op_zshow.c b/sr_port/op_zshow.c
index 5a37177..1e3f3af 100644
--- a/sr_port/op_zshow.c
+++ b/sr_port/op_zshow.c
@@ -36,6 +36,7 @@ void op_zshow(mval *func, int type, lv_val *lvn)
{
const char *ptr;
boolean_t do_all = FALSE,
+ done_a = FALSE,
done_b = FALSE,
done_c = FALSE,
done_d = FALSE,
@@ -55,6 +56,8 @@ void op_zshow(mval *func, int type, lv_val *lvn)
{
switch (*ptr)
{
+ case 'A':
+ case 'a':
case 'B':
case 'b':
case 'C':
@@ -107,7 +110,16 @@ void op_zshow(mval *func, int type, lv_val *lvn)
{
output.line_num = 1;
switch (*ptr)
- { case 'B':
+ {
+ case 'A':
+ case 'a':
+ if (done_a)
+ break;
+ done_a = TRUE;
+ output.code = 'A';
+ ARLINK_ONLY(zshow_rctldump(&output));
+ break;
+ case 'B':
case 'b':
if (done_b)
break;
diff --git a/sr_port/opcode_def.h b/sr_port/opcode_def.h
index c8ee247..0ac2a6a 100644
--- a/sr_port/opcode_def.h
+++ b/sr_port/opcode_def.h
@@ -344,6 +344,8 @@ OPCODE_DEF(OC_STOLITC, (OCT_NULL))
OPCODE_DEF(OC_FNZPEEK, (OCT_MVAL | OCT_EXPRLEAF))
OPCODE_DEF(OC_FNZSOCKET, (OCT_MVAL | OCT_EXPRLEAF))
OPCODE_DEF(OC_FNZSYSLOG, (OCT_MVAL | OCT_EXPRLEAF))
+#ifdef AUTORELINK_SUPPORTED
OPCODE_DEF(OC_RHD_EXT, (OCT_CDADDR))
OPCODE_DEF(OC_LAB_EXT, (OCT_CDADDR))
OPCODE_DEF(OC_ZRUPDATE, (OCT_NULL))
+#endif
diff --git a/sr_port/put_indr.c b/sr_port/put_indr.c
index 5306aee..79a39b5 100644
--- a/sr_port/put_indr.c
+++ b/sr_port/put_indr.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -12,12 +12,11 @@
#include "mdef.h"
#include "compiler.h"
-oprtype put_indr(x)
-oprtype *x;
+oprtype put_indr(oprtype *x)
{
-mval *p;
-oprtype a;
-a.oprclass = INDR_REF;
-a.oprval.indr = x;
-return a;
+ oprtype a;
+
+ a.oprclass = INDR_REF;
+ a.oprval.indr = x;
+ return a;
}
diff --git a/sr_port/put_lit.c b/sr_port/put_lit.c
index 61b026e..c17ff25 100644
--- a/sr_port/put_lit.c
+++ b/sr_port/put_lit.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -35,10 +35,10 @@ oprtype put_lit(mval *x)
ref = newtriple(OC_LIT);
ref->operand[0].oprclass = MLIT_REF;
/* Multiple reasons to use hashtab since coerce which processes integer parms to functions will
- actually *remove* literals if they were just put on so we don't want to convert to hashtab
- then have that literal and/or some others yanked to pull us back under the count as that would
- confuse things mightily.
- */
+ * actually *remove* literals if they were just put on so we don't want to convert to hashtab
+ * then have that literal and/or some others yanked to pull us back under the count as that would
+ * confuse things mightily.
+ */
usehtab = (LIT_HASH_CUTOVER < mlitmax) || (complits_hashtab && complits_hashtab->base);
if (!usehtab)
{ /* Brute force scan under cutover .. should include all intrinsics */
diff --git a/sr_port/put_str.c b/sr_port/put_str.c
index 4ebff46..9b090d4 100644
--- a/sr_port/put_str.c
+++ b/sr_port/put_str.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -18,12 +18,13 @@
GBLREF spdesc stringpool;
-oprtype put_str(char *pt,mstr_len_t n)
+oprtype put_str(char *pt, mstr_len_t n)
{
mval p;
ENSURE_STP_FREE_SPACE(n);
memcpy(stringpool.free, pt, n);
+ memset(&p, 0, SIZEOF(mval));
p.mvtype = MV_STR;
p.str.len = n;
p.str.addr = (char *) stringpool.free;
diff --git a/sr_port/repl_errno.h b/sr_port/repl_errno.h
index e3a4aaa..d234724 100644
--- a/sr_port/repl_errno.h
+++ b/sr_port/repl_errno.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -48,11 +48,10 @@ enum
EREPL_INTLFILTER_DATA2LONG, /* 285 */
EREPL_INTLFILTER_REPLGBL2LONG, /* 286 */
EREPL_FILTERRECV, /* 287 */
- EREPL_FILTERNOSPC, /* 288 */
- EREPL_INTLFILTER_SECNODZTRIGINTP, /* 289 */
- EREPL_INTLFILTER_MULTILINEXECUTE, /* 290 */
- EREPL_FILTERTIMEDOUT, /* 291 */
- EREPL_MAXERRNO /* 292 */
+ EREPL_INTLFILTER_PRILESSTHANV62, /* 288 */
+ EREPL_INTLFILTER_SECLESSTHANV62, /* 289 */
+ EREPL_FILTERTIMEDOUT, /* 290 */
+ EREPL_MAXERRNO /* 291 */
};
#endif
diff --git a/sr_port/repl_filter.c b/sr_port/repl_filter.c
index 6a9d933..11743c8 100644
--- a/sr_port/repl_filter.c
+++ b/sr_port/repl_filter.c
@@ -60,35 +60,37 @@
#include "gtm_c_stack_trace.h"
#include "fork_init.h"
#endif
-#ifdef DEBUG
#include "wbox_test_init.h"
-#endif
#ifdef GTM_USE_POLL_FOR_SUBSECOND_SELECT
#include <sys/poll.h>
#endif
+#ifdef GTM_TRIGGER
+#include "trigger.h"
+#endif
-#define NULLSUBSC_TRANSFORM_IF_NEEDED(PTR) \
-{ \
- int keylen; \
- uchar_ptr_t lclptr; \
- DCL_THREADGBL_ACCESS; \
- \
- SETUP_THREADGBL_ACCESS; \
- if (REMOTE_NULL_SUBS_XFORM) \
- { \
- assert(SIZEOF(jnl_str_len_t) == SIZEOF(uint4)); \
- keylen = *((jnl_str_len_t *)(PTR)); \
- keylen &= 0xFFFFFF; /* to remove 8-bit nodeflags if any */ \
- lclptr = PTR + SIZEOF(jnl_str_len_t); \
- if (STDNULL_TO_GTMNULL_COLL == REMOTE_NULL_SUBS_XFORM) \
- { \
- STD2GTMNULLCOLL(lclptr, keylen); \
- } else \
- { \
- GTM2STDNULLCOLL(lclptr, keylen); \
- } \
- } \
-} \
+/* Do not apply null subscript transformations to LGTRIG and ZTWORM type records */
+#define NULLSUBSC_TRANSFORM_IF_NEEDED(RECTYPE, PTR) \
+{ \
+ int keylen; \
+ uchar_ptr_t lclptr; \
+ DCL_THREADGBL_ACCESS; \
+ \
+ SETUP_THREADGBL_ACCESS; \
+ if (!IS_ZTWORM(rectype) && !IS_LGTRIG(rectype) && REMOTE_NULL_SUBS_XFORM) \
+ { \
+ assert(SIZEOF(jnl_str_len_t) == SIZEOF(uint4)); \
+ keylen = *((jnl_str_len_t *)(PTR)); \
+ keylen &= 0xFFFFFF; /* to remove 8-bit nodeflags if any */ \
+ lclptr = PTR + SIZEOF(jnl_str_len_t); \
+ if (STDNULL_TO_GTMNULL_COLL == REMOTE_NULL_SUBS_XFORM) \
+ { \
+ STD2GTMNULLCOLL(lclptr, keylen); \
+ } else \
+ { \
+ GTM2STDNULLCOLL(lclptr, keylen); \
+ } \
+ } \
+} \
#define BREAK_IF_BADREC(RECLEN, STATUS) \
{ \
@@ -202,7 +204,8 @@
nodelen = *((uint4 *)jb); \
assert(tail_minus_suffix_len >= (SIZEOF(jnl_str_len_t) + nodelen)); \
memcpy(cb, jb, tail_minus_suffix_len); \
- NULLSUBSC_TRANSFORM_IF_NEEDED(cb); \
+ /* V17 did not support triggers, no need to send the actual rectype */ \
+ NULLSUBSC_TRANSFORM_IF_NEEDED(SET_KILL_ZKILL_MASK , cb); \
jb += tail_minus_suffix_len; \
cb += tail_minus_suffix_len; \
}
@@ -272,7 +275,8 @@
*/ \
((jnl_string *)cb)->nodeflags = 0; \
GET_JREC_UPD_TYPE(jb, trigupd_type); \
- NULLSUBSC_TRANSFORM_IF_NEEDED(cb); \
+ /* Caller excludes ZTWORM and LGTRIG already, no need to send the actual rectype */ \
+ NULLSUBSC_TRANSFORM_IF_NEEDED(SET_KILL_ZKILL_MASK , cb); \
jb += tail_minus_suffix_len; \
cb += tail_minus_suffix_len; \
}
@@ -408,26 +412,28 @@ enum
GBLDEF intlfltr_t repl_filter_cur2old[JNL_VER_THIS - JNL_VER_EARLIEST_REPL + 1] =
{
- IF_24TO17, /* Convert from filter format V24 to V17 (i.e., from jnl ver V24 to V17) */
- IF_24TO17, /* Convert from filter format V24 to V17 (i.e., from jnl ver V24 to V18) */
- IF_24TO19, /* Convert from filter format V24 to V19 (i.e., from jnl ver V24 to V19) */
- IF_24TO19, /* Convert from filter format V24 to V19 (i.e., from jnl ver V24 to V20) */
- IF_24TO21, /* Convert from filter format V24 to V21 (i.e., from jnl ver V24 to V21) */
- IF_24TO22, /* Convert from filter format V24 to V22 (i.e., from jnl ver V24 to V22) */
- IF_24TO22, /* Convert from filter format V24 to V22 (i.e., from jnl ver V24 to V23) */
- IF_24TO24 /* Convert from filter format V24 to V24 (i.e., from jnl ver V24 to V24) */
+ IF_24TO17, /* Convert from filter format V24 to V17 (i.e., from jnl ver V25 to V17) */
+ IF_24TO17, /* Convert from filter format V24 to V17 (i.e., from jnl ver V25 to V18) */
+ IF_24TO19, /* Convert from filter format V24 to V19 (i.e., from jnl ver V25 to V19) */
+ IF_24TO19, /* Convert from filter format V24 to V19 (i.e., from jnl ver V25 to V20) */
+ IF_24TO21, /* Convert from filter format V24 to V21 (i.e., from jnl ver V25 to V21) */
+ IF_24TO22, /* Convert from filter format V24 to V22 (i.e., from jnl ver V25 to V22) */
+ IF_24TO22, /* Convert from filter format V24 to V22 (i.e., from jnl ver V25 to V23) */
+ IF_24TO24, /* Convert from filter format V24 to V24 (i.e., from jnl ver V25 to V24) */
+ IF_24TO24 /* Convert from filter format V24 to V24 (i.e., from jnl ver V25 to V25) */
};
GBLDEF intlfltr_t repl_filter_old2cur[JNL_VER_THIS - JNL_VER_EARLIEST_REPL + 1] =
{
- IF_17TO24, /* Convert from filter format V17 to V24 (i.e., from jnl ver V17 to V24) */
- IF_17TO24, /* Convert from filter format V17 to V24 (i.e., from jnl ver V18 to V24) */
- IF_19TO24, /* Convert from filter format V19 to V24 (i.e., from jnl ver V19 to V24) */
- IF_19TO24, /* Convert from filter format V19 to V24 (i.e., from jnl ver V20 to V24) */
- IF_21TO24, /* Convert from filter format V21 to V24 (i.e., from jnl ver V21 to V24) */
- IF_22TO24, /* Convert from filter format V22 to V24 (i.e., from jnl ver V22 to V24) */
- IF_22TO24, /* Convert from filter format V22 to V24 (i.e., from jnl ver V23 to V24) */
- IF_24TO24 /* Convert from filter format V24 to V24 (i.e., from jnl ver V24 to V24) */
+ IF_17TO24, /* Convert from filter format V17 to V24 (i.e., from jnl ver V17 to V25) */
+ IF_17TO24, /* Convert from filter format V17 to V24 (i.e., from jnl ver V18 to V25) */
+ IF_19TO24, /* Convert from filter format V19 to V24 (i.e., from jnl ver V19 to V25) */
+ IF_19TO24, /* Convert from filter format V19 to V24 (i.e., from jnl ver V20 to V25) */
+ IF_21TO24, /* Convert from filter format V21 to V24 (i.e., from jnl ver V21 to V25) */
+ IF_22TO24, /* Convert from filter format V22 to V24 (i.e., from jnl ver V22 to V25) */
+ IF_22TO24, /* Convert from filter format V22 to V24 (i.e., from jnl ver V23 to V25) */
+ IF_24TO24, /* Convert from filter format V24 to V24 (i.e., from jnl ver V24 to V25) */
+ IF_24TO24 /* Convert from filter format V24 to V24 (i.e., from jnl ver V25 to V25) */
};
GBLREF unsigned int jnl_source_datalen, jnl_dest_maxdatalen;
@@ -447,6 +453,8 @@ GBLREF boolean_t heartbeat_started;
#endif
GBLREF uint4 process_id;
+LITREF char *trigger_subs[];
+
error_def(ERR_FILTERBADCONV);
error_def(ERR_FILTERCOMM);
error_def(ERR_FILTERNOTALIVE);
@@ -631,7 +639,8 @@ int repl_filter_init(char *filter_cmd)
gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLFILTER, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Could not exec filter"), ERRNO);
repl_errno = EREPL_FILTERSTART_EXEC;
- return(FILTERSTART_ERR);
+ UNIX_ONLY(_exit(FILTERSTART_ERR);)
+ VMS_ONLY(return(FILTERSTART_ERR);) /* maintain existing for VMS */
}
} else
{ /* Error in fork */
@@ -1201,53 +1210,6 @@ void repl_check_jnlver_compat(UNIX_ONLY(boolean_t same_endianness))
# endif
}
-static void upgrd_V19_hasht_xecute_string_to_V24(uchar_ptr_t jb, uchar_ptr_t cb, jnl_string *keystr, char *xecute_val_ptr,
- uint4 *conv_reclen)
-{ /* Upgrade the ^#t("GBL",1,"XECUTE") node's value to the xecute string format supported in V5.4-002 (and later).
- * Before V5.4-002, the xecute string is stored as-is in the database. But, from V5.4-002, the xecute string is
- * stored differently based on whether it is a single-line trigger xecute string or a multi-line trigger xecute
- * string. If former, the xecute string is prefixed with a <SPACE> character. If latter, no <SPACE> is prefixed.
- * Since, V5.4-001 does NOT support multi-line triggers, all we need is to prefix the xecute string with <SPACE>
- */
- uint4 tmp_jrec_size, jrec_size, align_fill_size;
- uchar_ptr_t srcptr;
- int valstrlen, new_valstrlen;
-
- /* An update-type journal record is formatted as follows:
- *
- * [FIXED_UPD_RECLEN][KEYLEN][NODEFLAGS][KEY][\0][VALUE_LEN][VALUE][PADDING_ZEROS][JREC_SUFFIX_SIZE]
- *
- * The input parameter 'xecute_val_ptr' points to the beginning of VALUE_LEN in the above journal format. Since
- * <SPACE> is added to the xecute string, this will affect the VALUE_LEN, PADDING_ZEROS, record length.
- * Note: 'cb' already has a copy of 'jb' and 'xecute_val_ptr' is a pointer inside 'cb'
- */
- GET_MSTR_LEN(valstrlen, xecute_val_ptr); /* get the length of the value */
- new_valstrlen = valstrlen + 1;
- PUT_MSTR_LEN(xecute_val_ptr, new_valstrlen);
- /* new record size and padding byte calculations */
- tmp_jrec_size = FIXED_UPD_RECLEN
- + SIZEOF(jnl_str_len_t) + keystr->length
- + SIZEOF(mstr_len_t) + (valstrlen + 1)
- + JREC_SUFFIX_SIZE;
- jrec_size = ROUND_UP2(tmp_jrec_size, JNL_REC_START_BNDRY); /* new record size (aligned to 8 byte boundary) */
- align_fill_size = jrec_size - tmp_jrec_size; /* necessary padding bytes */
- /* add <SPACE> and copy the xecute string */
- xecute_val_ptr += SIZEOF(mstr_len_t); /* move to the beginning of the 'value' */
- srcptr = jb + ((uchar_ptr_t)xecute_val_ptr - cb - 8); /* pointer to the xecute string from the source buffer.
- * -8 needed because "strm_seqno" is absent in source. */
- *xecute_val_ptr++ = ' '; /* add the much needed <SPACE> */
- memcpy(xecute_val_ptr, srcptr, valstrlen); /* copy the actual xecute string */
- xecute_val_ptr += valstrlen;
- memset(xecute_val_ptr, 0, align_fill_size); /* padding zeros for 8 byte alignment */
- xecute_val_ptr += align_fill_size; /* points to suffix */
- /* fill suffix */
- ((jrec_suffix *)(xecute_val_ptr))->backptr = jrec_size;
- ((jrec_suffix *)(xecute_val_ptr))->suffix_code = JNL_REC_SUFFIX_CODE;
- assert((0 != *conv_reclen) && !(*conv_reclen % JNL_REC_START_BNDRY));
- if (*conv_reclen != jrec_size)
- ((jrec_prefix *)(cb))->forwptr = *conv_reclen = jrec_size;
-}
-
/* The following code defines the functions that convert one jnl format to another.
* The only replicated records we expect to see here are *SET* or *KILL* or TCOM or NULL records.
* These fall under the following 3 structure types each of which is described for the different jnl formats we handle.
@@ -1336,6 +1298,7 @@ static void upgrd_V19_hasht_xecute_string_to_V24(uchar_ptr_t jb, uchar_ptr_t cb,
* This means, we need to have 8 more bytes in the conversion buffer for NULL type of records.
* (d) If the null collation is different between primary and secondary (null_subs_xform) then appropriate conversion
* is needed
+ * (e) Note that V17 did not support triggers so dont need to check for ^#t or ZTRIG or ZTWORM or LGTRIG records.
* Reformat accordingly.
*/
int jnl_v17TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, uint4 *conv_len, uint4 conv_bufsiz)
@@ -1432,7 +1395,7 @@ int jnl_v17TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
* (a) Since the remote side (V17) does NOT support triggers, skip ^#t, ZTWORM/LGTRIG/ZTRIG journal records
* & reset nodeflags (if set). If the entire transaction consists of skipped records, send a NULL record instead.
*
- * Note: Although (1) is trigger specific, the logic should be available for trigger non-supporting platorms as well to
+ * Note: Although (a) is trigger specific, the logic should be available for trigger non-supporting platorms as well to
* handle replication scenarios like V5.4-001 (TS) -> V5.4-002 (NTS) -> V4.4-004 (NTS) where TS indicates a trigger supporting
* platform and NTS indicates either a version without trigger support OR is running on trigger non-supporting platform.
*/
@@ -1446,7 +1409,7 @@ int jnl_v24TOv17(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
jrec_prefix *prefix;
seq_num this_upd_seqno;
uint4 trigupd_type = NO_TRIG_JREC;
- DEBUG_ONLY(boolean_t non_ztrig_rec_found = FALSE;)
+ DEBUG_ONLY(boolean_t non_trig_rec_found = FALSE;)
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
@@ -1490,10 +1453,7 @@ int jnl_v24TOv17(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
jb += t_len;
if (is_set_kill_zkill_ztrig)
{
- DEBUG_ONLY(
- if (!IS_ZTRIG(rectype))
- non_ztrig_rec_found = TRUE;
- )
+ DEBUG_ONLY(non_trig_rec_found = TRUE;)
assert((cb - cstart) == (OFFSETOF(struct_jrec_upd, token_seq) + SIZEOF(token_seq_t)));
/* side-effect: increments cb and jb and GTM Null Collation or Standard Null Collation applied */
INITIALIZE_V17_MUMPS_NODE_FROM_V24(cstart, cb, jstart, jb, trigupd_type, FALSE);
@@ -1586,7 +1546,7 @@ int jnl_v24TOv17(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
* (b) If the only records in a transaction are ZTRIG records and a TCOM record.
* In both the above cases we need to send a NULL record instead.
*/
- assert((HASHT_JREC == trigupd_type) || (FALSE == non_ztrig_rec_found));
+ assert((HASHT_JREC == trigupd_type) || (FALSE == non_trig_rec_found));
prefix = (jrec_prefix *)(cb);
if (V17_NULL_RECLEN > conv_bufsiz)
{
@@ -1610,8 +1570,8 @@ int jnl_v24TOv17(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
* (b) If the receiver side does NOT support triggers, then skip ^#t/ZTWORM journal records & reset nodeflags (if set).
* Note that V19 did not support ZTRIG or LGTRIG records so dont need to check for them.
* If the entire transaction consists of skipped records, send a NULL record instead.
- * (c) If receiver side does support triggers, then fix ^#t("GBL","#LABEL") and ^#t("GBL",1,"XECUTE") to reflect newer format.
- *
+ * (c) If receiver side does support triggers, then issue error if ^#t records are found as those are not allowed in
+ * the replication stream from V62001 onwards.
* Note : For both (a) and (b), ZTRIG type of records are not possible in V19 (they start only from V21).
* Reformat accordingly.
*/
@@ -1676,6 +1636,14 @@ int jnl_v19TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
jb = jb + reclen;
jlen -= reclen;
continue;
+ } else if (HASHT_JREC == trigupd_type)
+ { /* Journal record has a #t global. #t records are no longer allowed to V24,
+ * only LGTRIG records are. But since the source version does not support
+ * LGTRIG records, issue error.
+ */
+ repl_errno = EREPL_INTLFILTER_PRILESSTHANV62;
+ status = -1;
+ break;
}
} else if (HASHT_JREC == trigupd_type)
{ /* Journal record has a #t global. #t records are not replicated if the secondary does not
@@ -1696,38 +1664,9 @@ int jnl_v19TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
memcpy(cb + V19_UPDATE_NUM_OFFSET + 8, jb + V19_UPDATE_NUM_OFFSET,
conv_reclen - 8 - V19_UPDATE_NUM_OFFSET);
mumps_node_ptr = cstart + V24_MUMPS_NODE_OFFSET;
- if (HASHT_JREC == trigupd_type)
- { /* ^#t record */
- assert(receiver_supports_triggers);
- keystr = (jnl_string *)mumps_node_ptr;
- keyend = &keystr->text[keystr->length - 1];
- if (!MEMCMP_LIT((keyend - LITERAL_HASHLABEL_LEN), LITERAL_HASHLABEL))
- { /* ^#t("GBL","#LABEL") found. Adjust the value of this node to be equal to
- * HASHT_GBL_CURLABEL as the secondary is the latest trigger supported version.
- * But, we should do this ONLY if this is a SET record.
- */
- if (IS_SET(rectype))
- { /* Upgrade the #LABEL to the current version's #LABEL */
- /* '+ 1' below is to account for '- 1' done above */
- ptr = keyend + SIZEOF(mstr_len_t) + 1;
- assert(0 == MEMCMP_LIT(ptr, V19_HASHT_GBL_LABEL));
- assert(STR_LIT_LEN(HASHT_GBL_CURLABEL) == STR_LIT_LEN(V19_HASHT_GBL_LABEL));
- MEMCPY_LIT(ptr, HASHT_GBL_CURLABEL);
- }
- } else if (!MEMCMP_LIT(keyend - LITERAL_XECUTE_LEN, LITERAL_XECUTE))
- { /* ^#t("GBL",1,"XECUTE") found. Upgrade it to the current version's XECUTE format */
- assert(IS_SET(rectype)); /* This better be a SET record */
- if (IS_SET(rectype))
- { /* do the upgrade in PRO only if this is a SET record */
- upgrd_V19_hasht_xecute_string_to_V24(jb, cb, keystr, keyend + 1,
- &conv_reclen);
- assert(0 == conv_reclen % JNL_REC_START_BNDRY);
- }
- }
- }
if (!receiver_supports_triggers)
((jnl_string *)mumps_node_ptr)->nodeflags = 0;
- NULLSUBSC_TRANSFORM_IF_NEEDED(mumps_node_ptr);
+ NULLSUBSC_TRANSFORM_IF_NEEDED(rectype, mumps_node_ptr);
if (IS_TUPD(rectype))
tupd_num++;
else if (IS_UUPD(rectype) && promote_uupd_to_tupd)
@@ -1836,9 +1775,9 @@ int jnl_v24TOv19(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
jrec_prefix *prefix;
seq_num this_upd_seqno;
uint4 trigupd_type = NO_TRIG_JREC;
- boolean_t promote_uupd_to_tupd, hasht_update_found, normal_update_found, receiver_supports_triggers;
+ boolean_t promote_uupd_to_tupd, receiver_supports_triggers;
boolean_t hasht_seen;
- DEBUG_ONLY(boolean_t non_ztrig_rec_found = FALSE;)
+ DEBUG_ONLY(boolean_t non_trig_rec_found = FALSE;)
jnl_string *keystr;
DCL_THREADGBL_ACCESS;
@@ -1848,7 +1787,7 @@ int jnl_v24TOv19(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
status = SS_NORMAL;
jlen = *jnl_len;
QWASSIGN(this_upd_seqno, seq_num_zero);
- promote_uupd_to_tupd = hasht_update_found = normal_update_found = FALSE;
+ promote_uupd_to_tupd = FALSE;
hasht_seen = FALSE;
assert(is_src_server);
/* Since this filter function will be invoked only on the source side, the check for whether the receiver
@@ -1897,15 +1836,19 @@ int jnl_v24TOv19(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
if (IS_SET_KILL_ZKILL_ZTWORM(rectype))
{
assert((cb == cstart) && (jb == jstart));
- DEBUG_ONLY(
- if (!IS_ZTRIG(rectype))
- non_ztrig_rec_found = TRUE;
- )
+ DEBUG_ONLY(non_trig_rec_found = TRUE;)
GET_JREC_UPD_TYPE(jb + V24_MUMPS_NODE_OFFSET, trigupd_type);
if (receiver_supports_triggers)
{
- if (!normal_update_found)
- normal_update_found = (HASHT_JREC != trigupd_type);
+ if (HASHT_JREC == trigupd_type)
+ { /* Journal record has a #t global. #t records are no longer allowed from V24,
+ * only LGTRIG records are. But since the receiver version does not support
+ * LGTRIG records, issue error.
+ */
+ repl_errno = EREPL_INTLFILTER_SECLESSTHANV62;
+ status = -1;
+ break;
+ }
if (NON_REPLIC_JREC_TRIG == trigupd_type)
{
if (IS_TUPD(rectype))
@@ -1931,57 +1874,9 @@ int jnl_v24TOv19(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
/* t_len bytes have already been copied. Skip 8-byte strm_seqno (absent in V19) and copy rest */
memcpy(cb + t_len, jb + t_len + 8, conv_reclen - t_len);
mumps_node_ptr = (cb + V19_MUMPS_NODE_OFFSET);
- if (HASHT_JREC == trigupd_type)
- {
- assert(receiver_supports_triggers);
- if (!hasht_update_found)
- hasht_update_found = TRUE;
- /* Since the secondary side is running on an older trigger-supporting version than the
- * primary, the ^#t("GBL","#LABEL") value needs to be adjusted to have the value that the
- * secondary will understand. Not doing so will cause the secondary to issue TRIGDEFBAD
- * error.
- */
- keystr = (jnl_string *)mumps_node_ptr;
- keyend = &keystr->text[keystr->length - 1];
- assert('\0' == *keyend); /* we better have a null terminator at the end of the key */
- if (!MEMCMP_LIT((keyend - LITERAL_HASHLABEL_LEN), LITERAL_HASHLABEL))
- { /* ^#t("GBL","#LABEL") found. For details on the update record layout, see the
- * comment in upgrd_hasht_xecute_string
- */
- ptr = keyend + SIZEOF(mstr_len_t) + 1; /* '+ 1' to account for '- 1' done above */
- assert(0 == MEMCMP_LIT(ptr, HASHT_GBL_CURLABEL));
- assert(STR_LIT_LEN(HASHT_GBL_CURLABEL) == STR_LIT_LEN(V19_HASHT_GBL_LABEL));
- MEMCPY_LIT(ptr, V19_HASHT_GBL_LABEL);
- } else if (0x80 == (unsigned char)(*(keyend - 1)))
- { /* last subscript is zero. Check if the preceding subscript is "XECUTE" */
- ptr = keyend - 2; /* -1 for 0x80 and -1 for null terminator */
- if (!MEMCMP_LIT((ptr - LITERAL_XECUTE_LEN), LITERAL_XECUTE))
- { /* preceding subscript is "XECUTE". Ensure the preceding character is \0 */
- ptr -= (LITERAL_XECUTE_LEN + 1); /* +1 for the leading \0 */
- assert(STR_SUB_PREFIX == ((unsigned char)(*ptr)));
- if (STR_SUB_PREFIX == ((unsigned char)(*ptr)))
- { /* found ^#t("GBL",1,"XECUTE",0) which V5.4-001 secondary does
- * NOT understand
- */
- repl_errno = EREPL_INTLFILTER_MULTILINEXECUTE;
- status = -1;
- break;
- }
- }
- }
- }
if (!receiver_supports_triggers)
((jnl_string *)mumps_node_ptr)->nodeflags = 0;
- else if (hasht_update_found && normal_update_found)
- { /* A mix of ^#t updates and normal updates. Secondary (V5.4-000 to V5.4-001) does not
- * understand mix of such updates. Set error status and break. Replication cannot
- * continue unless $ztrigger() in TP (along with other updates) is eliminated.
- */
- repl_errno = EREPL_INTLFILTER_SECNODZTRIGINTP;
- status = -1;
- break;
- }
- NULLSUBSC_TRANSFORM_IF_NEEDED(mumps_node_ptr);
+ NULLSUBSC_TRANSFORM_IF_NEEDED(rectype, mumps_node_ptr);
if (IS_TUPD(rectype))
tupd_num++;
else if (IS_UUPD(rectype) && promote_uupd_to_tupd)
@@ -2032,7 +1927,7 @@ int jnl_v24TOv19(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
* (b) If the only records in a transaction are ZTRIG records and a TCOM record.
* In both the above cases we need to send a NULL record instead.
*/
- assert((HASHT_JREC == trigupd_type) || (FALSE == non_ztrig_rec_found));
+ assert((HASHT_JREC == trigupd_type) || (FALSE == non_trig_rec_found));
prefix = (jrec_prefix *)(cb);
if (NULL_RECLEN > conv_bufsiz)
{
@@ -2058,10 +1953,11 @@ int jnl_v24TOv19(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
* (b) If the receiver side does NOT support triggers, then skip ^#t/ZTWORM/ZTRIG journal records & reset nodeflags (if set).
* Note that V21 did not support LGTRIG records so dont need to check for them.
* If the entire transaction consists of skipped records, send a NULL record instead.
+ * (c) If receiver side does support triggers, then issue error if ^#t records are found as those are not allowed in
+ * the replication stream from V62001 onwards.
* Reformat accordingly.
* Note: This function (jnl_v21TOv24) is somewhat similar to jnl_v19TOv24 except that ZTRIG records can be seen in v21
- * whereas it cannot be in v19. In addition, no ^#t("GBL","#LABEL") or ^#t("GBL",1,"XECUTE") conversions are needed
- * since the ^#t format is unchanged between V21 and V24.
+ * whereas it cannot be in v19.
*/
int jnl_v21TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, uint4 *conv_len, uint4 conv_bufsiz)
{
@@ -2134,6 +2030,14 @@ int jnl_v21TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
jb = jb + reclen;
jlen -= reclen;
continue;
+ } else if (HASHT_JREC == trigupd_type)
+ { /* Journal record has a #t global. #t records are no longer allowed to V24,
+ * only LGTRIG records are. But since the source version does not support
+ * LGTRIG records, issue error.
+ */
+ repl_errno = EREPL_INTLFILTER_PRILESSTHANV62;
+ status = -1;
+ break;
}
} else if (HASHT_JREC == trigupd_type)
{ /* Journal record has a #t global. #t records are not replicated if the secondary
@@ -2159,7 +2063,7 @@ int jnl_v21TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
/* V21 and V24 have same ^#t("GBL","#LABEL") value so no need to fix like is done for V19 to V24 */
if (!receiver_supports_triggers)
((jnl_string *)mumps_node_ptr)->nodeflags = 0;
- NULLSUBSC_TRANSFORM_IF_NEEDED(mumps_node_ptr);
+ NULLSUBSC_TRANSFORM_IF_NEEDED(rectype, mumps_node_ptr);
if (IS_TUPD(rectype))
tupd_num++;
else if (IS_UUPD(rectype) && promote_uupd_to_tupd)
@@ -2243,7 +2147,7 @@ int jnl_v21TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
* For differences between the two versions, see the comment in jnl_v19TOv24. In addition, take care of the following.
* (a) If the remote side does NOT support triggers, then skip ^#t/ZTWORM/ZTRIG/LGTRIG journal records.
* If the entire transaction consists of skipped records, send a NULL record instead.
- * (b) If remote side does support triggers, then skip LGTRIG journal records as they are not known to the older journal format.
+ * (b) If remote side supports triggers, then error out for LGTRIG journal records as they are unknown to the older journal format.
* Note: This function (jnl_v21TOv24) is somewhat similar to jnl_v24TOv19 except that ZTRIG records can be seen in v21
* whereas it cannot be in v19. In addition, no ^#t("GBL","#LABEL") or ^#t("GBL",1,"XECUTE") conversions are needed
* since the ^#t format is unchanged between V21 and V24.
@@ -2323,6 +2227,15 @@ int jnl_v24TOv21(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
GET_JREC_UPD_TYPE(jb + V24_MUMPS_NODE_OFFSET, trigupd_type);
if (receiver_supports_triggers)
{
+ if (HASHT_JREC == trigupd_type)
+ { /* Journal record has a #t global. #t records are no longer allowed from V24,
+ * only LGTRIG records are. But since the receiver version does not support
+ * LGTRIG records, issue error.
+ */
+ repl_errno = EREPL_INTLFILTER_SECLESSTHANV62;
+ status = -1;
+ break;
+ }
if (NON_REPLIC_JREC_TRIG == trigupd_type)
{
if (IS_TUPD(rectype))
@@ -2352,7 +2265,7 @@ int jnl_v24TOv21(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
mumps_node_ptr = (cb + V19_MUMPS_NODE_OFFSET);
if (!receiver_supports_triggers)
((jnl_string *)mumps_node_ptr)->nodeflags = 0;
- NULLSUBSC_TRANSFORM_IF_NEEDED(mumps_node_ptr);
+ NULLSUBSC_TRANSFORM_IF_NEEDED(rectype, mumps_node_ptr);
if (IS_TUPD(rectype))
tupd_num++;
else if (IS_UUPD(rectype) && promote_uupd_to_tupd)
@@ -2424,7 +2337,9 @@ int jnl_v24TOv21(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
* (a) If null-subscript collation is different between the primary and the secondary
* (b) If the remote side does NOT support triggers, then skip ^#t/ZTWORM/ZTRIG journal records & reset nodeflags (if set).
* Note that V22 did not support LGTRIG records so dont need to check for them.
- * (c) If the entire transaction consists of skipped records, send a NULL record instead.
+ * (c) If the entire transaction consists of skipped records, send a NULL record instead.
+ * (d) If receiver side does support triggers, then issue error if ^#t records are found as those are not allowed in
+ * the replication stream from V62001 onwards.
*/
int jnl_v22TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, uint4 *conv_len, uint4 conv_bufsiz)
{
@@ -2467,7 +2382,7 @@ int jnl_v22TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
this_strm_seqno = GET_STRM_SEQNO(jb);
}
assert(IS_REPLICATED(rectype));
- assert(JRT_MAX_V23 >= rectype);
+ assert(JRT_MAX_V22 >= rectype);
if (IS_TUPD(rectype))
promote_uupd_to_tupd = FALSE;
if (!receiver_supports_triggers && (IS_ZTRIG(rectype) || IS_ZTWORM(rectype)))
@@ -2499,6 +2414,14 @@ int jnl_v22TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
jb = jb + reclen;
jlen -= reclen;
continue;
+ } else if (HASHT_JREC == trigupd_type)
+ { /* Journal record has a #t global. #t records are no longer allowed to V24,
+ * only LGTRIG records are. But since the source version does not support
+ * LGTRIG records, issue error.
+ */
+ repl_errno = EREPL_INTLFILTER_PRILESSTHANV62;
+ status = -1;
+ break;
}
} else if (HASHT_JREC == trigupd_type)
{ /* Journal record has a #t global. #t records are not replicated if the secondary does not
@@ -2519,7 +2442,7 @@ int jnl_v22TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
mumps_node_ptr = cb + FIXED_UPD_RECLEN;
if (!receiver_supports_triggers)
((jnl_string *)mumps_node_ptr)->nodeflags = 0;
- NULLSUBSC_TRANSFORM_IF_NEEDED(mumps_node_ptr);
+ NULLSUBSC_TRANSFORM_IF_NEEDED(rectype, mumps_node_ptr);
if (IS_TUPD(rectype))
tupd_num++;
else if (IS_UUPD(rectype) && promote_uupd_to_tupd)
@@ -2586,7 +2509,7 @@ int jnl_v22TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
/* Convert a transaction from jnl version V24 (V6.2-000 onwards) to V22/V23 (V5.5-000 thru V6.1-000).
* (a) If null-subscript collation is different between the primary and the secondary
* (b) If the remote side does NOT support triggers, then skip ^#t/ZTWORM/ZTRIG journal records & reset nodeflags (if set).
- * Note that V22 did not support LGTRIG records so dont need to check for them.
+ * Note that V22 did not support LGTRIG records so issue an error.
* (c) If remote side does support triggers, then skip LGTRIG journal records as they are not known to the older journal format.
* (d) If the entire transaction consists of skipped records, send a NULL record instead.
*/
@@ -2656,6 +2579,15 @@ int jnl_v24TOv22(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
GET_JREC_UPD_TYPE((jb + FIXED_UPD_RECLEN), trigupd_type);
if (receiver_supports_triggers)
{
+ if (HASHT_JREC == trigupd_type)
+ { /* Journal record has a #t global. #t records are no longer allowed from V24,
+ * only LGTRIG records are. But since the receiver version does not support
+ * LGTRIG records, issue error.
+ */
+ repl_errno = EREPL_INTLFILTER_SECLESSTHANV62;
+ status = -1;
+ break;
+ }
if (NON_REPLIC_JREC_TRIG == trigupd_type)
{
if (IS_TUPD(rectype))
@@ -2684,7 +2616,7 @@ int jnl_v24TOv22(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
mumps_node_ptr = cb + FIXED_UPD_RECLEN;
if (!receiver_supports_triggers)
((jnl_string *)mumps_node_ptr)->nodeflags = 0;
- NULLSUBSC_TRANSFORM_IF_NEEDED(mumps_node_ptr);
+ NULLSUBSC_TRANSFORM_IF_NEEDED(rectype, mumps_node_ptr);
if (IS_TUPD(rectype))
tupd_num++;
else if (IS_UUPD(rectype) && promote_uupd_to_tupd)
@@ -2749,7 +2681,7 @@ int jnl_v24TOv22(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
return(status);
}
-/* Convert a transaction from jnl version V24 (V6.2-000 onwards) to V24 (V6.2-000 onwards).
+/* Convert a transaction from filter format V24 (V6.2-000 onwards) to V24 (V6.2-000 onwards).
* Same version filters are needed if one of the below is true.
* (a) If null-subscript collation is different between the primary and the secondary
* (b) If the remote side does NOT support triggers, then skip ^#t/ZTWORM/LGTRIG/ZTRIG journal records & reset nodeflags (if set).
@@ -2776,12 +2708,15 @@ int jnl_v24TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
jlen = *jnl_len;
this_upd_seqno = seq_num_zero;
promote_uupd_to_tupd = FALSE;
- /* The following assert ensures that filtering is initiated by the responsible party and in the expected direction. */
- assert(is_src_server);
- /* Since this filter function will be invoked only on the source side, the check for whether the receiver
- * supports triggers is equal to checking whether the REMOTE side supports triggers.
+ /* Since filter format V24 corresponds to journal format V24 or V25, in case of a V24 source and V25 receiver,
+ * the source server will not do any filter transformations (because receiver jnl ver is higher). This means
+ * jnl_v24TOv24 filter conversion function will be invoked on the receiver side to do V24 to V25 jnl format conversion.
+ * Therefore we cannot do an assert(is_src_server) which we otherwise would have had in case the latest filter
+ * version corresponds to only ONE journal version.
+ * assert(is_src_server);
*/
- receiver_supports_triggers = REMOTE_TRIGGER_SUPPORT;
+ assert(is_src_server || is_rcvr_server);
+ receiver_supports_triggers = (is_src_server ? REMOTE_TRIGGER_SUPPORT : LOCAL_TRIGGER_SUPPORT);
GTMTRIG_ONLY(assert(receiver_supports_triggers);) /* if receiver is V24 format, it should have been built
* with trigger support enabled since we dont either build
* anymore OR replicate anymore to trigger unsupported platforms
@@ -2850,7 +2785,7 @@ int jnl_v24TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
mumps_node_ptr = cb + FIXED_UPD_RECLEN;
if (!receiver_supports_triggers)
((jnl_string *)mumps_node_ptr)->nodeflags = 0;
- NULLSUBSC_TRANSFORM_IF_NEEDED(mumps_node_ptr);
+ NULLSUBSC_TRANSFORM_IF_NEEDED(rectype, mumps_node_ptr);
if (IS_TUPD(rectype))
tupd_num++;
else if (IS_UUPD(rectype) && promote_uupd_to_tupd)
diff --git a/sr_port/repl_filter.h b/sr_port/repl_filter.h
index 2d80eda..c058ea9 100644
--- a/sr_port/repl_filter.h
+++ b/sr_port/repl_filter.h
@@ -69,6 +69,7 @@ typedef int (*intlfltr_t)(uchar_ptr_t, uint4 *, uchar_ptr_t, uint4 *, uint4);
* V22 V22 GT.M V5.5-000 strm_seqno added to all logical records (supplementary instances)
* V22 V23 GT.M V6.0-000 Various journaling-related limits have changed, allowing for much larger journal records
* V24 V24 GT.M V6.2-000 New logical trigger journal record (TLGTRIG and ULGTRIG jnl records)
+ * V24 V25 GT.M V6.2-001 No new jnl record but bump needed to replicate logical trigger jnl records (GTM-7509)
*/
typedef enum
@@ -92,6 +93,7 @@ typedef enum
REPL_JNL_V22, /* enum corresponding to journal format V22 */
REPL_JNL_V23, /* enum corresponding to journal format V23 */
REPL_JNL_V24, /* enum corresponding to journal format V24 */
+ REPL_JNL_V25, /* enum corresponding to journal format V25 */
REPL_JNL_MAX
} repl_jnl_t;
@@ -140,6 +142,8 @@ GBLREF intlfltr_t repl_filter_cur2old[JNL_VER_THIS - JNL_VER_EARLIEST_REPL + 1];
* EREPL_INTLFILTER_INCMPLREC - incomplete record in the filter buffer.
* EREPL_INTLFILTER_NEWREC - cannot convert record, the record is newer than the "to" version.
* EREPL_INTLFILTER_REPLGBL2LONG - record contains global name > 8 characters, which is not supported in remote side
+ * EREPL_INTLFILTER_SECLESSTHANV62 - record contains #t global which is not allowed when source side is > V62000
+ * EREPL_INTLFILTER_PRILESSTHANV62 - record contains #t global which is not allowed when receiver side is > V62000
* In all error cases, conv_len will be the offset at which processing was stopped.
*/
@@ -156,6 +160,7 @@ GBLREF intlfltr_t repl_filter_cur2old[JNL_VER_THIS - JNL_VER_EARLIEST_REPL + 1];
#define V22_JNL_VER 22
#define V23_JNL_VER 23
#define V24_JNL_VER 24
+#define V25_JNL_VER 25
#define V17_NULL_RECLEN 40 /* size of a JRT_NULL record in V17/V18 jnl format */
#define V19_NULL_RECLEN 40 /* size of a JRT_NULL record in V19/V20 jnl format */
@@ -252,19 +257,28 @@ void repl_filter_error(seq_num filter_seqno, int why);
assert(0 < OUT_BUFSIZ); \
}
+/* Below error_defs are needed by the following macros */
+error_def(ERR_REPLRECFMT);
+error_def(ERR_REPLGBL2LONG);
+error_def(ERR_REPLNOHASHTREC);
+
#ifdef UNIX
-# define INT_FILTER_RTS_ERROR(FILTER_SEQNO) \
-{ \
- if (EREPL_INTLFILTER_BADREC == repl_errno) \
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REPLRECFMT); \
- else if (EREPL_INTLFILTER_REPLGBL2LONG == repl_errno) \
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REPLGBL2LONG); \
- else if (EREPL_INTLFILTER_SECNODZTRIGINTP == repl_errno) \
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_SECNODZTRIGINTP, 1, &FILTER_SEQNO); \
- else if (EREPL_INTLFILTER_MULTILINEXECUTE == repl_errno) \
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_REPLNOMULTILINETRG, 1, &FILTER_SEQNO); \
- else /* (EREPL_INTLFILTER_INCMPLREC == repl_errno) */ \
- assertpro(FALSE); \
+# define INT_FILTER_RTS_ERROR(FILTER_SEQNO, REPL_ERRNO) \
+{ \
+ assert((EREPL_INTLFILTER_BADREC == REPL_ERRNO) \
+ || (EREPL_INTLFILTER_REPLGBL2LONG == REPL_ERRNO) \
+ || (EREPL_INTLFILTER_PRILESSTHANV62 == REPL_ERRNO) \
+ || (EREPL_INTLFILTER_SECLESSTHANV62 == REPL_ERRNO)); \
+ if (EREPL_INTLFILTER_BADREC == REPL_ERRNO) \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REPLRECFMT); \
+ else if (EREPL_INTLFILTER_REPLGBL2LONG == REPL_ERRNO) \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REPLGBL2LONG); \
+ else if (EREPL_INTLFILTER_PRILESSTHANV62 == REPL_ERRNO) \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_REPLNOHASHTREC, 3, &FILTER_SEQNO, LEN_AND_LIT("Source")); \
+ else if (EREPL_INTLFILTER_SECLESSTHANV62 == REPL_ERRNO) \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_REPLNOHASHTREC, 3, &FILTER_SEQNO, LEN_AND_LIT("Receiver")); \
+ else /* (EREPL_INTLFILTER_INCMPLREC == REPL_ERRNO) */ \
+ assertpro(FALSE); \
}
#else
# define INT_FILTER_RTS_ERROR(FILTER_SEQNO) \
diff --git a/sr_port/rtn_src_chksum.c b/sr_port/rtn_src_chksum.c
index 599b4ec..1095f14 100644
--- a/sr_port/rtn_src_chksum.c
+++ b/sr_port/rtn_src_chksum.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2013 Fidelity Information Services, Inc *
+ * Copyright 2013, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -31,7 +31,12 @@ error_def(ERR_FILENOTFND);
void rtn_src_chksum_init(gtm_rtn_src_chksum_ctx *ctx)
{
+# ifdef UNIX
+ HASH128_STATE_INIT(ctx->hash_state, 0);
+ ctx->total_size = 0;
+# else
cvs_MD5Init(&ctx->md5ctx);
+# endif
}
/*
@@ -40,16 +45,28 @@ void rtn_src_chksum_init(gtm_rtn_src_chksum_ctx *ctx)
void rtn_src_chksum_line(gtm_rtn_src_chksum_ctx *ctx, const void *data, uint4 len)
{
+# ifdef UNIX
+ gtmmrhash_128_ingest(&ctx->hash_state, data, len);
+ ctx->total_size += len;
+# else
cvs_MD5Update(&ctx->md5ctx, data, len);
+# endif
}
/*
- * Finished computing checksum. Fill in digest[] array from MD5 context.
+ * Finished computing checksum. Fill in digest[] array.
*/
void rtn_src_chksum_digest(gtm_rtn_src_chksum_ctx *ctx)
{
+# ifdef UNIX
+ gtm_uint16 hash;
+
+ gtmmrhash_128_result(&ctx->hash_state, ctx->total_size, &hash);
+ gtmmrhash_128_bytes(&hash, ctx->digest);
+# else
cvs_MD5Final(ctx->digest, &ctx->md5ctx);
+# endif
# ifndef GTM_USE_128BIT_SRC_CHKSUM
GET_ULONG(ctx->checksum, &ctx->digest[0]);
# endif
@@ -62,7 +79,7 @@ void rtn_src_chksum_digest(gtm_rtn_src_chksum_ctx *ctx)
void set_rtnhdr_checksum(rhdtyp *hdr, gtm_rtn_src_chksum_ctx *ctx)
{
# ifdef GTM_USE_128BIT_SRC_CHKSUM
- memcpy(&hdr->checksum_md5[0], &ctx->digest[0], MD5_DIGEST_LENGTH);
+ memcpy(&hdr->checksum_128[0], &ctx->digest[0], MD5_DIGEST_LENGTH);
# else
hdr->checksum = ctx->checksum;
# endif
@@ -89,7 +106,7 @@ void rtn_src_chksum_buffer(gtm_rtn_src_chksum_ctx *ctx, const void *data, uint4
unsigned char *get_rtnhdr_checksum(rhdtyp *hdr)
{
- return &hdr->checksum_md5[0];
+ return &hdr->checksum_128[0];
}
/*
diff --git a/sr_port/rtn_src_chksum.h b/sr_port/rtn_src_chksum.h
index ff02d43..76f4cc9 100644
--- a/sr_port/rtn_src_chksum.h
+++ b/sr_port/rtn_src_chksum.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2013 Fidelity Information Services, Inc *
+ * Copyright 2013, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -20,12 +20,18 @@
#include "md5hash.h"
#ifdef UNIX
+# include "mmrhash.h"
# define GTM_USE_128BIT_SRC_CHKSUM
#endif
typedef struct
{
+# ifdef UNIX
+ hash128_state_t hash_state;
+ uint4 total_size;
+# else
cvs_MD5_CTX md5ctx;
+# endif
unsigned char digest[MD5_DIGEST_LENGTH];
# ifndef GTM_USE_128BIT_SRC_CHKSUM
uint4 checksum; /* 32-bit checksum, equals first 4 bytes of digest */
diff --git a/sr_port/s2n.c b/sr_port/s2n.c
index 21d43ed..ece8cda 100644
--- a/sr_port/s2n.c
+++ b/sr_port/s2n.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -32,6 +32,7 @@ char *s2n (mval *u)
SETUP_THREADGBL_ACCESS;
i = 0;
assertpro(MV_DEFINED(u));
+ ((mval_b *)u)->sgne = 0; /* Clear current sign/exponent to contant start value */
c = u->str.addr;
if (0 == u->str.len)
{ /* Substitute pre-converted NULL/0 value */
diff --git a/sr_port/srcline.h b/sr_port/srcline.h
index 04bab4b..9944a04 100644
--- a/sr_port/srcline.h
+++ b/sr_port/srcline.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -35,21 +35,24 @@ typedef struct
#ifdef GTM_TRIGGER
/* Macro to determine if a routine name is a trigger name - the answer is yes if
* the routine name contains a "#" which all triggers do. Args are mstr addr and boolean_t.
+ * Note: If # occurs after 31st byte, then it is treated as a non-trigger routine due to truncation.
*/
-# define IS_TRIGGER_RTN(RTNNAME, RSLT) \
-{ \
- unsigned char *cptr, *cptr_top; \
- \
- if (0 < (RTNNAME)->len) \
- { \
- for (cptr = (unsigned char *)(RTNNAME)->addr, cptr_top = cptr + (RTNNAME)->len - 1; cptr <= cptr_top; --cptr_top) \
- { \
- if ('#' == *cptr_top) \
- break; \
- } \
- RSLT = !(cptr > cptr_top); \
- } else \
- RSLT = FALSE; \
+# define IS_TRIGGER_RTN(RTNNAME, RSLT) \
+{ \
+ char *cptr, *cptr_top; \
+ int rtnlen; \
+ \
+ rtnlen = MIN((RTNNAME)->len, MAX_MIDENT_LEN); \
+ if (0 < rtnlen) \
+ { \
+ for (cptr = (RTNNAME)->addr, cptr_top = cptr + rtnlen - 1; cptr <= cptr_top; --cptr_top) \
+ { \
+ if ('#' == *cptr_top) \
+ break; \
+ } \
+ RSLT = !(cptr > cptr_top); \
+ } else \
+ RSLT = FALSE; \
}
#else
# define IS_TRIGGER_RTN(RTNNAME, RSLT) RSLT = FALSE
diff --git a/sr_port/stp_gcol_src.h b/sr_port/stp_gcol_src.h
index 3818ff5..45764c7 100644
--- a/sr_port/stp_gcol_src.h
+++ b/sr_port/stp_gcol_src.h
@@ -60,9 +60,6 @@
#ifdef GTM_CRYPT
# include "iormdef.h"
#endif
-#ifdef USHBIN_SUPPORTED
-# include "relinkctl.h"
-#endif
#ifndef STP_MOVE
GBLDEF int indr_stp_low_reclaim_passes = 0;
@@ -106,6 +103,7 @@ GBLREF hash_table_str *complits_hashtab;
GBLREF mval *alias_retarg;
GTMTRIG_ONLY(GBLREF mval dollar_ztwormhole;)
DEBUG_ONLY(GBLREF boolean_t ok_to_UNWIND_in_exit_handling;)
+UNIX_ONLY(GBLREF io_pair *io_std_device;)
OS_PAGE_SIZE_DECLARE
@@ -500,9 +498,6 @@ void stp_gcol(int space_asked) /* BYPASSOK */
glvn_pool_entry *slot, *top;
int i, n;
unsigned char *old_free;
-# ifdef USHBIN_SUPPORTED
- open_relinkctl_sgm *linkctl;
-# endif
# ifdef GTM_CRYPT
d_rm_struct *rm_ptr;
# endif
@@ -582,7 +577,7 @@ void stp_gcol(int space_asked) /* BYPASSOK */
if (((stringpool.base != rts_stringpool.base) || (0 == cache_table.size)))
{
# ifndef STP_MOVE
- if (0 != literal_chain.que.fl)
+ if (NULL != literal_chain.que.fl)
{ /* If hashtable exists, pull it all from there rather that searching for it twice */
if (complits_hashtab && complits_hashtab->base)
{
@@ -683,8 +678,16 @@ void stp_gcol(int space_asked) /* BYPASSOK */
if ((IO_ESC != l->dollar_io[0]) && (l->iod->trans_name == l))
{
MSTR_STPG_ADD(&l->iod->error_handler);
+# ifdef UNIX
+ /* if this is on UNIX and it is a split $principal, protect
+ * error_handler defined on the output side
+ */
+ if ((l->iod->pair.in != l->iod->pair.out)
+ && (l->iod->pair.out == io_std_device->out))
+ MSTR_STPG_ADD(&l->iod->pair.out->error_handler);
+# endif
# ifdef GTM_CRYPT
- rm_ptr = (d_rm_struct *)l->iod->dev_sp;
+ rm_ptr = (rm == l->iod->type) ? (d_rm_struct *)l->iod->dev_sp : NULL;
if (NULL != rm_ptr)
{ /* Protect the IVs and KEYs as needed. */
if (rm_ptr->input_encrypted)
@@ -830,7 +833,11 @@ void stp_gcol(int space_asked) /* BYPASSOK */
}
MVAL_STPG_ADD(m);
}
- for (sf = frame_pointer; sf < (stack_frame *)stackbase; sf = sf->old_frame_pointer)
+ /* If LINK:RECURSIVE is enabled and the first M frame on the stack is recursively replaced, when it unwinds,
+ * op_unwind() is going to unlink that version of the routine. We will eventually come here (as stp_move)
+ * with a zeroed frame pointer so the test below needs to deal with a NULL frame_pointer value.
+ */
+ for (sf = frame_pointer; (NULL != sf) && (sf < (stack_frame *)stackbase); sf = sf->old_frame_pointer)
{ /* Cover temp mvals in use */
if (NULL == sf->old_frame_pointer)
{ /* If trigger enabled, may need to jump over a base frame */
@@ -885,13 +892,6 @@ void stp_gcol(int space_asked) /* BYPASSOK */
tf = tf->old_tp_frame;
}
}
-# ifdef USHBIN_SUPPORTED
- /* Make sure we keep track of the relinkable directory names */
- for (linkctl = TREF(open_relinkctl_list); NULL != linkctl; linkctl = linkctl->next)
- {
- MSTR_STPG_ADD(&linkctl->zro_entry_name);
- }
-# endif
}
space_before_compact = stringpool.top - stringpool.free; /* Available space before compaction */
DEBUG_ONLY(blklen = stringpool.free - stringpool.base);
diff --git a/sr_port/svnames.h b/sr_port/svnames.h
index 0cf5e56..f8495c5 100644
--- a/sr_port/svnames.h
+++ b/sr_port/svnames.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -81,6 +81,7 @@ enum
SV_ZONLNRLBK, /* 67 */
SV_ZCLOSE, /* 68 */
SV_ZKEY, /* 69 */
+ SV_ZTDELIM, /* 70 */
SV_NUM_SV, /* count - should be next to last SV entry just prior to dummy entry below */
SV_DUMMY_TO_FORCE_INT = 0x0FFFFFFF /* to ensure an int on S390 */
};
diff --git a/sr_port/t_end.c b/sr_port/t_end.c
index 45d5a2d..5df1c0d 100644
--- a/sr_port/t_end.c
+++ b/sr_port/t_end.c
@@ -270,11 +270,13 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn)
* (b) DSE CRIT -SEIZE (and any command that follows it), DSE CHANGE -BLOCK, DSE ALL -SEIZE (and any command that follows)
* and DSE MAPS -RESTORE_ALL. Since we cannot distinguish between different DSE qualifiers, we use IS_DSE_IMAGE.
* (c) gvcst_redo_root_search in the final retry.
+ * (d) MUPIP TRIGGER -UPGRADE which is a TP transaction but it could do non-TP as part of gvcst_bmp_mark_free at the end.
*
* Since we don't expect hold_onto_crit to be set by any other utility/function, the below assert is valid and is intended
* to catch cases where the field is inadvertently set to TRUE.
*/
- assert(!csa->hold_onto_crit || IS_DSE_IMAGE UNIX_ONLY(|| jgbl.onlnrlbk || TREF(in_gvcst_redo_root_search)));
+ assert(!csa->hold_onto_crit || IS_DSE_IMAGE
+ UNIX_ONLY(|| jgbl.onlnrlbk || TREF(in_gvcst_redo_root_search) || TREF(in_trigger_upgrade)));
assert(cs_data == csd);
assert((t_tries < CDB_STAGNATE) || csa->now_crit);
assert(!dollar_tlevel);
diff --git a/sr_port/t_end_sysops.c b/sr_port/t_end_sysops.c
index fb44ef8..fdf3400 100644
--- a/sr_port/t_end_sysops.c
+++ b/sr_port/t_end_sysops.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2007, 2013 Fidelity Information Services, Inc *
+ * Copyright 2007, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -1204,9 +1204,10 @@ enum cdb_sc bg_update_phase2(cw_set_element *cs, trans_num ctn, trans_num effect
{ /* either it is a non-local bit-map or we are in dse_maps or MUPIP RECOVER writing an AIMG record */
assert((0 != (blkid & (BLKS_PER_LMAP - 1))) || write_after_image);
/* we should NOT be in crit for phase2 except dse_maps/dse_chng_bhead OR if cse has a non-zero recompute list. The
- * only exception to this is ONLINE ROLLBACK which holds crit for the entire duration
+ * only exception to this is ONLINE ROLLBACK or MUPIP TRIGGER -UPGRADE which holds crit for the entire duration
*/
- assert(!csa->now_crit || cs->recompute_list_head || dse_running UNIX_ONLY(|| jgbl.onlnrlbk));
+ assert(!csa->now_crit || cs->recompute_list_head || dse_running
+ UNIX_ONLY(|| jgbl.onlnrlbk || TREF(in_trigger_upgrade)));
if (FALSE == cs->done)
{ /* if the current block has not been built (from being referenced in TP) */
if (NULL != cs->new_buff)
diff --git a/sr_port/tab_gvstats_rec.h b/sr_port/tab_gvstats_rec.h
index 1c58456..274dd30 100644
--- a/sr_port/tab_gvstats_rec.h
+++ b/sr_port/tab_gvstats_rec.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2008, 2013 Fidelity Information Services, Inc *
+ * Copyright 2008, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -64,3 +64,13 @@ TAB_GVSTATS_REC(n_jrec_epoch_idle , "JRI", "# of Idle epoch Journal Records
TAB_GVSTATS_REC(n_jrec_other , "JRO", "# of Other Journal Records ")
TAB_GVSTATS_REC(n_jnl_extends , "JEX", "# of Journal file EXtensions ")
TAB_GVSTATS_REC(n_db_extends , "DEX", "# of Database file EXtensions ")
+#ifdef UNIX
+TAB_GVSTATS_REC(n_crit_success , "CAT", "# of crit acquired total successes ")
+TAB_GVSTATS_REC(n_crits_in_epch , "CFE", "# of attempts in CFT caused by epochs ")
+TAB_GVSTATS_REC(sq_crit_failed , "CFS", "sum squares grab crit failed ")
+TAB_GVSTATS_REC(n_crit_failed , "CFT", "# of grab crit failures ")
+TAB_GVSTATS_REC(sq_crit_que_slps , "CQS", "sum squares grab crit queued sleeps ")
+TAB_GVSTATS_REC(n_crit_que_slps , "CQT", "# of grab crit queued sleeps ")
+TAB_GVSTATS_REC(sq_crit_yields , "CYS", "sum squares grab crit yields ")
+TAB_GVSTATS_REC(n_crit_yields , "CYT", "# of grab crit yields ")
+#endif
diff --git a/sr_port/tp.h b/sr_port/tp.h
index 1875bf8..9b0f506 100644
--- a/sr_port/tp.h
+++ b/sr_port/tp.h
@@ -84,6 +84,9 @@ typedef struct global_tlvl_info_struct
# endif
struct ua_list *curr_ua; /* points to global variable curr_ua at start of this transaction */
char *upd_array_ptr; /* points to global variable update_array_ptr at start of this transaction */
+# ifdef GTM_TRIGGER
+ int ztrigbuffLen; /* copy of TREF(ztrigbuffLen) at start of this transaction */
+# endif
} global_tlvl_info;
/* A note on the buddy lists used in sgm_info structure,
@@ -709,7 +712,7 @@ typedef struct trans_restart_hist_struct
{ /* TROLLBACK(0) or TRESTART. Reset db_dztrigger_cycle to 0 since we are going to start \
* a new transaction. But, we want to ensure that the new transaction re-reads triggers \
* since any gvt which updated its gvt_trigger in this transaction will be stale as \
- * they never got committed. \
+ * they never got committed. We will later ensure csa->db_dztrigger_cycle is non-zero. \
*/ \
gvnh->db_dztrigger_cycle = 0; \
gvnh->db_trigger_cycle = 0; \
@@ -753,10 +756,13 @@ typedef struct trans_restart_hist_struct
} else if (!COMMIT) \
{ /* This is either a complete rollback or a restart. In either case, set csa->incr_db_trigger_cycle \
* to FALSE for all csa referenced in this transaction as they are anyways not going to be committed. \
+ * Based on this though, set csa->db_dztrigger_cycle to a non-zero value this way we ensure \
+ * triggers are forced to be re-read on the restart/rollback so any cached stale trigger state from \
+ * the current failed try is thrown away. \
*/ \
for (si = first_sgm_info; NULL != si; si = si->next_sgm_info) \
{ \
- si->tp_csa->db_dztrigger_cycle = 0; \
+ si->tp_csa->db_dztrigger_cycle = si->tp_csa->incr_db_trigger_cycle ? 1 : 0; \
si->tp_csa->incr_db_trigger_cycle = FALSE; \
} \
} \
@@ -794,17 +800,19 @@ typedef struct trans_restart_hist_struct
}
# ifdef DEBUG
# define TP_ASSERT_ZTRIGGER_CYCLE_RESET \
-{ /* At the end of a transaction (either because of trestart, complete trollback or tcommit) ensure that \
- * csa->db_dztrigger_cycle is reset to zero. It's okay not to check if all gvt updated in this transaction \
- * also has gvt->db_dztrigger_cycle set back to zero because if they don't there are other asserts that \
- * will trip in the subsequent transactions \
+{ /* At the end of a transaction commit ensure that csa->db_dztrigger_cycle is reset to zero. \
+ * In the case of trestart and/or rollback, this value could be 1 if $ztrigger activity happened in \
+ * the failed try. Because of this it is also possible the value could be 1 after a commit (that is preceded \
+ * by a restart). Assert this. \
+ * It's okay not to check if all gvt updated in this transaction also has gvt->db_dztrigger_cycle set \
+ * back to zero because if they don't there are other asserts that will trip in the subsequent transactions. \
*/ \
GBLREF sgm_info *first_sgm_info; \
\
sgm_info *si; \
\
for (si = first_sgm_info; NULL != si; si = si->next_sgm_info) \
- assert(0 == si->tp_csa->db_dztrigger_cycle); \
+ assert((0 == si->tp_csa->db_dztrigger_cycle) || (1 == si->tp_csa->db_dztrigger_cycle)); \
}
# else
# define TP_ASSERT_ZTRIGGER_CYCLE_RESET
diff --git a/sr_port/tp_clean_up.c b/sr_port/tp_clean_up.c
index 140aae5..bf3c459 100644
--- a/sr_port/tp_clean_up.c
+++ b/sr_port/tp_clean_up.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -35,6 +35,7 @@
#ifdef GTM_TRIGGER
#include <rtnhdr.h>
#include "gv_trigger.h" /* for TP_INVALIDATE_TRIGGER_CYCLES_IF_NEEDED macro */
+#include "util.h" /* for TP_ZTRIGBUFF_PRINT macro */
#endif
GBLREF sgmnt_data_ptr_t cs_data;
@@ -190,7 +191,8 @@ void tp_clean_up(boolean_t rollback_flag)
*/
}
GTMTRIG_ONLY(assert(!TREF(gvt_triggers_read_this_tn));)
- GTMTRIG_ONLY(TP_ASSERT_ZTRIGGER_CYCLE_RESET;) /* for all regions, we better have csa->db_dztrigger_cycle = 0*/
+ /* Assert that for all regions, we have csa->db_dztrigger_cycle = 0 or 1 (based on commit/restart/rollback) */
+ GTMTRIG_ONLY(TP_ASSERT_ZTRIGGER_CYCLE_RESET;)
for (si = first_sgm_info; si != NULL; si = next_si)
{
TP_TEND_CHANGE_REG(si);
@@ -432,9 +434,10 @@ void tp_clean_up(boolean_t rollback_flag)
sgm_info_ptr = NULL;
first_sgm_info = NULL;
/* ensure that we don't have crit on any region at the end of a TP transaction (be it GT.M or MUPIP). The only exception
- * is ONLINE ROLLBACK which holds crit for the entire duration
+ * is ONLINE ROLLBACK or MUPIP TRIGGER -UPGRADE which holds crit for the entire duration
*/
- assert((CDB_STAGNATE == t_tries) || (0 == have_crit(CRIT_HAVE_ANY_REG)) UNIX_ONLY(|| jgbl.onlnrlbk));
+ assert((CDB_STAGNATE == t_tries) || (0 == have_crit(CRIT_HAVE_ANY_REG))
+ UNIX_ONLY(|| jgbl.onlnrlbk || TREF(in_trigger_upgrade)));
/* Now that this transaction try is done (need to start a fresh try in case of a restart; in case of commit the entire
* transaction is done) ensure first_tp_si_by_ftok is NULL at end of tp_clean_up as this field is relied upon by
* secshr_db_clnup and t_commit_cleanup to determine if we have an ongoing transaction. In case of a successfully
@@ -445,4 +448,11 @@ void tp_clean_up(boolean_t rollback_flag)
assert(rollback_flag || (NULL == first_tp_si_by_ftok));
first_tp_si_by_ftok = NULL;
ENABLE_INTERRUPTS(INTRPT_IN_TP_CLEAN_UP); /* check if any MUPIP STOP/signals were deferred while in this function */
+# ifdef GTM_TRIGGER
+ if (!rollback_flag)
+ {
+ TP_ZTRIGBUFF_PRINT; /* TP is committed so print $ZTRIGGER/MUPIP-TRIGGER activity output in this tn */
+ } else
+ TREF(ztrigbuffLen) = 0;
+# endif
}
diff --git a/sr_port/tp_incr_clean_up.c b/sr_port/tp_incr_clean_up.c
index febf9d5..4d03ab0 100644
--- a/sr_port/tp_incr_clean_up.c
+++ b/sr_port/tp_incr_clean_up.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -260,9 +260,10 @@ void rollbk_gbl_tlvl_info(uint4 newlevel)
sgmnt_addrs *old_csa, *tmp_next_csa;
ua_list *ua_ptr;
DEBUG_ONLY(uint4 dbg_upd_array_size;)
+ DCL_THREADGBL_ACCESS;
+ SETUP_THREADGBL_ACCESS;
old_csa = jnl_fence_ctl.fence_list;
-
for (prev_gtli = NULL, gtli = global_tlvl_info_head; gtli; gtli = gtli->next_global_tlvl_info)
{
if (newlevel < gtli->t_level)
@@ -284,6 +285,7 @@ void rollbk_gbl_tlvl_info(uint4 newlevel)
assert(NULL != gtli->curr_ua);
curr_ua = (ua_list *)(gtli->curr_ua);
update_array_ptr = gtli->upd_array_ptr;
+ GTMTRIG_ONLY(TREF(ztrigbuffLen) = gtli->ztrigbuffLen;)
} else
{
jnl_fence_ctl.fence_list = JNL_FENCE_LIST_END;
diff --git a/sr_port/tp_tend.c b/sr_port/tp_tend.c
index 67c9958..95ba835 100644
--- a/sr_port/tp_tend.c
+++ b/sr_port/tp_tend.c
@@ -109,6 +109,7 @@ GBLREF jnl_fence_control jnl_fence_ctl;
GBLREF jnlpool_addrs jnlpool;
GBLREF jnlpool_ctl_ptr_t jnlpool_ctl, temp_jnlpool_ctl;
GBLREF boolean_t is_updproc;
+GBLREF boolean_t is_replicator;
GBLREF seq_num seq_num_zero;
GBLREF seq_num seq_num_one;
GBLREF int gv_fillfactor;
@@ -152,7 +153,7 @@ error_def(ERR_TEXT);
GBLREF boolean_t is_updproc; \
UNIX_ONLY(GBLREF recvpool_addrs recvpool;) \
\
- if (REPL_ALLOWED(CSA)) \
+ if (REPL_ALLOWED(CSA) && is_replicator) \
{ \
assert(CSA->hdr->reg_seqno < TJPL->jnl_seqno); \
CSA->hdr->reg_seqno = TJPL->jnl_seqno; \
@@ -320,10 +321,11 @@ boolean_t tp_tend()
csd = cs_data;
cnl = csa->nl;
is_mm = (dba_mm == csd->acc_meth);
- UNIX_ONLY(
- assert(!csa->hold_onto_crit || jgbl.onlnrlbk); /* In TP, hold_onto_crit is set ONLY by online rollback */
- assert(!jgbl.onlnrlbk || (csa->hold_onto_crit && csa->now_crit));
- )
+# ifdef UNIX
+ assert(!csa->hold_onto_crit || jgbl.onlnrlbk || TREF(in_trigger_upgrade));
+ assert(!jgbl.onlnrlbk || (csa->hold_onto_crit && csa->now_crit));
+ assert(!TREF(in_trigger_upgrade) || (csa->hold_onto_crit && csa->now_crit));
+# endif
si = (sgm_info *)(csa->sgm_info_ptr);
sgm_info_ptr = si;
*prev_tp_si_by_ftok = si;
@@ -424,7 +426,8 @@ boolean_t tp_tend()
{
assert(JNL_ENABLED(csa) || REPL_WAS_ENABLED(csa));
replication = TRUE;
- repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;
+ if (is_replicator)
+ repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;
jnl_participants++;
} else if (JNL_ENABLED(csa))
{
@@ -451,9 +454,17 @@ boolean_t tp_tend()
SET_GBL_JREC_TIME; /* initializes jgbl.gbl_jrec_time */
assert(jgbl.gbl_jrec_time);
/* If any one DB that we are updating has replication turned on and another has only journaling, issue error */
- if (replication && yes_jnl_no_repl)
- rts_error_csa(CSA_ARG(REG2CSA(save_gv_cur_region)) VARLSTCNT(4) ERR_REPLOFFJNLON, 2,
- DB_LEN_STR(save_gv_cur_region));
+ if (replication)
+ {
+ if (yes_jnl_no_repl)
+ rts_error_csa(CSA_ARG(REG2CSA(save_gv_cur_region)) VARLSTCNT(4) ERR_REPLOFFJNLON, 2,
+ DB_LEN_STR(save_gv_cur_region));
+ /* If caller does NOT want this update to be replicated, turn "replication" local variable off.
+ * The only such caller known at this time is "trigger_upgrade" - 2014/05/02.
+ */
+ if (!is_replicator)
+ replication = FALSE;
+ }
}
if (!do_validation)
{
@@ -1778,8 +1789,8 @@ boolean_t tp_tend()
rel_lock(jnlpool.jnlpool_dummy_reg);
}
/* Check that we DONT own crit on ANY region. The only exception is online mupip journal rollback/recovery
- * which holds crit for the entire process lifetime. */
- assert(UNIX_ONLY(jgbl.onlnrlbk || ) (0 == have_crit(CRIT_HAVE_ANY_REG)));
+ * or MUPIP TRIGGER -UPGRADE which holds crit for the entire process lifetime. */
+ assert(UNIX_ONLY(jgbl.onlnrlbk || TREF(in_trigger_upgrade) || ) (0 == have_crit(CRIT_HAVE_ANY_REG)));
/* the following section is the actual commitment of the changes in the database (phase2 for BG) */
for (si = first_tp_si_by_ftok; (NULL != si); si = si->next_tp_si_by_ftok)
{
diff --git a/sr_port/unw_mv_ent.c b/sr_port/unw_mv_ent.c
index 8430a07..86f898f 100644
--- a/sr_port/unw_mv_ent.c
+++ b/sr_port/unw_mv_ent.c
@@ -75,6 +75,7 @@ GBLREF lv_xnew_var *xnewvar_anchor;
#ifdef GTM_TRIGGER
GBLREF mstr *dollar_ztname;
GBLREF mval *dollar_ztdata;
+GBLREF mval *dollar_ztdelim;
GBLREF mval *dollar_ztoldval;
GBLREF mval *dollar_ztriggerop;
GBLREF mval *dollar_ztupdate;
@@ -443,6 +444,7 @@ void unw_mv_ent(mv_stent *mv_st_ent)
dollar_ztvalue = mv_st_ent->mv_st_cont.mvs_trigr.ztvalue_save;
dollar_ztname = mv_st_ent->mv_st_cont.mvs_trigr.ztname_save;
dollar_ztdata = mv_st_ent->mv_st_cont.mvs_trigr.ztdata_save;
+ dollar_ztdelim = mv_st_ent->mv_st_cont.mvs_trigr.ztdelim_save;
dollar_ztoldval = mv_st_ent->mv_st_cont.mvs_trigr.ztoldval_save;
dollar_ztriggerop = mv_st_ent->mv_st_cont.mvs_trigr.ztriggerop_save;
dollar_ztupdate = mv_st_ent->mv_st_cont.mvs_trigr.ztupdate_save;
@@ -465,13 +467,15 @@ void unw_mv_ent(mv_stent *mv_st_ent)
ctxt = mv_st_ent->mv_st_cont.mvs_trigr.ctxt_save;
/* same assert as in gtm_trigger.c */
assert(((0 == gtm_trigger_depth)
- && (((ch_at_trigger_init == ctxt->ch)
- || ((ch_at_trigger_init == (ctxt - 1)->ch)
- && ((&gvcst_put_ch == ctxt->ch) || (&gvcst_kill_ch == ctxt->ch))))))
- || ((0 < gtm_trigger_depth)
- && (((&mdb_condition_handler == ctxt->ch)
- || ((&mdb_condition_handler == (ctxt - 1)->ch)
- && ((&gvcst_put_ch == ctxt->ch) || (&gvcst_kill_ch == ctxt->ch)))))));
+ && (((ch_at_trigger_init == ctxt->ch)
+ || ((ch_at_trigger_init == (ctxt - 1)->ch)
+ && ((&gvcst_put_ch == ctxt->ch) || (&gvcst_kill_ch == ctxt->ch)
+ || (&gvcst_spr_kill_ch == ctxt->ch))))))
+ || ((0 < gtm_trigger_depth)
+ && (((&mdb_condition_handler == ctxt->ch)
+ || ((&mdb_condition_handler == (ctxt - 1)->ch)
+ && ((&gvcst_put_ch == ctxt->ch) || (&gvcst_kill_ch == ctxt->ch)
+ || (&gvcst_spr_kill_ch == ctxt->ch)))))));
active_ch = ctxt;
ctxt->ch_active = FALSE;
if (tp_timeout_deferred && !((0 < dollar_ecode.index) && (ETRAP_IN_EFFECT))
diff --git a/sr_port/unw_retarg.c b/sr_port/unw_retarg.c
index 04d8559..86afd61 100644
--- a/sr_port/unw_retarg.c
+++ b/sr_port/unw_retarg.c
@@ -35,17 +35,24 @@
#include "get_ret_targ.h"
#include "opcode.h"
#include "glvn_pool.h"
+#include "zr_unlink_rtn.h"
+#include "tp_timeout.h"
-GBLREF void (*unw_prof_frame_ptr)(void);
-GBLREF stack_frame *frame_pointer, *zyerr_frame;
-GBLREF unsigned char *msp,*stackbase,*stacktop;
-GBLREF mv_stent *mv_chain;
-GBLREF tp_frame *tp_pointer;
-GBLREF boolean_t is_tracing_on;
-GBLREF symval *curr_symval;
-GBLREF mval *alias_retarg;
-GBLREF boolean_t dollar_truth;
-GBLREF boolean_t dollar_zquit_anyway;
+GBLREF void (*unw_prof_frame_ptr)(void);
+GBLREF stack_frame *frame_pointer, *zyerr_frame;
+GBLREF unsigned char *msp, *stackbase, *stacktop;
+GBLREF mv_stent *mv_chain;
+GBLREF tp_frame *tp_pointer;
+GBLREF boolean_t is_tracing_on;
+GBLREF symval *curr_symval;
+GBLREF mval *alias_retarg;
+GBLREF boolean_t dollar_truth;
+GBLREF boolean_t dollar_zquit_anyway;
+GBLREF boolean_t dollar_zininterrupt;
+GBLREF mval dollar_ztrap;
+GBLREF boolean_t ztrap_explicit_null;
+GBLREF boolean_t tp_timeout_deferred;
+GBLREF dollar_ecode_type dollar_ecode;
LITREF mval literal_null;
@@ -57,9 +64,10 @@ error_def(ERR_TPQUIT);
/* This has to be maintained in parallel with op_unwind(), the unwind without a return argument (intrinsic quit) routine. */
int unw_retarg(mval *src, boolean_t alias_return)
{
+ rhdtyp *rtnhdr;
mval ret_value, *trg;
boolean_t got_ret_target;
- stack_frame *prevfp;
+ stack_frame *prevfp, *fp;
lv_val *srclv, *srclvc, *base_lv;
symval *symlv, *symlvc;
int4 srcsymvlvl;
@@ -165,6 +173,7 @@ int unw_retarg(mval *src, boolean_t alias_return)
msp = (unsigned char *)frame_pointer + SIZEOF(stack_frame);
DRAIN_GLVN_POOL_IF_NEEDED;
PARM_ACT_UNSTACK_IF_NEEDED;
+ USHBIN_ONLY(rtnhdr = frame_pointer->rvector); /* Save rtnhdr for cleanup call below */
frame_pointer = frame_pointer->old_frame_pointer;
DBGEHND((stderr, "unw_retarg: Stack frame 0x"lvaddr" unwound - frame 0x"lvaddr" now current - New msp: 0x"lvaddr"\n",
prevfp, frame_pointer, msp));
@@ -177,5 +186,12 @@ int unw_retarg(mval *src, boolean_t alias_return)
if (!dollar_zquit_anyway || trg)
trg->mvtype |= MV_RETARG;
assert((frame_pointer < frame_pointer->old_frame_pointer) || (NULL == frame_pointer->old_frame_pointer));
+ USHBIN_ONLY(CLEANUP_COPIED_RECURSIVE_RTN(rtnhdr));
+ /* We just unwound a frame. May have been either a zintrupt frame and/or may have unwound a NEW'd ZTRAP or even cleared
+ * our error state. If we have a deferred timeout and none of the deferral conditions are anymore in effect, release
+ * the hounds.
+ */
+ if (tp_timeout_deferred UNIX_ONLY(&& !dollar_zininterrupt) && ((0 == dollar_ecode.index) || !(ETRAP_IN_EFFECT)))
+ tptimeout_set(0);
return 0;
}
diff --git a/sr_port/updhelper_reader.c b/sr_port/updhelper_reader.c
index cb43a0d..8fd7017 100644
--- a/sr_port/updhelper_reader.c
+++ b/sr_port/updhelper_reader.c
@@ -109,7 +109,6 @@ GBLREF sgmnt_data_ptr_t cs_data;
GBLREF uint4 image_count;
#endif
GBLREF boolean_t disk_blk_read;
-LITREF mval literal_hasht;
static uint4 last_pre_read_offset;
error_def(ERR_DBCCERR);
diff --git a/sr_port/updproc.c b/sr_port/updproc.c
index adfa376..ce5a1da 100644
--- a/sr_port/updproc.c
+++ b/sr_port/updproc.c
@@ -62,6 +62,7 @@
#ifdef GTM_TRIGGER
#include <rtnhdr.h> /* for rtn_tabent in gv_trigger.h */
#include "gv_trigger.h"
+# include "gtm_trigger.h"
#include "targ_alloc.h"
#include "trigger.h"
#include "hashtab_str.h"
@@ -150,16 +151,16 @@ GBLREF int tprestart_state; /* When triggers restart, multiple states p
GBLREF dollar_ecode_type dollar_ecode; /* structure containing $ECODE related information */
GBLREF mval dollar_ztwormhole;
GBLREF boolean_t dollar_ztrigger_invoked;
+GBLREF stack_frame *frame_pointer; /* needed by TRIGGER_BASE_FRAME_UNWIND_IF_NOMANSLAND macro */
#endif
GBLREF boolean_t skip_dbtriggers;
GBLREF gv_namehead *gv_target;
GBLREF boolean_t gv_play_duplicate_kills;
#ifdef UNIX
-GBLREF int4 strm_index;
-STATICDEF boolean_t set_onln_rlbk_flg;
+GBLREF int4 strm_index;
+STATICDEF boolean_t set_onln_rlbk_flg;
#endif
-LITREF mval literal_hasht;
static boolean_t updproc_continue = TRUE;
error_def(ERR_GBLOFLOW);
@@ -265,9 +266,12 @@ error_def(ERR_UPDREPLSTATEOFF);
CONDITION_HANDLER(updproc_ch)
{
- int rc;
- unsigned char seq_num_str[32], *seq_num_ptr;
- unsigned char seq_num_strx[32], *seq_num_ptrx;
+ int rc;
+ unsigned char seq_num_str[32], *seq_num_ptr;
+ unsigned char seq_num_strx[32], *seq_num_ptrx;
+# ifdef GTM_TRIGGER
+ condition_handler *save_active_ch;
+# endif
START_CH(TRUE);
if ((int)ERR_TPRETRY == SIGNAL)
@@ -287,6 +291,24 @@ CONDITION_HANDLER(updproc_ch)
if (first_sgm_info GTMTRIG_ONLY( || (TPRESTART_STATE_NORMAL != tprestart_state)))
{
VMS_ONLY(assert(FALSE == tp_restart_fail_sig_used);)
+# ifdef GTM_TRIGGER
+ /* Note: Below GTM_TRIGGER-only code is similar to mdb_condition_handler. But unlike there,
+ * where MUM_TSTART is done inside the condition handler to transfer control, we do an UNWIND
+ * here in updproc_ch. The UNWIND macro does an active_ch++ (to balance out the active_ch-- done
+ * by START_CH done at the entry of every condition handler). We want to preserve active_ch in
+ * the state that UNWIND expects. But the macro call done below calls gtm_trigger_fini which in
+ * turn calls unw_mv_ent which could modify active_ch as part of popping MVST_TRIGR. Work around
+ * that by saving and restoring active_ch after the macro call so UNWIND is fine. But what this
+ * means is that for a short code window (from when unw_mv_ent sets active_ch to when we reset it
+ * after the macro call below), active_ch would be incorrectly set to updproc_ch (instead of
+ * util_base_ch which START_CH would have set it to above). But that is okay since we dont expect
+ * any TPRETRY errors in this short window and updproc_ch would anyways transfer control to
+ * util_base_ch (through NEXTCH) for all non-TPRETRY errors.
+ */
+ save_active_ch = active_ch;
+ TRIGGER_BASE_FRAME_UNWIND_IF_NOMANSLAND;
+ active_ch = save_active_ch;
+# endif
rc = tp_restart(1, TP_RESTART_HANDLES_ERRORS); /* any nested errors will set SIGNAL accordingly */
assert(0 == rc); /* No partials restarts can happen at this final level */
GTMTRIG_ONLY(assert(TPRESTART_STATE_NORMAL == tprestart_state));
@@ -1382,7 +1404,7 @@ void updproc_actions(gld_dbname_list *gld_db_files)
assert(NULL != tmpcsa);
rts_error_csa(CSA_ARG(tmpcsa) VARLSTCNT(10) ERR_REC2BIG, 4,
VMS_ONLY(gv_currkey->end + 1 + SIZEOF(rec_hdr) +) val_mv.str.len,
- (int4)gv_cur_region->max_rec_size, REG_LEN_STR(gv_cur_region),
+ (int4)(tmpcsa->region)->max_rec_size, REG_LEN_STR(tmpcsa->region),
ERR_GVIS, 2, end - buff, buff);
break;
}
diff --git a/sr_port/updproc.h b/sr_port/updproc.h
index 5fd830b..9dc2fe8 100644
--- a/sr_port/updproc.h
+++ b/sr_port/updproc.h
@@ -37,49 +37,10 @@ enum upd_bad_trans_type
#define UPD_GV_BIND_NAME(GD_HEADER, GVNAME, GVNH_REG) GV_BIND_NAME_AND_ROOT_SEARCH(GD_HEADER, &GVNAME, GVNH_REG)
#ifdef GTM_TRIGGER
-#define UPD_GV_BIND_NAME_APPROPRIATE(GD_HEADER, GVNAME, KEY, KEYLEN, GVNH_REG) \
-{ \
- char *tr_ptr; \
- mname_entry gvname1; \
- int tr_len; \
- sgmnt_addrs *csa; \
- \
- GBLREF boolean_t dollar_ztrigger_invoked; \
- \
- if (IS_MNAME_HASHT_GBLNAME(GVNAME.var_name)) \
- { /* gbl is ^#t. In this case, do special processing. Look at the first subscript and \
- * bind to the region mapped to by that global name (not ^#t). Also since V62 will \
- * never receive ^#t records from V62 source (it will receive TLGTRIG/ULGTRIG logical \
- * journal records only) assert accordingly. \
- */ \
- assert(V24_JNL_VER > gtmrecv_local->remote_side.jnl_ver); \
- tr_ptr = KEY; /* Skip to the first subscript */ \
- tr_len = STRLEN(KEY); /* Only want length to first 0, not entire length */ \
- assert(tr_len < KEYLEN); /* If ^#t, there has to be a subscript */ \
- tr_ptr += tr_len; \
- assert((KEY_DELIMITER == *tr_ptr) && ((char)STR_SUB_PREFIX == *(tr_ptr + 1))); \
- tr_ptr += 2; /* Skip the 0x00 and 0xFF */ \
- assert((HASHT_GBL_CHAR1 == *tr_ptr) || ('%' == *tr_ptr) || (ISALPHA_ASCII(*tr_ptr))); \
- if (HASHT_GBL_CHAR1 != *tr_ptr) \
- { \
- gvname1.var_name.addr = tr_ptr; \
- gvname1.var_name.len = STRLEN(tr_ptr); \
- COMPUTE_HASH_MNAME(&gvname1); \
- GV_BIND_NAME_ONLY(GD_HEADER, &gvname1, GVNH_REG); \
- csa = cs_addrs; \
- SET_GVTARGET_TO_HASHT_GBL(csa); \
- dollar_ztrigger_invoked = TRUE; \
- csa->incr_db_trigger_cycle = TRUE; \
- csa->db_dztrigger_cycle++; \
- } else \
- { \
- SWITCH_TO_DEFAULT_REGION; \
- /* Special case for ^#t. Set GVNH_REG to NULL. Caller needs to check this */ \
- GVNH_REG = NULL; \
- } \
- INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED; \
- } else \
- UPD_GV_BIND_NAME(GD_HEADER, GVNAME, GVNH_REG); \
+#define UPD_GV_BIND_NAME_APPROPRIATE(GD_HEADER, GVNAME, KEY, KEYLEN, GVNH_REG) \
+{ \
+ assert(!IS_MNAME_HASHT_GBLNAME(GVNAME.var_name)); \
+ UPD_GV_BIND_NAME(GD_HEADER, GVNAME, GVNH_REG); \
}
#else
#define UPD_GV_BIND_NAME_APPROPRIATE(GD_HEADER, GVNAME, KEY, KEYLEN, GVNH_REG) UPD_GV_BIND_NAME(GD_HEADER, GVNAME, GVNH_REG)
diff --git a/sr_port/updproc_get_gblname.c b/sr_port/updproc_get_gblname.c
index b75cab0..b0a4a5b 100644
--- a/sr_port/updproc_get_gblname.c
+++ b/sr_port/updproc_get_gblname.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2005, 2013 Fidelity Information Services, Inc *
+ * Copyright 2005, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -32,14 +32,16 @@
#include "updproc_get_gblname.h"
#include "min_max.h"
#include "hashtab_mname.h"
+#include "toktyp.h" /* Needed for "valid_mname.h" */
+#include "valid_mname.h"
/* This routine validates the key from journal record copying to memory pointed updproc_get_gblname
* "gvname" is an mname_entry pointing to the global name (to be used for gv_bind_name) is set here.
*/
enum upd_bad_trans_type updproc_get_gblname(char *src_ptr, int key_len, char *gv_mname, mname_entry *gvname)
{
- char *dest_ptr;
- int cplen;
+ char *dest_ptr;
+ int cplen;
cplen = MIN(MAX_MIDENT_LEN + 1, key_len); /* +1 to consider null */
dest_ptr = (char *)gv_mname;
@@ -53,6 +55,11 @@ enum upd_bad_trans_type updproc_get_gblname(char *src_ptr, int key_len, char *gv
return upd_bad_mname_size;
gvname->var_name.addr = (char *)gv_mname;
gvname->var_name.len = INTCAST(dest_ptr - 1 - (char *)gv_mname);
+ /* We have already checked for global name length. Now check for global name contents */
+ if (!valid_mname(&gvname->var_name))
+ return upd_bad_mname_size; /* caller currently only cares good or bad so overload existing error
+ * even if not entirely accurate.
+ */
COMPUTE_HASH_MNAME(gvname);
return upd_good_record;
}
diff --git a/sr_port/util.h b/sr_port/util.h
index fa8ce82..226567d 100644
--- a/sr_port/util.h
+++ b/sr_port/util.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -48,9 +48,10 @@ void util_log_open(char *filename, uint4 len);
void util_out_write(unsigned char *addr, unsigned int len);
#else /* UNIX */
#include "gtm_stdio.h" /* for FILE * */
-void util_in_open(void *);
-char *util_input(char *buffer, int buffersize, FILE *fp, boolean_t remove_leading_spaces);
-void util_out_print_gtmio(caddr_t message, int flush, ...);
+void util_in_open(void *);
+char *util_input(char *buffer, int buffersize, FILE *fp, boolean_t remove_leading_spaces);
+void util_out_print_gtmio(caddr_t message, int flush, ...);
+boolean_t util_out_save(char *dst, int *dstlen_ptr);
#ifdef DEBUG
void util_out_syslog_dump(void);
@@ -75,7 +76,7 @@ void util_out_syslog_dump(void);
(TREF(util_outbuff_ptr)) += OUT_BUFF_SIZE; \
VAR_COPY(VA_LIST_SAVE_PTR, TREF(last_va_list_ptr)); \
UTIL_OUT_SAVE_PTR = TREF(util_outptr); \
- TREF(util_outptr) = NULL; \
+ TREF(util_outptr) = TREF(util_outbuff_ptr); \
COPY_SAVED = TRUE; \
} else \
assert(FALSE); \
@@ -106,6 +107,20 @@ void util_out_syslog_dump(void);
#define HEX8 8
#define HEX16 16
+#define TP_ZTRIGBUFF_PRINT \
+{ \
+ DCL_THREADGBL_ACCESS; \
+ \
+ SETUP_THREADGBL_ACCESS; \
+ if (TREF(ztrigbuffLen)) \
+ { \
+ tp_ztrigbuff_print(); \
+ TREF(ztrigbuffLen) = 0; \
+ } \
+}
+
+void tp_ztrigbuff_print(void);
+
void util_exit_handler(void);
void util_out_close(void);
void util_out_send_oper(char *addr, unsigned int len);
diff --git a/sr_port/verify_queue.c b/sr_port/verify_queue.c
index fb29602..0a0ad96 100644
--- a/sr_port/verify_queue.c
+++ b/sr_port/verify_queue.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2005 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -10,19 +10,12 @@
****************************************************************/
/* Routines to verify a simple double-linked queue.
-
- If we fail any of these tests, we will gtmassert in case a call to
- this routine is made from "pro" code. No messages are produced by
- this code since they would be useful only in the context of the
- dumped data and would scare the hell out of the user anyway.
-
- Two versions of this test are supplied. The first will lock the queue
- header first. The second assumes the queue is already locked.
-
- Most(All?) calls to this routine are compiled in by specifying the compile
- flag DEBUG_QUEUE.
-
-*/
+ *
+ * If we fail any of these tests in pro code, we gtmassert.
+ * This code produces no messages because they would be useful only in the context of the dumped data and would scare the user.
+ * We have two versions of this test. The first locks the queue header. The second assumes the queue is already locked.
+ * Most calls to this routine are compiled in by specifying the compile flag DEBUG_QUEUE.
+ */
#include "mdef.h"
@@ -54,16 +47,14 @@ GBLREF volatile int4 fast_lock_count;
GBLREF pid_t process_id;
VMS_ONLY(GBLREF uint4 image_count;) /* Needed for GET/RELEASE_SWAPLOCK */
-void verify_queue_lock(que_head_ptr_t qhdr)
+gtm_uint64_t verify_queue_lock(que_head_ptr_t qhdr)
{
que_ent_ptr_t qe, last_qe;
- int i, k;
- boolean_t got_lock;
+ gtm_uint64_t i, k;
+ boolean_t got_lock;
++fast_lock_count;
-
- /* Before we can play with the queue, we have to lock it
- to prevent it from being changed out from underneath us */
+ /* Before running this queue, must lock it to prevent it from being changed during our run */
for (got_lock = FALSE, k = 0; k < QI_STARVATION; ++k)
{
for (i = 0; got_lock == FALSE && i < QI_RETRY; ++i)
@@ -73,48 +64,27 @@ void verify_queue_lock(que_head_ptr_t qhdr)
if (0 != k)
wcs_backoff(k);
}
-
- if (!got_lock) /* We gotta have our lock */
- GTMASSERT;
-
- /* Now run through queue. Verify the fwd and backward chain ptrs */
- last_qe = (que_ent_ptr_t)qhdr;
- for (qe = (que_ent_ptr_t)((sm_uc_ptr_t)qhdr + qhdr->fl);
- qe != (que_ent_ptr_t)qhdr;
- qe = (que_ent_ptr_t)((sm_uc_ptr_t)qe + qe->fl))
- {
-
- if ((que_ent_ptr_t)((sm_uc_ptr_t)qe + qe->bl) != last_qe) /* Back pointer works good? */
- {
-/* ASWP(&qhdr->latch, LOCK_AVAILABLE, latch); */
- GTMASSERT;
- }
- last_qe = qe;
- }
-
+ assertpro(got_lock); /* We gotta have our lock */
+ i = verify_queue(qhdr);
/* Release locks */
RELEASE_SWAPLOCK(&qhdr->latch);
--fast_lock_count;
-
- return;
+ return i;
}
-
-void verify_queue(que_head_ptr_t qhdr)
+gtm_uint64_t verify_queue(que_head_ptr_t qhdr)
{
+ gtm_uint64_t i;
que_ent_ptr_t qe, last_qe;
- /* Now run through queue. Verify the fwd and backward chain ptrs */
+ /* run through queue. Verify the fwd and backward chain ptrs */
last_qe = (que_ent_ptr_t)qhdr;
- for (qe = (que_ent_ptr_t)((sm_uc_ptr_t)qhdr + qhdr->fl);
+ for (i = 0, qe = (que_ent_ptr_t)((sm_uc_ptr_t)qhdr + qhdr->fl);
qe != (que_ent_ptr_t)qhdr;
- qe = (que_ent_ptr_t)((sm_uc_ptr_t)qe + qe->fl))
+ qe = (que_ent_ptr_t)((sm_uc_ptr_t)qe + qe->fl), i++)
{
-
- if ((que_ent_ptr_t)((sm_uc_ptr_t)qe + qe->bl) != last_qe) /* Back pointer works good? */
- GTMASSERT;
+ assertpro((que_ent_ptr_t)((sm_uc_ptr_t)qe + qe->bl) == last_qe); /* Back pointer works good? */
last_qe = qe;
}
-
- return;
+ return i;
}
diff --git a/sr_port/view_arg_convert.c b/sr_port/view_arg_convert.c
index 52d1542..765e28a 100644
--- a/sr_port/view_arg_convert.c
+++ b/sr_port/view_arg_convert.c
@@ -48,19 +48,18 @@ error_def(ERR_VIEWLVN);
void view_arg_convert(viewtab_entry *vtp, int vtp_parm, mval *parm, viewparm *parmblk, boolean_t is_dollar_view)
{
static int4 first_time = TRUE;
- int n, reg_index;
- ht_ent_mname *tabent;
- mstr tmpstr, namestr;
- gd_region *r_top, *r_ptr, *gd_reg_start;
- mname_entry gvent, lvent;
- mident_fixed lcl_buff;
- unsigned char global_names[1024], stashed;
- unsigned char *src, *nextsrc, *src_top, *dst, *dst_top, y;
- unsigned char *c, *c_top;
+ char *cptr;
gd_binding *gd_map;
- gv_namehead *tmp_gvt;
+ gd_region *gd_reg_start, *r_ptr, *r_top;
gvnh_reg_t *gvnh_reg;
gvnh_spanreg_t *gvspan;
+ gv_namehead *tmp_gvt;
+ ht_ent_mname *tabent;
+ int n, reg_index;
+ mident_fixed lcl_buff;
+ mname_entry gvent, lvent;
+ mstr namestr, tmpstr;
+ unsigned char *c, *c_top, *dst, *dst_top, global_names[1024], *nextsrc, *src, *src_top, stashed, y;
switch (vtp_parm)
{
@@ -83,9 +82,9 @@ void view_arg_convert(viewtab_entry *vtp, int vtp_parm, mval *parm, viewparm *pa
parmblk->value = parm;
break;
case (VTP_NULL | VTP_DBREGION):
- if (NULL == parm)
+ if ((NULL == parm) || ((1 == parm->str.len) && ('*' == *parm->str.addr)))
{
- parmblk->gv_ptr = 0;
+ parmblk->gv_ptr = NULL;
break;
}
/* caution: fall through */
@@ -100,18 +99,23 @@ void view_arg_convert(viewtab_entry *vtp, int vtp_parm, mval *parm, viewparm *pa
parmblk->gv_ptr = r_ptr;
else
{
+ for (cptr = parm->str.addr, n = 0; n < parm->str.len; cptr++, n++)
+ lcl_buff.c[n] = TOUPPER(*cptr); /* Region names are upper-case ASCII */
+ cptr = parm->str.addr; /* remember the original name */
+ parm->str.addr = (char *)&lcl_buff.c; /* use the upper case name formed above */
for (r_top = r_ptr + gd_header->n_regions; ; r_ptr++)
{
if (r_ptr >= r_top)
rts_error_csa(CSA_ARG(NULL)
VARLSTCNT(4) ERR_NOREGION,2, parm->str.len, parm->str.addr);
tmpstr.len = r_ptr->rname_len;
- tmpstr.addr = (char *) r_ptr->rname;
+ tmpstr.addr = (char *)r_ptr->rname;
MSTR_CMP(tmpstr, parm->str, n);
if (0 == n)
break;
}
parmblk->gv_ptr = r_ptr;
+ parm->str.addr = cptr; /* be nice and restore the original name */
}
break;
case VTP_DBKEY:
diff --git a/sr_port/viewtab.h b/sr_port/viewtab.h
index f80f090..badcbed 100644
--- a/sr_port/viewtab.h
+++ b/sr_port/viewtab.h
@@ -38,6 +38,7 @@ VIEWTAB("GVFILE", VTP_DBREGION, VTK_GVFILE, MV_STR),
VIEWTAB("GVFIRST", VTP_NULL, VTK_GVFIRST, MV_STR), /* nodoc : archaic and deprecated.
* use GVNEXT instead */
VIEWTAB("GVNEXT", VTP_DBREGION, VTK_GVNEXT, MV_STR),
+VIEWTAB("GVSRESET", VTP_DBREGION | VTP_NULL, VTK_GVSRESET, MV_STR),
VIEWTAB("GVSTATS", VTP_DBREGION, VTK_GVSTATS, MV_STR),
VIEWTAB("ICHITS", VTP_NULL, VTK_ICHITS, MV_NM),
VIEWTAB("ICMISS", VTP_NULL, VTK_ICMISS, MV_NM),
@@ -82,15 +83,11 @@ VIEWTAB("NOLVNULLSUBS", VTP_NULL, VTK_NOLVNULLSUBS, MV_NM),
VIEWTAB("NOUNDEF", VTP_NULL, VTK_NOUNDEF, MV_NM),
VIEWTAB("PATCODE", VTP_VALUE | VTP_NULL, VTK_PATCODE, MV_STR),
VIEWTAB("PATLOAD", VTP_VALUE, VTK_PATLOAD, MV_NM),
-#ifdef DEBUG
-VIEWTAB("PROBECRIT", VTP_DBREGION, VTK_PROBECRIT, MV_NM),
-#endif
+VIEWTAB("POOLLIMIT", VTP_DBREGION | VTP_NULL, VTK_POOLLIMIT, MV_NM),
+VIEWTAB("PROBECRIT", VTP_DBREGION, VTK_PROBECRIT, MV_STR),
VIEWTAB("RCHITS", VTP_NULL, VTK_RCHITS, MV_NM),
VIEWTAB("RCMISSES", VTP_NULL, VTK_RCMISSES, MV_NM),
VIEWTAB("RCSIZE", VTP_NULL, VTK_RCSIZE, MV_NM),
-#if defined(DEBUG) && defined(USHBIN_SUPPORTED)
-VIEWTAB("RCTLDUMP", VTP_NULL, VTK_RCTLDUMP, MV_STR),
-#endif
VIEWTAB("REGION", VTP_DBKEY, VTK_REGION, MV_STR),
VIEWTAB("RESETGVSTATS", VTP_NULL, VTK_RESETGVSTATS, MV_STR),
VIEWTAB("RTNCHECKSUM", VTP_RTNAME, VTK_RTNCHECKSUM, MV_STR),
diff --git a/sr_port/wbox_test_init.h b/sr_port/wbox_test_init.h
index 5d3a11c..0409c6b 100644
--- a/sr_port/wbox_test_init.h
+++ b/sr_port/wbox_test_init.h
@@ -140,9 +140,24 @@ typedef enum {
WBTEST_INFO_HUB_SEND_ZMESS, /* 101 : Print messages triggered via ZMESSAGE to the syslog */
WBTEST_SKIP_CORE_FOR_MEMORY_ERROR, /* 102 : Do not generate core file in case of GTM-E-MEMORY fatal error */
WBTEST_EXTFILTER_INDUCE_ERROR, /* 103 : Do not assert in case of external filter error (test induces that) */
+ WBTEST_BADEXEC_UPDATE_PROCESS, /* 104 : Prevent the update process from EXECing */
+ WBTEST_BADEXEC_HELPER_PROCESS, /* 105 : Prevent the helper processes from EXECing */
+ WBTEST_BADEDITOR_GETEDITOR, /* 106 : Have geteditor return that it was unable to find an editor*/
+ WBTEST_BADEXEC_OP_ZEDIT, /* 107 : Give a invalid executable path to an editor so EXEC will fail*/
+ WBTEST_BADEXEC_SECSHR_PROCESS, /* 108 : Prevent the SECSHR process from being EXEC'ed */
+ WBTEST_BADDUP_PIPE_STDIN, /* 109 : Prevent dup2() of stdin in forked piped process */
+ WBTEST_BADDUP_PIPE_STDOUT, /* 110 : Prevent dup2() of stdout in forked piped process */
+ WBTEST_BADDUP_PIPE_STDERR1, /* 111 : Prevent dup2() of stderr in forked piped process */
+ WBTEST_BADDUP_PIPE_STDERR2, /* 112 : Prevent second dup2() of stderr in forked piped process */
+ WBTEST_BADEXEC_PIPE_PROCESS, /* 113 : Prevent the SECSHR process from being EXEC'ed */
+ WBTEST_MAXGTMDIST_UPDATE_PROCESS, /* 114 : Make gtm_dist too big for update process */
+ WBTEST_MAXGTMDIST_HELPER_PROCESS, /* 115 : Make gtm_dist too big for helper process */
+ WBTEST_MAX_TRIGNAME_SEQ_NUM, /* 116 : Induce "too many triggers" error sooner (MAX_TRIGNAME_SEQ_NUM) */
+ WBTEST_RELINKCTL_MAX_ENTRIES, /* 117 : Bring down the maximum number of relink control entries in one file */
+ WBTEST_FAKE_BIG_KEY_COUNT /* 118 : fake large increase in mupip load key count to show it doesn't overflow */
/* Note 1: when adding new white box test cases, please make use of WBTEST_ENABLED and WBTEST_ASSIGN_ONLY (defined below)
* whenever applicable
- * Note 2: when adding a new white box test case, see if an existing WBTEST_UNUSED* slot can be levereged.
+ * Note 2: when adding a new white box test case, see if an existing WBTEST_UNUSED* slot can be leveraged.
*/
} wbtest_code_t;
diff --git a/sr_port/xfer.h b/sr_port/xfer.h
index bf8e25e..f392284 100644
--- a/sr_port/xfer.h
+++ b/sr_port/xfer.h
@@ -313,7 +313,7 @@ XFER(xf_fnzsocket, op_fnzsocket)
XFER(xf_fnzsyslog, op_fnzsyslog),
XFER(xf_zrupdate, op_zrupdate)
#endif
-#ifdef USHBIN_SUPPORTED
+#ifdef AUTORELINK_SUPPORTED
,
XFER(xf_rhd_ext, op_rhd_ext),
XFER(xf_lab_ext, op_lab_ext)
diff --git a/sr_port/zbreak.h b/sr_port/zbreak.h
index c68d0cd..d7e00a2 100644
--- a/sr_port/zbreak.h
+++ b/sr_port/zbreak.h
@@ -15,6 +15,7 @@
#include <zbreaksp.h>
#include "cache.h"
+/* Structure for each ZBREAK set in the process */
typedef struct
{
zb_code *mpc; /* MUMPS address for ZBREAK */
@@ -23,9 +24,12 @@ typedef struct
int offset;
int count; /* # of time ZBREAK encountered */
cache_entry *action; /* action associated with ZBREAK (indirect cache entry) */
+ rhdtyp *rtnhdr; /* Routine header of routine containing ZBREAK */
zb_code m_opcode; /* MUMPS op_code replaced */
+ char filler[SIZEOF(char *) - SIZEOF(zb_code)];
} zbrk_struct;
+/* ZBREAK anchoring structure */
typedef struct
{
zbrk_struct *beg;
@@ -46,9 +50,9 @@ typedef struct
#define SIZEOF_LA 0
zbrk_struct *zr_find(z_records *zrecs, zb_code *addr);
-zbrk_struct *zr_get_free(z_records *zrecs, zb_code *addr);
+zbrk_struct *zr_add_zbreak(z_records *zrecs, zb_code *addr);
void zr_init(z_records *zrecs, int4 count);
-void zr_put_free(z_records *zrecs, zbrk_struct *z_ptr);
+void zr_remove_zbreak(z_records *zrecs, zbrk_struct *z_ptr);
zb_code *find_line_call(void *addr);
void zr_remove_zbrks(rhdtyp *rtn, boolean_t notify_is_trigger);
diff --git a/sr_port/zlput_rname.c b/sr_port/zlput_rname.c
index e766bb1..cca5129 100644
--- a/sr_port/zlput_rname.c
+++ b/sr_port/zlput_rname.c
@@ -49,6 +49,16 @@ STATICFNDCL boolean_t handle_active_old_versions(boolean_t *duplicated, rhdtyp *
GBLREF rtn_tabent *rtn_fst_table, *rtn_names, *rtn_names_end, *rtn_names_top;
GBLREF stack_frame *frame_pointer;
+/* Routine to perform routine table maintenance. In addition, if a routine is being replaced instead of just added, performs
+ * the necessary maintenance to the replaced routine.
+ *
+ * Parameter:
+ * hdr - routine header address of the routine header just linked in
+ *
+ * Return value:
+ * TRUE - If routine updated/added.
+ * FALSE - If routine could not be updated/added.
+ */
bool zlput_rname (rhdtyp *hdr)
{
rhdtyp *old_rhead, *rhead;
@@ -95,7 +105,7 @@ bool zlput_rname (rhdtyp *hdr)
if (!handle_active_old_versions(&duplicated, old_rhead, hdr))
return FALSE;
if (!duplicated)
- zr_unlink_rtn(old_rhead, FALSE); /* Release private code sections no longer in use */
+ zr_unlink_rtn(old_rhead, FALSE); /* Free releasable pieces of old routines */
# ifndef USHBIN_SUPPORTED
hdr->old_rhead_ptr = (int4)old_rhead;
# else /* USHBIN_SUPPORTED */
@@ -115,6 +125,10 @@ bool zlput_rname (rhdtyp *hdr)
* Parameters:
* rtnhdr - The routine header to start our backwards search at.
* need_duplicate - Address of boolean_t to set if is the exact same routine (same routine header address).
+ *
+ * Return value:
+ * TRUE - If a stack frame specifies the supplied routine header.
+ * FALSE - If no stack frame specifies the supplied routine header.
*/
boolean_t on_stack(rhdtyp *rtnhdr, boolean_t *need_duplicate)
{
@@ -135,10 +149,23 @@ boolean_t on_stack(rhdtyp *rtnhdr, boolean_t *need_duplicate)
return FALSE;
}
+/* Routine to:
+ * 1. Check if the specified routine is currently on the M stack and if it is then
+ * 2. If we are running with VIEW LINK:RECURSIVE.
+ * 3. If no, then return FALSE to signify need for an error.
+ * 4. If yes, we need to do a number of things to allow both versions of the same routine to
+ * exist on the M stack at the same time.
+ *
+ * Parameters:
+ * duplicated - Pointer to boolean return flag indicating we duplicated the input routine header and
+ * related fields.
+ * old_rhead - The routine header being replaced/checked.
+ * hdr - The new routine header doing the replacing.
+ */
STATICFNDEF boolean_t handle_active_old_versions(boolean_t *duplicated, rhdtyp *old_rhead, rhdtyp *hdr)
{
stack_frame *fp;
- rhdtyp *rhead, *new_rhead;
+ rhdtyp *rhead, *copy_rhead;
boolean_t need_duplicate, is_on_stack;
ssize_t sect_rw_nonrel_size;
DCL_THREADGBL_ACCESS;
@@ -157,26 +184,70 @@ STATICFNDEF boolean_t handle_active_old_versions(boolean_t *duplicated, rhdtyp *
}
# ifdef USHBIN_SUPPORTED
if (need_duplicate)
- {
- new_rhead = (rhdtyp *)malloc(SIZEOF(rhdtyp));
- *new_rhead = *old_rhead;
- new_rhead->current_rhead_adr = new_rhead;
- old_rhead->active_rhead_adr = new_rhead; /* Reserve previous version on active chain */
+ { /* The routine is on the M stack so is active. To allow it to stay there while we also link in a newer version
+ * we need to make some changes to the older version. The way the replaced routine would normally be handled if
+ * we weren't keeping it is the various sections of it would be released and the fields in its routine header be
+ * reset to point to those sections in the latest version. That's still going to happen so what we do here is to
+ * create a SEPARATE copy of the routine header that WON'T be modified so all its fields are intact and as they
+ * were along with a separate copy of the label table since the replacement process also resets the label table
+ * to point to the new version of the routine. Lastly, we'll run back through the stack changing the stack frame's
+ * "rvector" field to point to the copied routine header so it continues to work as it did.
+ */
+ copy_rhead = (rhdtyp *)malloc(SIZEOF(rhdtyp));
+ *copy_rhead = *old_rhead;
+ copy_rhead->current_rhead_adr = copy_rhead; /* Grabs of current fhead need to stay with this one for this
+ * older version
+ */
+ copy_rhead->old_rhead_adr = old_rhead; /* Link copied routine back to its original flavor. Used to know which
+ * routine should have its active_rhead_adr field cleared when the copy
+ * becomes inactive and gets cleaned up.
+ */
+ assert(NULL == old_rhead->active_rhead_adr);
+ old_rhead->active_rhead_adr = copy_rhead; /* Reserve previous version on active chain */
for (fp = frame_pointer; NULL != fp; fp = SKIP_BASE_FRAME(fp->old_frame_pointer))
if (CURRENT_RHEAD_ADR(fp->rvector) == old_rhead)
- fp->rvector = new_rhead; /* Point frame's code vector at reserved copy of old routine version */
- /* Any field (e.g. the label table) that is currently shared by old_rhead needs to be copied to a separate area
- * other fields (e.g. literal mvals) will be redirected for old_rhead, so we just need to keep the older version
- * around (don't free it).
+ fp->rvector = copy_rhead; /* Point frame's code vector at reserved copy of old routine version */
+ /* Need to preserve original copy of label table for as long as this routine is active since it is used by
+ * routines like get_symb_line (or symb_line() it calls) and find_line_start() and find_line_addr(). Once the
+ * routine is no longer active, this label table and the copied routine header can go away since no other
+ * routine would have been able to resolve to it. We call the label table copy sect_rw_nonrel_* here because
+ * that is how this section is identified everywhere else. But here, it is releasable when inactive.
*/
sect_rw_nonrel_size = old_rhead->labtab_len * SIZEOF(lab_tabent);
- new_rhead->labtab_adr = (lab_tabent *)malloc(sect_rw_nonrel_size);
- memcpy(new_rhead->labtab_adr, old_rhead->labtab_adr, sect_rw_nonrel_size);
- /* Make sure to: skip urx_remove, do not free code section, etc. */
- /* ALSO: We need to go through resolve linkage table entries corresponding to this the old version, and re-resolve
- * them to point into the new version */
+ copy_rhead->labtab_adr = (lab_tabent *)malloc(sect_rw_nonrel_size);
+ memcpy(copy_rhead->labtab_adr, old_rhead->labtab_adr, sect_rw_nonrel_size);
+ copy_rhead->rtn_relinked = TRUE; /* This flag is checked on unwind to see if routine should be cleaned up */
*duplicated = TRUE;
}
# endif /* USHBIN_SUPPORTED */
return TRUE;
}
+
+#ifdef USHBIN_SUPPORTED
+/* Routine called from op_unwind/unw_retarg/flush_jmp (via CLEANUP_COPIED_RECURSIVE_RTN macro) when a routine pops with the
+ * rtn_relinked flag set indicating potential need to clean up a copied routine header and label table - along with the rest
+ * of the routine's pieces which were purposely bypassed since the routine was on the M stack at the time.
+ */
+void zr_cleanup_recursive_rtn(rhdtyp *rtnhdr)
+{
+ stack_frame *fp;
+
+ /* See if routine is still in use */
+ for (fp = frame_pointer; fp; fp = SKIP_BASE_FRAME(fp->old_frame_pointer))
+ {
+ if (rtnhdr == fp->rvector)
+ break; /* Found reference - not done with it */
+ }
+ if (NULL == fp)
+ { /* We reached the end of the stack without finding the routine, seems ripe for cleaning */
+ assert(rtnhdr->old_rhead_adr->active_rhead_adr == rtnhdr);
+ assert(NULL == rtnhdr->active_rhead_adr);
+ zr_unlink_rtn(rtnhdr, FALSE); /* Cleans up the copy */
+ assert(!rtnhdr->has_ZBREAK);
+ assert(!rtnhdr->old_rhead_adr->has_ZBREAK); /* These should both be cleared now if ever set */
+ free(rtnhdr->labtab_adr);
+ rtnhdr->old_rhead_adr->active_rhead_adr = NULL;
+ free(rtnhdr);
+ }
+}
+#endif /* USHBIN_SUPPORTED */
diff --git a/sr_port/zr_get_free.c b/sr_port/zr_add_zbreak.c
similarity index 78%
rename from sr_port/zr_get_free.c
rename to sr_port/zr_add_zbreak.c
index b5b0b6a..4a5d6a8 100644
--- a/sr_port/zr_get_free.c
+++ b/sr_port/zr_add_zbreak.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -16,22 +16,22 @@
#include <rtnhdr.h>
#include "zbreak.h"
-zbrk_struct *zr_get_free(z_records *zrecs, zb_code *addr)
+zbrk_struct *zr_add_zbreak(z_records *zrecs, zb_code *addr)
{
z_records temp;
zbrk_struct *z_ptr;
- /* NOTE: records are stored by decreasing addresses */
+ /* NOTE: Records are stored by decreasing addresses */
assert(zrecs->free < zrecs->end);
for (z_ptr = zrecs->beg; z_ptr < zrecs->free; z_ptr++)
{
if (z_ptr->mpc == addr)
return (z_ptr);
- if (z_ptr->mpc < addr) /* insert here */
+ if (z_ptr->mpc < addr) /* Insert here */
break;
}
assert(z_ptr == zrecs->free || z_ptr->mpc < addr);
- if (1 == zrecs->end - zrecs->free) /* expand if necessary */
+ if (1 == zrecs->end - zrecs->free) /* Expand if necessary */
{
temp = *zrecs;
zr_init(zrecs, 2 * (int)(zrecs->end - zrecs->beg));
@@ -42,7 +42,7 @@ zbrk_struct *zr_get_free(z_records *zrecs, zb_code *addr)
z_ptr = zrecs->beg + (z_ptr - temp.beg);
free(temp.beg);
}
- /* shift records down into the bottom spot which was allocated */
+ /* Shift records down into the bottom spot which was allocated */
memmove((char *)(z_ptr + 1), (char *)z_ptr, (zrecs->free - z_ptr) * SIZEOF(zbrk_struct));
memset((char *)z_ptr, 0, SIZEOF(zbrk_struct));
z_ptr->mpc = addr;
diff --git a/sr_port/zr_put_free.c b/sr_port/zr_remove_zbreak.c
similarity index 55%
rename from sr_port/zr_put_free.c
rename to sr_port/zr_remove_zbreak.c
index 75524f0..e2018a9 100644
--- a/sr_port/zr_put_free.c
+++ b/sr_port/zr_remove_zbreak.c
@@ -20,10 +20,10 @@
#include "private_code_copy.h"
#include "gtm_text_alloc.h"
-void zr_put_free(z_records *zrecs, zbrk_struct *z_ptr)
+void zr_remove_zbreak(z_records *zrecs, zbrk_struct *z_ptr)
{
mstr rtn_str;
- rhdtyp *routine;
+ rhdtyp *routine, *rtncopy;
boolean_t deleted;
assert(zrecs->beg <= zrecs->free);
@@ -32,22 +32,22 @@ void zr_put_free(z_records *zrecs, zbrk_struct *z_ptr)
assert(z_ptr <= zrecs->free);
if (NULL != z_ptr->action)
{ /* An action exists, reduce our interest in it */
- assert(z_ptr->action->zb_refcnt > 0);
+ assert(0 < z_ptr->action->zb_refcnt);
z_ptr->action->zb_refcnt--;
if (0 == z_ptr->action->zb_refcnt)
z_ptr->action = NULL;
}
- /* In the generated code, change the offset in TRANSFER TABLE */
+ /* In the generated code, change the opcode in the instruction */
# ifdef COMPLEX_INSTRUCTION_UPDATE
EXTRACT_AND_UPDATE_INST(z_ptr->mpc, z_ptr->m_opcode);
# else
*z_ptr->mpc = z_ptr->m_opcode;
-# endif
+# endif /* COMPLEX_INSTRUCTION_UPDATE */
inst_flush(z_ptr->mpc, SIZEOF(INST_TYPE));
# ifdef USHBIN_SUPPORTED
- if (((z_ptr == zrecs->beg) || !MIDENT_EQ((z_ptr - 1)->rtn, z_ptr->rtn)) &&
- (((z_ptr + 1) == zrecs->free) || !MIDENT_EQ((z_ptr + 1)->rtn, z_ptr->rtn)))
- { /* No more breakpoints in the routine we just removed a break from. Note that since zrecs is sorted based
+ if (((z_ptr == zrecs->beg) || ((z_ptr - 1)->rtnhdr != z_ptr->rtnhdr))
+ && (((z_ptr + 1) == zrecs->free) || ((z_ptr + 1)->rtnhdr != z_ptr->rtnhdr)))
+ { /* No more breakpoints in the routine we just removed a ZBREAK from. Note that since zrecs is sorted based
* on mpc, all breakpoints in a given routine are bunched together. Hence, it is possible to determine
* if all breakpoints are deleted from a routine by checking the preceding and succeeding entries of the
* one we are removing.
@@ -55,16 +55,30 @@ void zr_put_free(z_records *zrecs, zbrk_struct *z_ptr)
assert(0 != z_ptr->rtn->len);
rtn_str.len = z_ptr->rtn->len;
rtn_str.addr = z_ptr->rtn->addr;
- routine = find_rtn_hdr(&rtn_str);
- if (NULL != routine->shared_ptext_adr) /* don't need the private copy any more, revert back to shared copy */
- release_private_code_copy(routine);
+ routine = rtncopy = z_ptr->rtnhdr;
+ assert(NULL != routine);
+ /* We now have the routine header associated with this ZBREAK. But if this routine was recursively relinked
+ * AND shared, then the address we need to check about releasing is associated with the copy of the routine
+ * header/code we made for the recursive link (see handle_active_old_versions() for description).
+ */
+ if (NULL != routine->active_rhead_adr)
+ {
+ rtncopy = routine->active_rhead_adr;
+ rtncopy->has_ZBREAK = FALSE;
+ }
+ if (NULL != rtncopy->shared_ptext_adr) /* Revert back to shared copy of routine */
+ {
+ assert(rtncopy->shared_ptext_adr != rtncopy->ptext_adr);
+ release_private_code_copy(rtncopy);
+ }
+ routine->has_ZBREAK = FALSE; /* Indicate no more ZBREAKs in this routine */
}
-# endif
+# endif /* USHBIN_SUPPORTED */
zrecs->free--;
- /* potentially overlapped memory, use memmove, not memcpy */
+ /* Potentially overlapped memory, use memmove, not memcpy */
memmove((char *)z_ptr, (char *)(z_ptr + 1), (zrecs->free - z_ptr) * SIZEOF(zbrk_struct));
if (zrecs->free == zrecs->beg)
- { /* all breaks gone, free space allocated for breakpoints */
+ { /* All ZBREAKS gone, free space allocated for breakpoints */
free(zrecs->beg);
zrecs->beg = NULL;
zrecs->free = NULL;
diff --git a/sr_port/zr_remove_zbrks.c b/sr_port/zr_remove_zbrks.c
index f8a2dee..39a005c 100644
--- a/sr_port/zr_remove_zbrks.c
+++ b/sr_port/zr_remove_zbrks.c
@@ -24,13 +24,24 @@ GTMTRIG_ONLY(error_def(ERR_TRIGZBREAKREM);)
/* Remove all ZBREAKs in given rtn */
void zr_remove_zbrks(rhdtyp *rtn, boolean_t notify_is_trigger)
{
+ rhdtyp *rtn_look;
zbrk_struct *zb_ptr;
GTMTRIG_ONLY(boolean_t msg_done = FALSE;)
+ rtn_look = rtn; /* Initially routine to look for is same */
+# ifdef USHBIN_SUPPORTED
+ if ((NULL != rtn) && (rtn->rtn_relinked))
+ { /* For a recursively linked routine, the saved routine header is actually the original, not the
+ * copy we were supplied by caller.
+ */
+ rtn_look = rtn->old_rhead_adr;
+ }
+# endif /* USHBIN_SUPPORTED */
for (zb_ptr = zbrk_recs.free - 1; NULL != zbrk_recs.beg && zb_ptr >= zbrk_recs.beg; zb_ptr--)
{ /* Go in the reverse order to reduce memory movement in zr_put_free() */
- if ((NULL == rtn) || (ADDR_IN_CODE(((unsigned char *)zb_ptr->mpc), rtn)))
+ if ((NULL == rtn_look) || (zb_ptr->rtnhdr == rtn_look))
{
+ assert((NULL == rtn_look) || (ADDR_IN_CODE(((unsigned char *)zb_ptr->mpc), rtn)));
# ifdef GTM_TRIGGER
if ((BREAKMSG == notify_is_trigger) && !msg_done && (break_message_mask & TRIGGER_ZBREAK_REMOVED_MASK))
{ /* Message is info level */
@@ -39,7 +50,7 @@ void zr_remove_zbrks(rhdtyp *rtn, boolean_t notify_is_trigger)
msg_done = TRUE;
}
# endif
- zr_put_free(&zbrk_recs, zb_ptr);
+ zr_remove_zbreak(&zbrk_recs, zb_ptr);
}
}
return;
diff --git a/sr_port/zr_unlink_rtn.c b/sr_port/zr_unlink_rtn.c
index 3005298..bc7885e 100644
--- a/sr_port/zr_unlink_rtn.c
+++ b/sr_port/zr_unlink_rtn.c
@@ -14,7 +14,6 @@
#include <stddef.h> /* for offsetof macro */
#include "gtm_stdlib.h"
#include "gtm_string.h"
-#include "sys/mman.h"
#include <rtnhdr.h>
#include "fix_pages.h"
@@ -27,6 +26,9 @@
#include "zr_unlink_rtn.h"
#include "zroutines.h"
#include "incr_link.h"
+#ifdef UNIX
+#include "rtnobj.h"
+#endif
/* Routine to unlink given old flavor of routine (as much of it as we are able).
*
@@ -42,7 +44,6 @@
*/
void zr_unlink_rtn(rhdtyp *old_rhead, boolean_t free_all)
{
- unsigned char *map_adr; /* If code section is mmapped from shared .o file */
textElem *telem;
rhdtyp *rhdr, *next_rhdr;
@@ -69,14 +70,11 @@ void zr_unlink_rtn(rhdtyp *old_rhead, boolean_t free_all)
{ /* Object is not resident in a shared library */
if (!free_all)
zlmov_lnames(old_rhead); /* Copy the label names from literal pool to malloc'd area */
- if (0 < old_rhead->shared_len)
- { /* Object is being shared via mmap() */
- assert(NULL != old_rhead->shared_ptext_adr);
- assert(old_rhead->shared_ptext_adr == old_rhead->ptext_adr);
- map_adr = old_rhead->shared_ptext_adr - SIZEOF(rhdtyp)- NATIVE_HDR_LEN;
- munmap(map_adr, old_rhead->shared_len);
-
- } else
+# ifdef AUTORELINK_SUPPORTED
+ if (old_rhead->shared_object)
+ rtnobj_shm_free(old_rhead, LATCH_GRABBED_FALSE); /* Object is shared via rtnobj shared memory */
+ else
+# endif
{ /* Process private linked object */
GTM_TEXT_FREE(old_rhead->ptext_adr);
}
@@ -92,20 +90,27 @@ void zr_unlink_rtn(rhdtyp *old_rhead, boolean_t free_all)
old_rhead->vartab_adr = NULL;
free(old_rhead->linkage_adr); /* Release the old linkage section */
old_rhead->linkage_adr = NULL;
-# else
+# ifdef AUTORELINK_SUPPORTED
+ if (NULL != old_rhead->zhist)
+ { /* Free history used for autorelink if present */
+ free(old_rhead->zhist);
+ old_rhead->zhist = NULL;
+ }
+# endif /* AUTORELINK_SUPPORTED */
+# else /* (now) !USHBIN_SUPPORTED */
if (!old_rhead->old_rhead_ptr)
- { /* On VMS, this makes the routine "malleable" and on UNIX tiz a stub */
+ { /* On VMS, this makes the routine "malleable" and on UNIX tiz currently a stub */
fix_pages((unsigned char *)old_rhead, (unsigned char *)LNRTAB_ADR(old_rhead)
+ (SIZEOF(lnr_tabent) * old_rhead->lnrtab_len));
}
-# endif
+# endif /* !USHBIN_SUPPORTED */
if (free_all)
{ /* We are not keeping any parts of this routine (generally used for triggers and for gtm_unlink_all()) */
# ifdef USHBIN_SUPPORTED
free(old_rhead->labtab_adr); /* Usually non-releasable but not in this case */
if (old_rhead->lbltext_ptr)
free(old_rhead->lbltext_ptr); /* Get rid of any label text hangers-on */
- if (old_rhead->shared_len) /* If this is a shared object (not library), drop rtn name/path text */
+ if (old_rhead->shared_object) /* If this is a shared object (not library), drop rtn name/path text */
free(old_rhead->src_full_name.addr);
/* Run the chain of old (replaced) versions freeing them also if they exist*/
for (rhdr = OLD_RHEAD_ADR(old_rhead); NULL != rhdr; rhdr = next_rhdr)
@@ -113,7 +118,7 @@ void zr_unlink_rtn(rhdtyp *old_rhead, boolean_t free_all)
next_rhdr = rhdr->old_rhead_adr;
if (rhdr->lbltext_ptr)
free(rhdr->lbltext_ptr); /* Get rid of any label text hangers-on */
- if (rhdr->shared_len) /* If this is a shared object, drop rtn name/path text */
+ if (rhdr->shared_object) /* If this is a shared object, drop rtn name/path text */
free(rhdr->src_full_name.addr);
free(rhdr->labtab_adr); /* Free dangling label table */
free(rhdr);
diff --git a/sr_port/zshow.h b/sr_port/zshow.h
index ca5893f..19dc01f 100644
--- a/sr_port/zshow.h
+++ b/sr_port/zshow.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -98,9 +98,14 @@ void zshow_zwrite(zshow_out *output);
boolean_t zwr2format(mstr *src, mstr *des);
int zwrkeyvallen(char* ptr, int len, char **val_off, int *val_len, int *val_off1, int *val_len1);
int format2zwr(sm_uc_ptr_t src, int src_len, unsigned char *des, int *des_len);
+void format2disp(char *src, int src_len, char *dispbuff, int *displen);
void mval_write(zshow_out *output, mval *v, boolean_t flush);
void mval_nongraphic(zshow_out *output, char *cp, int len, int num);
void gvzwr_fini(zshow_out *out, int pat);
void lvzwr_fini(zshow_out *out, int t);
+#ifdef AUTORELINK_SUPPORTED
+void zshow_rctldump(zshow_out *output);
+#endif
+
#endif
diff --git a/sr_port/zshow_output.c b/sr_port/zshow_output.c
index 210e05f..2f29f3b 100644
--- a/sr_port/zshow_output.c
+++ b/sr_port/zshow_output.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -41,7 +41,19 @@
#define F_SUBSC_LEN 3
#define N_SUBSC_LEN 5
#define MIN_DATASIZE 40
-#define ZSHOW_SPACE_INDENT 10 /* # of spaces every following line of zshow output is indented with */
+
+#define WRITE_ONE_LINE_FROM_BUFFER \
+{ \
+ mv->str.addr = out->buff; \
+ mv->str.len = INTCAST(out->ptr - out->buff); \
+ mv->mvtype = MV_STR; \
+ op_write(mv); \
+ op_wteol(1); \
+ out->ptr = out->buff; \
+ out->len = 0; \
+ out->displen = 0; \
+ out->line_num++; \
+}
GBLREF io_pair io_curr_device;
GBLREF spdesc stringpool;
@@ -61,7 +73,7 @@ void zshow_output(zshow_out *out, const mstr *str)
mval *mv, lmv;
lv_val *lv, *lv_child;
char buff, *strptr, *strnext, *strtop, *strbase, *leadptr;
- int key_ovrhd, str_processed, n_spaces, sbs_depth, dbg_sbs_depth;
+ int key_ovrhd, str_processed, sbs_depth, dbg_sbs_depth;
ssize_t len, outlen, chcnt, char_len, disp_len ;
int buff_len;
int device_width, inchar_width, cumul_width;
@@ -101,10 +113,7 @@ void zshow_output(zshow_out *out, const mstr *str)
str_processed = 0;
}
device_width = io_curr_device.out->width;
- /* Do not indent if width is < the indentation length or if remaining width cannot accommodate one character */
- n_spaces = (device_width > (ZSHOW_SPACE_INDENT UNICODE_ONLY(+ (gtm_utf8_mode ? GTM_MB_DISP_LEN_MAX : 0)))
- ? ZSHOW_SPACE_INDENT : 0);
- if (str && (disp_len + out->displen > device_width))
+ if (str)
{
for (; (len > 0) && (disp_len + out->displen > device_width); )
{
@@ -143,37 +152,15 @@ void zshow_output(zshow_out *out, const mstr *str)
char_len -= chcnt;
assert((UNICODE_ONLY((gtm_utf8_mode) ?
(ssize_t)UTF8_LEN_STRICT(strptr, (int)len) :) len) == char_len);
- mv->str.addr = out->buff;
- mv->str.len = INTCAST(out->ptr - out->buff);
- mv->mvtype = MV_STR;
- op_write(mv);
- op_wteol(1);
- out->ptr = out->buff + n_spaces;
- memset(out->buff, ' ', n_spaces);
- out->len = n_spaces;
- out->displen = n_spaces;
- out->line_num++;
+ WRITE_ONE_LINE_FROM_BUFFER;
}
- }
- if (str)
- {
memcpy(out->ptr, str->addr + str_processed, len);
out->ptr += len;
out->len += (int)char_len;
out->displen += (int)disp_len;
}
if (out->flush && out->ptr != out->buff)
- {
- mv->str.addr = out->buff;
- mv->str.len = INTCAST(out->ptr - out->buff);
- mv->mvtype = MV_STR;
- op_write(mv);
- op_wteol(1);
- out->ptr = out->buff;
- out->len = 0;
- out->displen = 0;
- out->line_num++;
- }
+ WRITE_ONE_LINE_FROM_BUFFER
break;
case ZSHOW_LOCAL:
if (out->code)
@@ -254,8 +241,7 @@ void zshow_output(zshow_out *out, const mstr *str)
memcpy(mv->str.addr, &out->buff[0], mv->str.len);
stringpool.free += mv->str.len;
lv->v = *mv;
- out->ptr = out->buff + 10;
- memset(out->buff, ' ', 10);
+ out->ptr = out->buff;
out->line_num++;
}
}
@@ -360,8 +346,7 @@ void zshow_output(zshow_out *out, const mstr *str)
memcpy(mv->str.addr, &out->buff[0], mv->str.len);
stringpool.free += mv->str.len;
op_gvput(mv);
- out->ptr = out->buff + 10;
- memset(out->buff, ' ', 10);
+ out->ptr = out->buff;
out->line_num++;
}
}
diff --git a/sr_port/zshow_svn.c b/sr_port/zshow_svn.c
index a79c62c..01ee873 100644
--- a/sr_port/zshow_svn.c
+++ b/sr_port/zshow_svn.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -109,6 +109,7 @@ static readonly char zsystem_text[] = "$ZSYSTEM";
#ifdef GTM_TRIGGER
static readonly char ztname_text[] = "$ZTNAME";
static readonly char ztdata_text[] = "$ZTDATA";
+static readonly char ztdelim_text[] = "$ZTDELIM";
#endif
static readonly char ztexit_text[] = "$ZTEXIT";
GTMTRIG_ONLY(static readonly char ztlevel_text[] = "$ZTLEVEL";)
@@ -161,6 +162,7 @@ GBLREF boolean_t dollar_zquit_anyway;
#ifdef GTM_TRIGGER
GBLREF mstr *dollar_ztname;
GBLREF mval *dollar_ztdata;
+GBLREF mval *dollar_ztdelim;
GBLREF mval *dollar_ztoldval;
GBLREF mval *dollar_ztriggerop;
GBLREF mval dollar_ztslate;
@@ -674,6 +676,18 @@ void zshow_svn(zshow_out *output, int one_sv)
mval_write(output, &var, TRUE);
if (SV_ALL != one_sv)
break;
+ /* CAUTION: fall through */
+ case SV_ZTDELIM:
+ if (NULL != dollar_ztdelim && (0 < dollar_ztdelim->str.len))
+ {
+ var.mvtype = MV_STR;
+ var.str = dollar_ztdelim->str;
+ } else
+ memcpy(&var, &literal_null, SIZEOF(mval));
+ ZS_VAR_EQU(&x, ztdelim_text);
+ mval_write(output, &var, TRUE);
+ if (SV_ALL != one_sv)
+ break;
# endif
/* CAUTION: fall through */
case SV_ZTEXIT:
diff --git a/sr_unix/CMakeLists.txt b/sr_unix/CMakeLists.txt
index 40f5eb4..d07f854 100644
--- a/sr_unix/CMakeLists.txt
+++ b/sr_unix/CMakeLists.txt
@@ -60,8 +60,6 @@ set(gtm_osarch_libs "")
set(gt_src_list)
set(sources_used "")
set(extralibs "")
-set(GTMCRYPTLIB "GCRYPT")
-set(GTMCRYPTALGO "AES256CFB")
message("--> OS = ${CMAKE_SYSTEM_NAME} / ARCH = ${CMAKE_SYSTEM_PROCESSOR}")
# Establish platform
# Except for Solaris, CMAKE_COMPILER_IS_GNUCC is true
@@ -76,7 +74,6 @@ elseif("${CMAKE_SYSTEM_NAME}" MATCHES "SunOS")
else()
message(FATAL_ERROR "--> OS = ${CMAKE_SYSTEM_NAME} / ARCH = ${CMAKE_SYSTEM_PROCESSOR}")
endif()
-message("--> Encryption Library = ${GTMCRYPTLIB} / Algorithm = ${GTMCRYPTALGO}")
# Choose where to get bootstrap sources.
set(GTM_DIST "" CACHE PATH "Existing GT.M Distribution")
@@ -461,14 +458,50 @@ foreach(tlslib ssl crypto config)
set(TLS_LIBRARIES ${TLS_LIBRARIES} ${TLSLIB_${tlslib}})
endforeach()
-add_library(libgtmcrypt MODULE ${libgtmcrypt_SOURCES})
-set_target_properties(libgtmcrypt PROPERTIES
- OUTPUT_NAME gtmcrypt
- COMPILE_DEFINITIONS "USE_${GTMCRYPTLIB} -DUSE_${GTMCRYPTALGO}"
+# Building the three encryption libraries could by a loop of some sort, but
+# manually creating each target is way easier.
+
+# Library=GCRYPT Algorithm=AES256CFB
+add_library(libgtmcrypt_gcrypt_AES256CFB.so MODULE ${libgtmcrypt_SOURCES})
+set_target_properties(libgtmcrypt_gcrypt_AES256CFB.so PROPERTIES
+ OUTPUT_NAME gtmcrypt_gcrypt_AES256CFB
+ COMPILE_DEFINITIONS "USE_GCRYPT -DUSE_AES256CFB"
+ LIBRARY_OUTPUT_DIRECTORY ${GTM_BINARY_DIR}/plugin
+ )
+target_link_libraries(libgtmcrypt_gcrypt_AES256CFB.so ${GPG_LIBRARIES})
+install(TARGETS libgtmcrypt_gcrypt_AES256CFB.so DESTINATION ${GTM_INSTALL_DIR}/plugin)
+
+# Establish the default encryption link
+set(default_encr_link ${GTM_BINARY_DIR}/plugin/libgtmcrypt.so)
+set(default_encr_target libgtmcrypt_gcrypt_AES256CFB.so)
+add_custom_command(
+ OUTPUT ${default_encr_link}
+ COMMAND ${CMAKE_COMMAND} -E create_symlink "${default_encr_target}" "${default_encr_link}"
+ DEPENDS ${GTM_BINARY_DIR}/plugin/${default_encr_target}
+ COMMENT "Generating default_encr symbolic link"
+ )
+add_custom_target(install_default_encr ALL DEPENDS ${default_encr_link})
+install(FILES ${default_encr_link} DESTINATION ${GTM_INSTALL_DIR}/plugin)
+
+# Library=OPENSSL Algorithm=AES256CFB
+add_library(libgtmcrypt_openssl_AES256CFB MODULE ${libgtmcrypt_SOURCES})
+set_target_properties(libgtmcrypt_openssl_AES256CFB PROPERTIES
+ OUTPUT_NAME gtmcrypt_openssl_AES256CFB
+ COMPILE_DEFINITIONS "USE_OPENSSL -DUSE_AES256CFB"
+ LIBRARY_OUTPUT_DIRECTORY ${GTM_BINARY_DIR}/plugin
+ )
+target_link_libraries(libgtmcrypt_openssl_AES256CFB ${GPG_LIBRARIES} ${TLS_LIBRARIES})
+install(TARGETS libgtmcrypt_openssl_AES256CFB DESTINATION ${GTM_INSTALL_DIR}/plugin)
+
+# Library=OPENSSL Algorithm=BLOWFISHCFB
+add_library(libgtmcrypt_openssl_BLOWFISHCFB MODULE ${libgtmcrypt_SOURCES})
+set_target_properties(libgtmcrypt_openssl_BLOWFISHCFB PROPERTIES
+ OUTPUT_NAME gtmcrypt_openssl_BLOWFISHCFB
+ COMPILE_DEFINITIONS "USE_OPENSSL -DUSE_BLOWFISHCFB"
LIBRARY_OUTPUT_DIRECTORY ${GTM_BINARY_DIR}/plugin
)
-target_link_libraries(libgtmcrypt ${GPG_LIBRARIES})
-install(TARGETS libgtmcrypt DESTINATION ${GTM_INSTALL_DIR}/plugin)
+target_link_libraries(libgtmcrypt_openssl_BLOWFISHCFB ${GPG_LIBRARIES} ${TLS_LIBRARIES})
+install(TARGETS libgtmcrypt_openssl_BLOWFISHCFB DESTINATION ${GTM_INSTALL_DIR}/plugin)
add_library(libgtmtls MODULE ${libgtmtls_SOURCES})
set_target_properties(libgtmtls PROPERTIES
@@ -482,7 +515,7 @@ install(TARGETS libgtmtls DESTINATION ${GTM_INSTALL_DIR}/plugin)
add_executable(maskpass ${maskpass_SOURCES})
target_link_libraries(maskpass ${GPG_LIBRARIES} ${TLS_LIBRARIES})
set_target_properties(maskpass PROPERTIES
- COMPILE_DEFINITIONS "USE_${GTMCRYPTLIB} -DUSE_SYSLIB_FUNCS"
+ COMPILE_DEFINITIONS "USE_GCRYPT -DUSE_SYSLIB_FUNCS"
RUNTIME_OUTPUT_DIRECTORY ${GTM_BINARY_DIR}/plugin/gtmcrypt
)
install(TARGETS maskpass DESTINATION ${GTM_INSTALL_DIR}/plugin/gtmcrypt)
diff --git a/sr_unix/Makefile.mk b/sr_unix/Makefile.mk
index 7e3789c..c004326 100644
--- a/sr_unix/Makefile.mk
+++ b/sr_unix/Makefile.mk
@@ -26,8 +26,12 @@ endif
DISTDIR = $(gtm_dist)
PLUGINDIR = $(DISTDIR)/plugin
+GTMCRYPTDIR = $(PLUGINDIR)/gtmcrypt
CURDIR = `pwd`
+# Find out whether we are already in $gtm_dist/plugin/gtmcrypt directory.
+NOT_IN_GTMCRYPTDIR = $(shell [ "$(CURDIR)" = "$(GTMCRYPTDIR)" ] ; echo $$?)
+
# Determine machine and OS type.
UNAMESTR = $(shell uname -a)
MACHTYPE = $(shell uname -m)
@@ -35,7 +39,7 @@ MACHTYPE = $(shell uname -m)
ifneq (,$(findstring Linux,$(UNAMESTR)))
FILEFLAG = -L
endif
-# 64 bit system? 0 for yes!
+# 64 bit version of GT.M? 0 for yes!
BIT64 = $(shell file $(FILEFLAG) $(DISTDIR)/mumps | grep -q -E '64-bit|ELF-64'; echo $$?)
# Default installation target. This allows for the build system to randomize `thirdparty' and `algo' thereby changing the default
@@ -52,10 +56,9 @@ else
endif
CC = cc
-LD = $(CC)
# Setup common compiler flags
-CFLAGS = -c $(debug_flag) $(optimize) -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES -D_LARGEFILE64_SOURCE=1
+CFLAGS = $(debug_flag) $(optimize) -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES -D_LARGEFILE64_SOURCE=1
ifneq ($(gcrypt_nofips),0)
gcrypt_nofips_flag = -DGCRYPT_NO_FIPS
@@ -119,7 +122,10 @@ ifneq (,$(findstring AIX,$(UNAMESTR)))
CFLAGS += -qro -qroconst -q64
# -q64 for 64-bit object generation
# -brtl for allowing both '.a' and '.so' to be searched at runtime.
- LDFLAGS = -q64 -brtl
+ # -bhalt:5 is to disable warnings about duplicate symbols that come from
+ # libgtmcryptutil.so and other .so that need pulling the same object
+ # file (/lib/crt0_64.o)
+ LDFLAGS = -q64 -brtl -bhalt:5
RPATHFLAGS =
# -G so that we can build shared library
# -bexpall exports all symbols from the shared library.
@@ -145,81 +151,67 @@ LDFLAGS += $(LIBFLAGS) -o
COMMON_LIBS = -lgtmcryptutil -lconfig
-# List of all files needed for building the encryption plugin.
+# Lists of all files needed for building the encryption plugin.
+crypt_util_srcfiles = gtmcrypt_util.c
+crypt_util_hdrfiles = gtmcrypt_util.h gtmcrypt_interface.h
crypt_srcfiles = gtmcrypt_ref.c gtmcrypt_pk_ref.c gtmcrypt_dbk_ref.c gtmcrypt_sym_ref.c
-crypt_objfiles = gtmcrypt_ref.o gtmcrypt_pk_ref.o gtmcrypt_dbk_ref.o gtmcrypt_sym_ref.o
-all_crypt_objfiles = $(crypt_objfiles)
-
-tls_srcfiles = gtm_tls_impl.c gtm_tls_impl.h gtm_tls_interface.h
-tls_objfiles = gtm_tls_impl.o
-
-all_objfiles = $(all_crypt_objfiles) $(tls_objfiles) maskpass.o gtmcrypt_util.o gtmcrypt_util_syslib.o
-
-all: libgtmcryptutil.so maskpass gcrypt openssl gtmtls
- rm -f $(crypt_objfiles) maskpass.o
-
-gtmcrypt_util.o: gtmcrypt_util.c
- $(CC) $(CFLAGS) $(default_thirdparty_CFLAGS) $^
-
-# Rules for building libgtmcryptutil.so
-libgtmcryptutil.so: gtmcrypt_util.o
- $(LD) $^ $(LDSHR) $(LDFLAGS) $@ $(default_thirdparty_LDFLAGS)
-
-# Rules for building maskpass
-maskpass.o: maskpass.c
- $(CC) $(CFLAGS) $^
-
-# Since maskpass is a standalone utility and doesn't depend on functions like `gtm_malloc' and `gtm_free' for memory allocation,
-# build gtmcrypt_util.c with -DUSE_SYSLIB_FUNCS.
-gtmcrypt_util_syslib.o: gtmcrypt_util.c
- $(CC) $(CFLAGS) -DUSE_SYSLIB_FUNCS $(default_thirdparty_CFLAGS) -o $@ $^
-
-# Since maskpass is a standalone utility, link it with gtmcrypt_utils_syslib.o instead of libgtmcryptutil.so. This allows maskpass
-# to be run without the need for the user setting LD_LIBRARY_PATH/LIBPATH to load libgtmcryptutil.so.
-maskpass: maskpass.o gtmcrypt_util_syslib.o
- $(LD) $(LDFLAGS) maskpass $^ $(default_thirdparty_LDFLAGS)
-
-# Rules for building libgtmtls.so
-gtm_tls_impl.o: gtm_tls_impl.c
- $(CC) $(CFLAGS) $<
-
-gtmtls: gtm_tls_impl.o libgtmcryptutil.so
- $(LD) $< $(LDSHR) $(RPATHFLAGS) $(LDFLAGS) lib$@.so -lssl $(COMMON_LIBS)
-
-# Rules for building all supported variations of encryption libraries. These again point to the specific ones.
-gcrypt: gcrypt_AES256CFB
-
-openssl: openssl_AES256CFB openssl_BLOWFISHCFB
-
-# Rules for building specific encryption libraries.
-gcrypt_AES256CFB: $(crypt_srcfiles) libgtmcryptutil.so
- $(CC) $(CFLAGS) -DUSE_GCRYPT -DUSE_AES256CFB $(gcrypt_nofips_flag) $(crypt_srcfiles)
- $(LD) $(crypt_objfiles) $(LDSHR) $(RPATHFLAGS) $(LDFLAGS) libgtmcrypt_$@.so -lgcrypt -lgpgme -lgpg-error $(COMMON_LIBS)
-
-openssl_AES256CFB: $(crypt_srcfiles) libgtmcryptutil.so
- $(CC) $(CFLAGS) -DUSE_OPENSSL -DUSE_AES256CFB $(crypt_srcfiles)
- $(LD) $(crypt_objfiles) $(LDSHR) $(RPATHFLAGS) $(LDFLAGS) libgtmcrypt_$@.so -lcrypto -lgpgme -lgpg-error $(COMMON_LIBS)
-
-openssl_BLOWFISHCFB: $(crypt_srcfiles) libgtmcryptutil.so
- $(CC) $(CFLAGS) -DUSE_OPENSSL -DUSE_BLOWFISHCFB $(crypt_srcfiles)
- $(LD) $(crypt_objfiles) $(LDSHR) $(RPATHFLAGS) $(LDFLAGS) libgtmcrypt_$@.so -lcrypto -lgpgme -lgpg-error $(COMMON_LIBS)
-
-# The below rule is useful when the user wants to [re]build a specific target (one of gcrypt_AES256CFB, openssl_AES256CFB or
-# openssl_BLOWFISHCFB).
-gtmcrypt: $(thirdparty)_$(algo)
-
-
-# install, uninstall and cleanup rules.
-install:
- rm -f $(all_objfiles)
- mv *.so $(PLUGINDIR)
- ln -s ./$(install_targ) $(PLUGINDIR)/libgtmcrypt.so
+crypt_hrdfiles = gtmcrypt_ref.h gtmcrypt_pk_ref.h gtmcrypt_dbk_ref.h gtmcrypt_sym_ref.h gtmcrypt_interface.h
+tls_srcfiles = gtm_tls_impl.c
+tls_hdrfiles = gtm_tls_impl.h gtm_tls_interface.h
+
+all: libgtmcryptutil.so maskpass gcrypt openssl libgtmtls.so
+
+libgtmcryptutil.so: $(crypt_util_srcfiles) $(crypt_util_hdrfiles)
+ @echo ; echo "Compiling $@..."
+ $(CC) $(CFLAGS) $(default_thirdparty_CFLAGS) $(crypt_util_srcfiles) $(LDSHR) $(LDFLAGS) $@ $(default_thirdparty_LDFLAGS)
+
+# Since maskpass is a standalone utility, link it (implicitly) with gtmcrypt_util.o instead of libgtmcryptutil.so. This allows
+# maskpass to be run without setting LD_LIBRARY_PATH/LIBPATH to load libgtmcryptutil.so. As a standalone utility maskpass should
+# not depend on functions like `gtm_malloc' and `gtm_free', so we are compiling the executable with -DUSE_SYSLIB_FUNCS.
+maskpass: maskpass.c $(crypt_util_srcfiles) $(crypt_util_hdrfiles)
+ @echo ; echo "Compiling $@..."
+ $(CC) $(CFLAGS) -DUSE_SYSLIB_FUNCS $(default_thirdparty_CFLAGS) maskpass.c $(crypt_util_srcfiles) \
+ $(LDFLAGS) $@ $(default_thirdparty_LDFLAGS)
+
+gcrypt: libgtmcrypt_gcrypt_AES256CFB.so
+
+libgtmcrypt_gcrypt_AES256CFB.so: $(crypt_srcfiles) $(crypt_hdrfiles) libgtmcryptutil.so
+ @echo ; echo "Compiling $@..."
+ $(CC) $(CFLAGS) -DUSE_GCRYPT -DUSE_AES256CFB $(gcrypt_nofips_flag) $(crypt_srcfiles) $(LDSHR) \
+ $(RPATHFLAGS) $(LDFLAGS) $@ -lgcrypt -lgpgme -lgpg-error $(COMMON_LIBS)
+
+openssl: libgtmcrypt_openssl_AES256CFB.so libgtmcrypt_openssl_BLOWFISHCFB.so
+
+libgtmcrypt_openssl_AES256CFB.so: $(crypt_srcfiles) $(crypt_hdrfiles) libgtmcryptutil.so
+ @echo ; echo "Compiling $@..."
+ $(CC) $(CFLAGS) -DUSE_OPENSSL -DUSE_AES256CFB $(crypt_srcfiles) $(LDSHR) $(RPATHFLAGS) $(LDFLAGS) \
+ $@ -lcrypto -lgpgme -lgpg-error $(COMMON_LIBS)
+
+libgtmcrypt_openssl_BLOWFISHCFB.so: $(crypt_srcfiles) $(crypt_hdrfiles) libgtmcryptutil.so
+ @echo ; echo "Compiling $@..."
+ $(CC) $(CFLAGS) -DUSE_OPENSSL -DUSE_BLOWFISHCFB $(crypt_srcfiles) $(LDSHR) $(RPATHFLAGS) $(LDFLAGS) \
+ $@ -lcrypto -lgpgme -lgpg-error $(COMMON_LIBS)
+
+libgtmtls.so: $(tls_srcfiles) $(tls_hdrfiles) libgtmcryptutil.so
+ @echo ; echo "Compiling $@..."
+ $(CC) $(CFLAGS) $(tls_srcfiles) $(LDSHR) $(RPATHFLAGS) $(LDFLAGS) $@ -lssl $(COMMON_LIBS)
+
+install: all
+ @echo ; echo "Installing shared libraries to $(PLUGINDIR) and maskpass to $(PLUGINDIR)/gtmcrypt..."
+ cp -f *.so $(PLUGINDIR)
+ ln -fs ./$(install_targ) $(PLUGINDIR)/libgtmcrypt.so
+ifeq ($(NOT_IN_GTMCRYPTDIR),1)
+ cp -f maskpass $(PLUGINDIR)/gtmcrypt
+endif
uninstall:
+ @echo ; echo "Uninstalling shared libraries from $(PLUGINDIR) and maskpass from $(PLUGINDIR)/gtmcrypt..."
rm -f $(PLUGINDIR)/*.so
rm -f $(PLUGINDIR)/gtmcrypt/maskpass
clean:
- rm -f $(all_objfiles)
+ @echo ; echo "Removing generated files..."
rm -f *.so
+ifeq ($(NOT_IN_GTMCRYPTDIR),1)
rm -f maskpass
+endif
diff --git a/sr_port/md5_digest2hex.h b/sr_unix/arlinkdbg.h
similarity index 53%
copy from sr_port/md5_digest2hex.h
copy to sr_unix/arlinkdbg.h
index fe3322c..e820bd0 100644
--- a/sr_port/md5_digest2hex.h
+++ b/sr_unix/arlinkdbg.h
@@ -9,13 +9,20 @@
* *
****************************************************************/
-#ifndef MD5_DIGEST2HEX_INCLUDED
-#define MD5_DIGEST2HEX_INCLUDED
+/* Header file to control debugging for autorelink */
+#ifndef ARLINKDBG_H
+#define ARLINKDBG_H
-#include "md5hash.h"
+/* To enable debugging macros (output to console) uncomment the following #define */
+/*#define DEBUG_ARLINK*/
+#ifdef DEBUG_ARLINK
+# define DBGARLNK(x) DBGFPF(x)
+# define DBGARLNK_ONLY(x) x
+# include "gtm_stdio.h"
+# include "gtmio.h"
+#else
+# define DBGARLNK(x)
+# define DBGARLNK_ONLY(x)
+#endif
-#define MD5_HEXSTR_LENGTH 33
-
-void md5_digest2hex(char hexstr[MD5_HEXSTR_LENGTH], const unsigned char digest[MD5_DIGEST_LENGTH]);
-
-#endif /* MD5_DIGEST2HEX_INCLUDED */
+#endif
diff --git a/sr_unix/auto_zlink.c b/sr_unix/auto_zlink.c
index 9214738..d444b35 100644
--- a/sr_unix/auto_zlink.c
+++ b/sr_unix/auto_zlink.c
@@ -46,13 +46,6 @@ rhdtyp *auto_zlink(mach_inst *pc, lnr_tabent ***line)
rhdtyp *rhead;
urx_rtnref *rtnurx;
-# ifdef USHBIN_SUPPORTED
- /* With the current autorelink multi-opcode call (OP_RHD_EXT and OP_LAB_EXT prior to actual call), auto_zlink()
- * isn't really at all used but this is likely to change in the next release which streamlines some of this so
- * for now, this routine is not being nixed.
- */
- USHBIN_ONLY(assertpro(FALSE));
-# else
/* (ASSUMPTION)
* The instructions immediately preceding the current mpc form a transfer table call.
* There will be two arguments to this call:
@@ -90,28 +83,27 @@ rhdtyp *auto_zlink(mach_inst *pc, lnr_tabent ***line)
if (azl_geturxrtn((char *)A_rtnhdr, &rname, &rtnurx))
{
assert(rname.len <= MAX_MIDENT_LEN);
- assert(0 != rname.addr);
+ assert(NULL != rname.addr);
/* Copy rname into local storage because azl_geturxrtn sets rname.addr to an address that is
* free'd during op_zlink and before the call to find_rtn_hdr.
*/
memcpy(rname_buff.c, rname.addr, rname.len);
rname.addr = rname_buff.c;
- assert(0 != rtnurx);
+ assert(NULL != rtnurx);
assert(azl_geturxlab((char *)A_labaddr, rtnurx));
- assert(0 == find_rtn_hdr(&rname));
+ assert(NULL == find_rtn_hdr(&rname));
rtn.mvtype = MV_STR;
rtn.str.len = rname.len;
rtn.str.addr = rname.addr;
- op_zlink(&rtn, 0);
- if (0 != (rhead = find_rtn_hdr(&rname)))
+ op_zlink(&rtn, NULL);
+ if (NULL != (rhead = find_rtn_hdr(&rname)))
{ /* Pull the linkage table reference out and return it to caller */
*line = (lnr_tabent **)(A_labaddr->ext_ref);
- if (0 == *line)
+ if (NULL == *line)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_LABELUNKNOWN);
return rhead;
}
}
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ROUTINEUNKNOWN);
-# endif /* ifdef USHBIN_SUPPORTED */
return NULL; /* Compiler happiness phase */
}
diff --git a/sr_unix/bin_load.c b/sr_unix/bin_load.c
index ca1b9e4..9872d27 100644
--- a/sr_unix/bin_load.c
+++ b/sr_unix/bin_load.c
@@ -113,22 +113,22 @@ error_def(ERR_RECLOAD);
#define DEFAULT_SN_HOLD_BUFF_SIZE MAX_IO_BLOCK_SIZE
-#define KILL_INCMP_SN_IF_NEEDED(GVNH_REG) \
-{ \
- gd_region *dummy_reg; \
- \
- if (!sn_incmp_gbl_already_killed) \
- { \
- COPY_KEY(sn_savekey, gv_currkey); \
- COPY_KEY(gv_currkey, sn_gvkey); \
- /* The below macro finishes the task of GV_BIND_NAME_AND_ROOT_SEARCH \
- * (e.g. setting gv_cur_region for spanning globals). \
- */ \
- GV_BIND_SUBSNAME_IF_GVSPAN(GVNH_REG, gd_header, gv_currkey, dummy_reg); \
- bin_call_db(BIN_KILL, 0, 0); \
- COPY_KEY(gv_currkey, sn_savekey); \
- sn_incmp_gbl_already_killed = TRUE; \
- } \
+#define KILL_INCMP_SN_IF_NEEDED(GVNH_REG) \
+{ \
+ gd_region *dummy_reg; \
+ \
+ if (!sn_incmp_gbl_already_killed) \
+ { \
+ COPY_KEY(sn_savekey, gv_currkey); \
+ COPY_KEY(gv_currkey, sn_gvkey); \
+ /* The below macro finishes the task of GV_BIND_NAME_AND_ROOT_SEARCH \
+ * (e.g. setting gv_cur_region for spanning globals). \
+ */ \
+ GV_BIND_SUBSNAME_IF_GVSPAN(GVNH_REG, gd_header, gv_currkey, dummy_reg); \
+ bin_call_db(BIN_KILL, 0, 0); \
+ COPY_KEY(gv_currkey, sn_savekey); \
+ sn_incmp_gbl_already_killed = TRUE; \
+ } \
}
#define DISPLAY_INCMP_SN_MSG \
@@ -221,7 +221,7 @@ void zwr_out_print(char * buff, int bufflen)
FPRINTF(stderr,"\n");
}
-void bin_load(uint4 begin, uint4 end)
+void bin_load(uint4 begin, uint4 end, char *line1_ptr, int line1_len)
{
unsigned char *ptr, *cp1, *cp2, *btop, *gvkey_char_ptr, *tmp_ptr, *tmp_key_ptr, *c, *ctop, *ptr_base;
unsigned char hdr_lvl, src_buff[MAX_KEY_SZ + 1], dest_buff[MAX_ZWR_KEY_SZ],
@@ -231,9 +231,10 @@ void bin_load(uint4 begin, uint4 end)
int len;
int current, last, length, max_blk_siz, max_key, status;
int tmp_cmpc, sn_chunk_number, expected_sn_chunk_number = 0, sn_hold_buff_pos, sn_hold_buff_size;
- uint4 iter, max_data_len, max_subsc_len, key_count, gblsize;
- ssize_t rec_count, global_key_count, subsc_len,extr_std_null_coll, last_sn_error_offset=0,
- file_offset_base=0, file_offset=0;
+ uint4 max_data_len, max_subsc_len, gblsize;
+ ssize_t subsc_len, extr_std_null_coll;
+ gtm_uint64_t iter, key_count, rec_count, tmp_rec_count, global_key_count;
+ off_t last_sn_error_offset = 0, file_offset_base = 0, file_offset = 0;
boolean_t need_xlation, new_gvn, utf8_extract;
boolean_t is_hidden_subscript, ok_to_put = TRUE, putting_a_sn = FALSE, sn_incmp_gbl_already_killed = FALSE;
rec_hdr *rp, *next_rp;
@@ -260,6 +261,12 @@ void bin_load(uint4 begin, uint4 end)
assert(4 == SIZEOF(coll_hdr));
gvinit();
v.mvtype = MV_STR;
+ file_offset_base = 0;
+ /* line1_ptr,line1_len were initialized as part of get_file_format using reads of the binary extract file which
+ * did not go through file_input_bin_get. So initialize the internal static structures that file_input_bin_get
+ * maintains as if that read happened through it. This will let us finish reading the binary extract header line.
+ */
+ file_input_bin_init(line1_ptr, line1_len);
len = file_input_bin_get((char **)&ptr, &file_offset_base, (char **)&ptr_base, DO_RTS_ERROR_FALSE);
if (0 >= len)
{
@@ -329,8 +336,8 @@ void bin_load(uint4 begin, uint4 end)
# ifdef GTM_CRYPT
if ('7' <= hdr_lvl)
{
- encrypted_hash_array_len = file_input_bin_get((char **)&ptr, &file_offset_base, (char **)&ptr_base,
- DO_RTS_ERROR_TRUE);
+ encrypted_hash_array_len = file_input_bin_get((char **)&ptr, &file_offset_base,
+ (char **)&ptr_base, DO_RTS_ERROR_TRUE);
encrypted_hash_array_ptr = malloc(encrypted_hash_array_len);
memcpy(encrypted_hash_array_ptr, ptr, encrypted_hash_array_len);
n_index = encrypted_hash_array_len / GTMCRYPT_HASH_LEN;
@@ -368,7 +375,7 @@ void bin_load(uint4 begin, uint4 end)
if (!(len = file_input_bin_get((char **)&ptr, &file_offset_base, (char **)&ptr_base, DO_RTS_ERROR_TRUE)))
{
gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_LOADEOF, 1, begin);
- util_out_print("Error reading record number: !UL\n", TRUE, iter);
+ util_out_print("Error reading record number: !@UQ\n", TRUE, &iter);
mupip_error_occurred = TRUE;
return;
} else if (len == SIZEOF(coll_hdr))
@@ -383,6 +390,7 @@ void bin_load(uint4 begin, uint4 end)
max_data_len = 0;
max_subsc_len = 0;
global_key_count = key_count = 0;
+ GTM_WHITE_BOX_TEST(WBTEST_FAKE_BIG_KEY_COUNT, key_count, 4294967196U); /* (2**32)-100=4294967196 */
rec_count = begin - 1;
extr_collseq = db_collseq = NULL;
need_xlation = FALSE;
@@ -405,9 +413,10 @@ void bin_load(uint4 begin, uint4 end)
break;
if (mu_ctrlc_occurred)
{
- util_out_print("!AD:!_ Key cnt: !UL max subsc len: !UL max data len: !UL", TRUE,
- LEN_AND_LIT("LOAD TOTAL"), key_count, max_subsc_len, max_data_len);
- util_out_print("Last LOAD record number: !UL", TRUE, key_count ? (rec_count - 1) : 0);
+ util_out_print("!AD:!_ Key cnt: !@UQ max subsc len: !UL max data len: !UL", TRUE,
+ LEN_AND_LIT("LOAD TOTAL"), &key_count, max_subsc_len, max_data_len);
+ tmp_rec_count = key_count ? (rec_count - 1) : 0;
+ util_out_print("Last LOAD record number: !@UQ", TRUE, &tmp_rec_count);
mu_gvis();
util_out_print(0, TRUE);
mu_ctrlc_occurred = FALSE;
@@ -458,7 +467,7 @@ void bin_load(uint4 begin, uint4 end)
*/
if (mupip_error_occurred)
{
- gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_RECLOAD, 1, rec_count);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_RECLOAD, 1, &rec_count);
ONERROR_PROCESS;
}
max_key = gvnh_reg->gd_reg->max_key_size;
@@ -817,9 +826,10 @@ void bin_load(uint4 begin, uint4 end)
if (NULL != sn_hold_buff)
free(sn_hold_buff);
file_input_close();
- util_out_print("LOAD TOTAL!_!_Key Cnt: !UL Max Subsc Len: !UL Max Data Len: !UL", TRUE, key_count, max_subsc_len,
+ util_out_print("LOAD TOTAL!_!_Key Cnt: !@UQ 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 ? (rec_count - 1) : 0);
+ tmp_rec_count = key_count ? (rec_count - 1) : 0;
+ util_out_print("Last LOAD record number: !@UQ\n", TRUE, &tmp_rec_count);
if (mu_ctrly_occurred)
{
gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_LOADCTRLY);
diff --git a/sr_unix/buildaux.csh b/sr_unix/buildaux.csh
index 281ac7b..67ed94f 100644
--- a/sr_unix/buildaux.csh
+++ b/sr_unix/buildaux.csh
@@ -27,6 +27,7 @@ set buildaux_status = 0
set dollar_sign = \$
set mach_type = `uname -m`
set platform_name = `uname | sed 's/-//g' | tr '[A-Z]' '[a-z]'`
+set host=$HOST:r:r:r
if ( $1 == "" ) then
@ buildaux_status++
@@ -485,7 +486,7 @@ if ( $buildaux_ftok == 1 ) then
set aix_loadmap_option = "-bcalls:$gtm_map/ftok.loadmap -bmap:$gtm_map/ftok.loadmap -bxref:$gtm_map/ftok.loadmap"
endif
gt_ld $gt_ld_options $aix_loadmap_option ${gt_ld_option_output}$3/ftok -L$gtm_obj $gtm_obj/ftok.o \
- $gt_ld_sysrtns -lmumps $gt_ld_extra_libs $gt_ld_syslibs >& $gtm_map/ftok.map
+ $gt_ld_sysrtns -lmupip -lmumps -lstub $gt_ld_extra_libs $gt_ld_syslibs >& $gtm_map/ftok.map
if ( $status != 0 || ! -x $3/ftok ) then
@ buildaux_status++
echo "buildaux-E-linkftok, Failed to link ftok (see ${dollar_sign}gtm_map/ftok.map)" \
@@ -566,16 +567,6 @@ if ($buildaux_gtmcrypt == 1) then
else
set make = "make"
endif
- # libssl.so isn't available on pfloyd. Skip building SSL/TLS reference implementation library on pfloyd. This is
- # okay since pfloyd is AIX 5.3 which isn't a supported AIX version anyways.
- set host=$HOST:r:r:r
- if ($host !~ pfloyd) then
- $make gtmtls image=$plugin_build_type
- if ($status) then
- @ buildaux_status++
- echo "buildaux-E-tls, failed to build libgtmtls.so." >> $gtm_log/error.${gtm_exe:t}.log
- endif
- endif
# On tuatara, atlhxit1 and atlhxit2 Libgcrypt version is too low to support FIPS mode. Add necessary flags to
# Makefile to tell the plugin to build without FIPS support.
if ($host =~ {tuatara,atlhxit1,atlhxit2}) then
@@ -583,27 +574,6 @@ if ($buildaux_gtmcrypt == 1) then
else
set fips_flag = ""
endif
- # Build all possible encryption libraries based on what encryption libraries are supported in this platform.
- foreach supported_lib ($supported_list)
- foreach algorithm ("AES256CFB" "BLOWFISHCFB")
- if ("gcrypt" == "$supported_lib" && "BLOWFISHCFB" == "$algorithm") continue
- echo "####### Building encryption plugin using $supported_lib with $algorithm algorithm #########"
- $make gtmcrypt image=$plugin_build_type thirdparty=$supported_lib algo=$algorithm $fips_flag
- if ($status) then
- @ buildaux_status++
- echo "buildaux-E-libgtmcrypt, failed to build gtmcrypt and/or helper scripts." \
- >> $gtm_log/error.${gtm_exe:t}.log
- endif
- echo ""
- end
- end
- # Now that the individual libraries are built, go ahead and build the maskpass
- $make maskpass
- if ($status) then
- @ buildaux_status++
- echo "buildaux-E-maskpass, failed to build maskpass." >> $gtm_log/error.${gtm_exe:t}.log
- endif
- #
if ($gtm_verno =~ V[4-8]*) then
# For production builds don't do any randomizations.
set algorithm = "AES256CFB"
@@ -613,32 +583,39 @@ if ($buildaux_gtmcrypt == 1) then
set encryption_lib = "gcrypt"
endif
else
- # Now that we've built "possibly" more than one encryption library, choose one configuration (based on
- # third-party library and algorithm) randomly and install that.
+ # Randomly choose one configuration based on third-party library and algorithm.
set rand = `echo $#supported_list | awk '{srand() ; print 1+int(rand()*$1)}'`
set encryption_lib = $supported_list[$rand]
if ("gcrypt" == "$encryption_lib") then
# Force AES as long as the plugin is linked against libgcrypt
set algorithm = "AES256CFB"
else
- # OpenSSL, V9* build. Go ahead and randomize the algorithm
- # increase probability of AES256CFB, the industry standard and the one we officially support
+ # OpenSSL, V9* build. Go ahead and randomize the algorithm. Increase the probability of AES256CFB,
+ # the industry standard and the one we officially support.
set algorithms = ("AES256CFB" "AES256CFB" "BLOWFISHCFB")
set rand = `echo $#algorithms | awk '{srand() ; print 1+int(rand()*$1)}'`
set algorithm = $algorithms[$rand]
endif
endif
- $make install thirdparty=$encryption_lib algo=$algorithm
+ # Build and install all encryption libraries and executables.
+ $make install algo=$algorithm image=$plugin_build_type thirdparty=$encryption_lib $fips_flag
+ if ($status) then
+ @ buildaux_status++
+ echo "buildaux-E-libgtmcrypt, failed to install libgtmcrypt and/or helper scripts" \
+ >> $gtm_log/error.${gtm_exe:t}.log
+ endif
+ # Remove temporary files.
+ $make clean
if ($status) then
@ buildaux_status++
- echo "buildaux-E-libgtmcrypt, failed to install libgtmcrypt and/or helper scripts" \
+ echo "buildaux-E-libgtmcrypt, failed to clean libgtmcrypt and/or helper scripts" \
>> $gtm_log/error.${gtm_exe:t}.log
endif
# Create the one time gpgagent.tab file.
echo "$gtm_dist_plugin/libgtmcryptutil.so" >&! $gtm_dist_plugin/gpgagent.tab
echo "unmaskpwd: gtm_status_t gc_mask_unmask_passwd(I:gtm_string_t*,O:gtm_string_t*[512])" \
- >>&! $gtm_dist_plugin/gpgagent.tab
- #
+ >>&! $gtm_dist_plugin/gpgagent.tab
+
popd >&! /dev/null
endif
endif
diff --git a/sr_unix/callintogtmxfer.c b/sr_unix/callintogtmxfer.c
index ea620a2..5af0b8c 100644
--- a/sr_unix/callintogtmxfer.c
+++ b/sr_unix/callintogtmxfer.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -18,6 +18,7 @@
#include "callintogtmxfer.h"
#include "gt_timer.h"
+#include "have_crit.h"
typedef int (*int_fptr)();
@@ -51,7 +52,7 @@ void init_callin_functable(void)
{
unsigned char *env_top, *address_top;
uint4 address_len;
- int save_errno;
+ int save_errno, status;
address_top = GTM64_ONLY(i2ascl)NON_GTM64_ONLY(i2asc)(gtmvectortable_address, (UINTPTR_T)(&callintogtm_vectortable[0]));
*address_top = '\0';
@@ -60,9 +61,10 @@ void init_callin_functable(void)
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))
+ PUTENV(status, (char *)gtmvectortable_env);
+ if (status)
{
save_errno = errno;
- rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("putenv"), CALLFROM, save_errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("putenv"), CALLFROM, save_errno);
}
}
diff --git a/sr_unix/ce_substitute.c b/sr_unix/ce_substitute.c
index 3f7f8f6..6f098e7 100644
--- a/sr_unix/ce_substitute.c
+++ b/sr_unix/ce_substitute.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -14,7 +14,7 @@
#include "comp_esc.h"
GBLREF unsigned char *source_buffer;
-GBLREF short int source_column;
+GBLREF int source_column;
GBLREF char *lexical_ptr;
GBLREF struct ce_sentinel_desc *ce_def_list;
diff --git a/sr_unix/cli.h b/sr_unix/cli.h
index a488100..313e8dd 100644
--- a/sr_unix/cli.h
+++ b/sr_unix/cli.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -17,7 +17,7 @@
* Parser include file
* -----------------------------------------------------------
*/
-#define MAX_PARMS 5 /* Maximum parameters on commands line */
+#define MAX_PARMS 1024 /* Maximum parameters on command line */
#define MAX_CMD_LEN 25 /* Max Command name string length */
#define MAX_OPT_LEN 25 /* Max Option name string length */
@@ -90,7 +90,7 @@ typedef struct cmd_parm_tag {
0 - disallowed,
1 - optional
2 - required */
- unsigned max_parms : 3; /* Max. # of parameters allowed */
+ unsigned short max_parms; /* Max. # of parameters allowed */
unsigned negatable : 1; /* Negatable flag */
unsigned val_type : 2; /* Value Type
VAL_N_A - type not applicable
diff --git a/sr_unix/cli_parse.c b/sr_unix/cli_parse.c
index 62d677c..091c935 100644
--- a/sr_unix/cli_parse.c
+++ b/sr_unix/cli_parse.c
@@ -298,7 +298,7 @@ int parse_arg(CLI_ENTRY *pcmd_parms, int *eof)
cli_get_string_token(eof);
if (TREF(parms_cnt) >= gpcmd_verb->max_parms)
{
- SNPRINTF(cli_err_str, MAX_CLI_ERR_STR, "Too many parameters ");
+ SNPRINTF(cli_err_str, MAX_CLI_ERR_STR, "Too many parameters");
return (-1);
}
TAREF1(parm_str_len, TREF(parms_cnt)) = strlen(cli_token_buf) + 1;
diff --git a/sr_unix/comlist.csh b/sr_unix/comlist.csh
index 3d4a0a7..9b1138a 100644
--- a/sr_unix/comlist.csh
+++ b/sr_unix/comlist.csh
@@ -326,16 +326,6 @@ if ( "$HOSTOS" == "OS/390disable" ) then
cp $gtm_inc/gtm_stat.h .
endif
-
-if ( "$HOSTOS" == "SunOS" ) then
- # Support for RPC implementation of DAL's and ZCALL's.
- # gtm_descript.h is already copied.
- cp $gtm_inc/gtmidef.h .
-endif
-
-cp $gtm_pct/*.hlp .
-
-
# If this is a test version not being built in $gtm_exe
# (see value of $3), then make sure ./obj and ./map exist.
if ( ! -d ./obj ) then
@@ -654,16 +644,16 @@ rm -f obj/gengtmdeftypes.log* >& /dev/null
rm -f GTMDefinedTypesInit.m >& /dev/null
echo "Generating GTMDefinedTypesInit.m"
if ($?work_dir) then
- if (-e $work_dir/tools/cms_tools/gengtmdeftypes.csh) then
+ if (-e $work_dir/tools/cms_tools/builddefinedtypes/gengtmdeftypes.csh) then
echo "Using gengtmdeftypes.csh from $work_dir"
- $work_dir/tools/cms_tools/gengtmdeftypes.csh >& obj/gengtmdeftypes.log
+ $work_dir/tools/cms_tools/builddefinedtypes/gengtmdeftypes.csh >& obj/gengtmdeftypes.log
@ savestatus = $status
else
- $cms_tools/gengtmdeftypes.csh >& obj/gengtmdeftypes.log
+ $cms_tools/builddefinedtypes/gengtmdeftypes.csh >& obj/gengtmdeftypes.log
@ savestatus = $status
endif
else
- $cms_tools/gengtmdeftypes.csh >& obj/gengtmdeftypes.log
+ $cms_tools/builddefinedtypes/gengtmdeftypes.csh >& obj/gengtmdeftypes.log
@ savestatus = $status
endif
if ((0 != $savestatus) || (! -e GTMDefinedTypesInit.m)) then
@@ -739,32 +729,11 @@ if ($status) then
endif
# Create the GT.M/GDE/MUPIP/DSE/LKE help databases
-foreach hlp (*.hlp)
- set hlp_status = 0
- set prefix=${hlp:r}
- if ("${prefix}" == "mumps") set prefix="gtm"
- setenv gtmgbldir $gtm_dist/${prefix}help.gld
- gde <<GDE_in_help
-Change -segment DEFAULT -block=2048 -file=\$gtm_dist/${prefix}help.dat
-Change -region DEFAULT -record=1020 -key=255
-GDE_in_help
-
- if ($status) @ hlp_status++
- mupip create
- if ($status) @ hlp_status++
- gtm <<GTM_in_gtmhelp
-Do ^GTMHLPLD
-$gtm_dist/${hlp}
-Halt
-GTM_in_gtmhelp
-
- if ($status) @ hlp_status++
- if ($hlp_status) then
- @ comlist_status = $comlist_status + $hlp_status
- echo "comlist-E-hlp, Error processing $hlp file" >> $errorlog
- endif
-
-end
+$gtm_tools/generate_help.csh $gtm_pct $errorlog
+if ($status) then
+ @ comlist_status++
+ echo "comlist-E-hlp, Error generating hlp databases" >> $errorlog
+endif
chmod 775 * # do not check $status here because we know it will be 1 since "gtmsecshr" permissions cannot be changed.
diff --git a/sr_unix/comp_lits.c b/sr_unix/comp_lits.c
index 3f7b89b..23b8a8d 100644
--- a/sr_unix/comp_lits.c
+++ b/sr_unix/comp_lits.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -14,6 +14,7 @@
#include <rtnhdr.h>
#include "mdq.h"
#include "stringpool.h"
+#include "obj_file.h"
GBLREF mliteral literal_chain;
GBLREF spdesc stringpool;
@@ -24,14 +25,18 @@ GBLDEF uint4 lits_text_size, lits_mval_size;
void comp_lits(rhdtyp *rhead)
{
- size_t offset;
- uint4 cnt;
- uint4 align_pad;
- mliteral *p;
+ size_t offset;
+ uint4 cnt;
+ uint4 align_pad;
+ mliteral *p;
+ struct linkage_entry *linkagep;
+ DCL_THREADGBL_ACCESS;
+ SETUP_THREADGBL_ACCESS;
/* Literal text pool is formed in stringpool except for the file name/path of the
* source module and routine name which will be emitted by emit_literals immediately
- * following the literal text pool and is considered part of that text pool.*/
+ * following the literal text pool and is considered part of that text pool.
+ */
offset = (stringpool.free - stringpool.base);
offset += PADLEN(offset, NATIVE_WSIZE);
rhead->src_full_name.len = source_name_len;
@@ -42,6 +47,12 @@ void comp_lits(rhdtyp *rhead)
rhead->routine_name.addr = (char *)offset;
offset += routine_name.len;
offset += PADLEN(offset, NATIVE_WSIZE);
+ for (linkagep = TREF(linkage_first); NULL != linkagep; linkagep = linkagep->next)
+ { /* Compute space for linkage name usage (symbol names associated with each linkage symbol) */
+ linkagep->lit_offset = offset;
+ offset += linkagep->symbol->name_len - 1;
+ offset += PADLEN(offset, NATIVE_WSIZE);
+ }
lits_text_size = UINTCAST(offset);
offset = 0;
dqloop(&literal_chain, que, p)
diff --git a/sr_unix/dbcertify_signal_handler.c b/sr_unix/dbcertify_signal_handler.c
index d28368d..c0de6ef 100644
--- a/sr_unix/dbcertify_signal_handler.c
+++ b/sr_unix/dbcertify_signal_handler.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2005, 2013 Fidelity Information Services, Inc *
+ * Copyright 2005, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -78,9 +78,9 @@ error_def(ERR_KRNLKILL);
void dbcertify_signal_handler(int sig, siginfo_t *info, void *context)
{
- boolean_t exit_now;
+ boolean_t dbc_critical, exit_now;
gtm_sigcontext_t *context_ptr;
- void (*signal_routine)();
+ void (*signal_routine)();
/* Save parameter value in global variables for easy access in core */
dont_want_core = FALSE; /* (re)set in case we recurse */
@@ -119,11 +119,12 @@ void dbcertify_signal_handler(int sig, siginfo_t *info, void *context)
}
++core_in_progress;
DUMP_CORE;
- GTMASSERT;
+ assertpro(FALSE);
default:
;
}
}
+ dbc_critical = ((NULL != psa_gbl) && psa_gbl->dbc_critical);
switch(sig)
{
case SIGINT:
@@ -132,7 +133,7 @@ void dbcertify_signal_handler(int sig, siginfo_t *info, void *context)
/* If nothing pending AND we have crit or already in exit processing, wait to
* invoke shutdown.
*/
- if ((EXIT_PENDING_TOLERANT >= exit_state) && (psa_gbl->dbc_critical || exit_handler_active))
+ if ((EXIT_PENDING_TOLERANT >= exit_state) && (dbc_critical || exit_handler_active))
{
SET_FORCED_EXIT_STATE;
exit_state++; /* Make exit pending, may still be tolerant though */
@@ -165,10 +166,10 @@ void dbcertify_signal_handler(int sig, siginfo_t *info, void *context)
break;
default:
exit_state = EXIT_IMMED;
- GTMASSERT;
+ assertpro(FALSE);
}
/* If nothing pending AND we have crit or already in exit processing, wait to invoke shutdown */
- if ((EXIT_PENDING_TOLERANT >= exit_state) && (psa_gbl->dbc_critical || exit_handler_active))
+ if ((EXIT_PENDING_TOLERANT >= exit_state) && (dbc_critical || exit_handler_active))
{
SET_FORCED_EXIT_STATE;
exit_state++; /* Make exit pending, may still be tolerant though */
@@ -215,7 +216,7 @@ void dbcertify_signal_handler(int sig, siginfo_t *info, void *context)
case SIGDANGER:
forced_exit_err = ERR_KRNLKILL;
/* If nothing pending AND we have crit or already in exit processing, wait to invoke shutdown */
- if ((EXIT_PENDING_TOLERANT >= exit_state) && (psa_gbl->dbc_critical || exit_handler_active))
+ if ((EXIT_PENDING_TOLERANT >= exit_state) && (dbc_critical || exit_handler_active))
{
SET_FORCED_EXIT_STATE;
exit_state++; /* Make exit pending, may still be tolerant though */
@@ -242,7 +243,7 @@ void dbcertify_signal_handler(int sig, siginfo_t *info, void *context)
/* This signal was SENT to us so it can wait until we are out of crit to cause an exit */
forced_exit_err = ERR_KILLBYSIGUINFO;
/* If nothing pending AND we have crit or already exiting, wait to invoke shutdown */
- if ((EXIT_PENDING_TOLERANT >= exit_state) && (psa_gbl->dbc_critical || exit_handler_active))
+ if ((EXIT_PENDING_TOLERANT >= exit_state) && (dbc_critical || exit_handler_active))
{
SET_FORCED_EXIT_STATE;
exit_state++; /* Make exit pending, may still be tolerant though */
@@ -281,7 +282,7 @@ void dbcertify_signal_handler(int sig, siginfo_t *info, void *context)
break;
default:
exit_state = EXIT_IMMED;
- GTMASSERT;
+ assertpro(FALSE);
}
if (0 != signal_info.sig_err)
{
@@ -297,7 +298,7 @@ void dbcertify_signal_handler(int sig, siginfo_t *info, void *context)
gtm_fork_n_core();
}
/* As on VMS, a mupip stop does not drive the condition handlers unless we are in crit */
- if ((psa_gbl->dbc_critical || SIGTERM != exi_condition) && CHANDLER_EXISTS)
+ if ((dbc_critical || (SIGTERM != exi_condition)) && CHANDLER_EXISTS)
DRIVECH(exi_condition);
assert((EXIT_IMMED <= exit_state) || !exit_handler_active);
diff --git a/sr_unix/do_shmat.c b/sr_unix/do_shmat.c
index f74a1f5..a0fbc44 100644
--- a/sr_unix/do_shmat.c
+++ b/sr_unix/do_shmat.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2004 Sanchez Computer Associates, Inc. *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -17,6 +17,9 @@
#include "mdef.h"
#include <sys/shm.h>
+#include <sys/mman.h>
+#include <errno.h>
+
#ifndef __MVS__
#include <sys/sysmacros.h>
#endif
@@ -25,14 +28,44 @@
#include "do_shmat.h"
-GBLREF int4 gtm_shmflags; /* Flags to OR into supplied flags */
-
-void *do_shmat(int4 shmid, const void *shmaddr, int4 shmflg)
+void *do_shmat(int4 shmid, const void *shm_base, int4 shmflg)
{
-#ifdef __sparc
- return(shmat((int)shmid, shmaddr, shmflg | gtm_shmflags | SHM_SHARE_MMU));
-#else
- return(shmat((int)shmid, shmaddr, shmflg | gtm_shmflags));
-#endif
+# ifdef __sparc
+ return(shmat((int)shmid, shm_base, shmflg | SHM_SHARE_MMU));
+# else
+ return(shmat((int)shmid, shm_base, shmflg));
+# endif
}
+/* This is do_shmat + capability to execute code from shared memory.
+ * Currently (Oct 2014), only newer Linuxes supports SHM_EXEC bit. Other platforms dont seem to have this option.
+ * So we use mprotect (additional system call) there to implement this requirement.
+ * Until SHM_EXEC is not available on all POSIX platforms that GT.M is built/supported on, we need the mprotect code.
+ */
+void *do_shmat_exec_perm(int4 shmid, size_t shm_size, int *save_errno)
+{
+ int4 shmflg;
+ void *addr;
+
+# if defined(SHM_EXEC)
+ shmflg = SHM_EXEC;
+# else
+ shmflg = 0;
+# endif
+ addr = do_shmat(shmid, NULL, shmflg);
+ if (-1 == (sm_long_t)addr)
+ {
+ *save_errno = errno;
+ return addr;
+ }
+# if !defined(SHM_EXEC)
+ if (-1 == mprotect(addr, shm_size, PROT_READ | PROT_WRITE | PROT_EXEC))
+ {
+ *save_errno = errno;
+ assert(FALSE);
+ SHMDT(addr);
+ addr = (void *)-1;
+ }
+# endif
+ return addr;
+}
diff --git a/sr_unix/do_shmat.h b/sr_unix/do_shmat.h
index c4143a7..f7da458 100644
--- a/sr_unix/do_shmat.h
+++ b/sr_unix/do_shmat.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -12,6 +12,7 @@
#ifndef __DO_SHMAT_H__
#define __DO_SHMAT_H__
-void *do_shmat(int4 shmid, const void *shmaddr, int4 shmflg);
+void *do_shmat(int4 shmid, const void *shm_base, int4 shmflg);
+void *do_shmat_exec_perm(int4 shmid, size_t shm_size, int *save_errno);
#endif
diff --git a/sr_unix/dollarh.c b/sr_unix/dollarh.c
index 3a010d8..d406b30 100644
--- a/sr_unix/dollarh.c
+++ b/sr_unix/dollarh.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -20,7 +20,7 @@
void dollarh(time_t intime, uint4 *days, time_t *seconds)
{
- uint4 tdays;
+ int4 tdays;
int isdst;
struct tm *ttime;
time_t mktime_ret;
@@ -40,22 +40,17 @@ void dollarh(time_t intime, uint4 *days, time_t *seconds)
* is to block signals (SIGINT, SIGQUIT, SIGTERM, SIGTSTP, SIGCONT, SIGALRM) during the function and then restore them
* at the end. [C9D06-002271] [C9I03-002967].
*/
- GTM_LOCALTIME(ttime, &intime); /* represent intime as local time in case of offsets from UCT other than hourly */
+ GTM_LOCALTIME(ttime, &intime); /* represent intime as local time in case of offsets from UTC other than hourly */
*seconds = (time_t)(ttime->tm_hour * HOUR) + (ttime->tm_min * MINUTE) + ttime->tm_sec;
isdst = ttime->tm_isdst;
- GTM_GMTIME(ttime, &intime); /* represent intime as UCT */
+ GTM_GMTIME(ttime, &intime); /* represent intime as UTC */
ttime->tm_isdst = isdst; /* use GTM_LOCALTIME to tell mktime whether daylight savings needs to be applied */
GTM_MKTIME(mktime_ret, ttime);
assert((time_t)-1 != mktime_ret);
- tdays = (uint4)((intime + (time_t)difftime(intime, mktime_ret)) / ONEDAY) + DAYS; /* adjust relative to UTC */
- *days = tdays; /* use temp local in case the caller has overlapped arguments */
- /* Assert that $H always moves forward. The only exception is a negative time adjustment due to DST change.
- * Do asserts AFTER unblocking signals as otherwise assert failures could hang and/or result in no cores.
- * DSE and MUPIP use this function to potentially display times in the past (e.g. in DSE DUMP -FILE,
- * MUPIP JOURNAL EXTRACT) so restrict this assert to the runtime for now.
- */
- assert(!IS_GTM_IMAGE || ((*days == old_days) && (*seconds >= old_seconds)) || (*days > old_days)
- || (0 < old_isdst) && (0 == isdst));
+ /* adjust relative to UTC - have to round the other way if intime is less than or equal to the UTC offset */
+ tdays = (int4)(intime - mktime_ret);
+ tdays = (int4)(((intime + tdays - (((intime + tdays) > 0) ? 0 : (ONEDAY - 1))) / ONEDAY) + DAYS);
+ *days = (uint4)tdays; /* use temp local in case the caller has overlapped arguments */
DEBUG_ONLY(old_seconds = (uint4)*seconds; old_days = *days; old_intime = intime; old_isdst = isdst;)
return;
}
diff --git a/sr_unix/dsk_read.c b/sr_unix/dsk_read.c
index 13f40e2..33991ca 100644
--- a/sr_unix/dsk_read.c
+++ b/sr_unix/dsk_read.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -220,13 +220,14 @@ int4 dsk_read (block_id blk, sm_uc_ptr_t buff, enum db_ver *ondsk_blkver, boolea
/* Expect t_tries to be 3 if we have crit. Exceptions: gvcst_redo_root_search (where t_tries is temporarily reset
* for the duration of the redo_root_search and so we should look at the real t_tries in redo_rootsrch_ctxt),
* gvcst_expand_free_subtree, REORG UPGRADE/DOWNGRADE, DSE (where we grab crit before doing the t_qread irrespective
- * of t_tries), forward recovery (where we grab crit before doing everything)
+ * of t_tries), forward recovery (where we grab crit before doing everything) OR MUPIP TRIGGER -UPGRADE (where we
+ * grab crit before doing the entire ^#t upgrade TP transaction).
*/
effective_t_tries = UNIX_ONLY( (TREF(in_gvcst_redo_root_search)) ? (TREF(redo_rootsrch_ctxt)).t_tries : ) t_tries;
effective_t_tries = MAX(effective_t_tries, t_tries);
killinprog = (NULL != ((dollar_tlevel) ? sgm_info_ptr->kip_csa : kip_csa));
assert(dse_running || killinprog || jgbl.forw_phase_recovery || mu_reorg_upgrd_dwngrd_in_prog
- || (cs_addrs->now_crit != (CDB_STAGNATE > effective_t_tries)));
+ GTMTRIG_ONLY(|| TREF(in_trigger_upgrade)) || (cs_addrs->now_crit != (CDB_STAGNATE > effective_t_tries)));
if (!blk_free && cs_addrs->now_crit && !dse_running && (0 == save_errno))
{ /* Do basic checks on GDS block that was just read. Do it only if holding crit as we could read
* uninitialized blocks otherwise. Also DSE might read bad blocks even inside crit so skip checks.
diff --git a/sr_unix/errorsp.h b/sr_unix/errorsp.h
index 8a36998..8cf6f1c 100644
--- a/sr_unix/errorsp.h
+++ b/sr_unix/errorsp.h
@@ -466,4 +466,6 @@ CONDITION_HANDLER(gvcst_spr_queryget_ch);
CONDITION_HANDLER(op_fnzpeek_ch);
CONDITION_HANDLER(op_fnzpeek_getpool_ch);
+CONDITION_HANDLER(trigger_upgrade_ch);
+
#endif
diff --git a/sr_port/lastchance3.c b/sr_unix/exi_ch.c
similarity index 62%
copy from sr_port/lastchance3.c
copy to sr_unix/exi_ch.c
index 991e2cd..3b9493b 100644
--- a/sr_port/lastchance3.c
+++ b/sr_unix/exi_ch.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -10,40 +10,28 @@
****************************************************************/
#include "mdef.h"
-#include "gtm_unistd.h"
#include "error.h"
-#include "io.h"
#include "util.h"
GBLREF int4 exi_condition;
GBLREF boolean_t created_core;
GBLREF boolean_t dont_want_core;
+DEBUG_ONLY(GBLREF boolean_t ok_to_UNWIND_in_exit_handling;)
-error_def(ERR_ASSERT);
-error_def(ERR_FORCEDHALT);
-error_def(ERR_GTMASSERT);
-error_def(ERR_GTMASSERT2);
-error_def(ERR_GTMCHECK);
-error_def(ERR_IORUNDOWN);
-error_def(ERR_MEMORY);
-error_def(ERR_OUTOFSPACE);
-error_def(ERR_STACKOFLOW);
-error_def(ERR_VMSMEMORY);
-
-CONDITION_HANDLER(lastchance3)
+CONDITION_HANDLER(exi_ch)
{
-
START_CH(TRUE);
ESTABLISH(terminate_ch);
+ exi_condition = SIGNAL;
if (DUMPABLE)
{
PRN_ERROR;
- dec_err(VARLSTCNT(1) ERR_IORUNDOWN);
if (!SUPPRESS_DUMP)
DUMP_CORE;
PROCDIE(exi_condition);
}
REVERT;
+ DEBUG_ONLY(ok_to_UNWIND_in_exit_handling = TRUE);
UNWIND(NULL, NULL);
}
diff --git a/sr_unix/file_input.c b/sr_unix/file_input.c
index 2af5488..f9df5d9 100644
--- a/sr_unix/file_input.c
+++ b/sr_unix/file_input.c
@@ -42,10 +42,24 @@ error_def(ERR_PREMATEOF);
static char buff1[BUFF_SIZE];
static char *buff1_end;
static char *buff1_ptr;
-static ssize_t buff1_ptr_file_offset;
+static off_t buff1_ptr_file_offset;
static char *load_fn_ptr;
static int load_fn_len;
-static readonly unsigned char open_params_list[] =
+static unsigned char open_params_list_default[] =
+{
+ (unsigned char)iop_recordsize, /* 64K enough to hold MAX_BLK_SZ */
+# ifdef BIGENDIAN
+ (unsigned char)0, (unsigned char)0, (unsigned char)255, (unsigned char)255,
+# else
+ (unsigned char)255, (unsigned char)255, (unsigned char)0, (unsigned char)0,
+# endif
+ (unsigned char)iop_readonly,
+ (unsigned char)iop_m,
+ /* iop_stream not included since it is necessary only if we are opening file for write (which is not the case here) */
+ (unsigned char)iop_nowrap,
+ (unsigned char)iop_eol
+};
+static unsigned char open_params_list_rewind[] =
{
(unsigned char)iop_recordsize, /* 64K enough to hold MAX_BLK_SZ */
# ifdef BIGENDIAN
@@ -61,16 +75,23 @@ static readonly unsigned char open_params_list[] =
(unsigned char)iop_eol
};
-void file_input_init(char *fn, short fn_len)
+void file_input_init(char *fn, short fn_len, open_params_flags params_flag)
{
int status;
mval pars, val;
unsigned char no_param = (unsigned char)iop_eol;
+ unsigned char* open_params;
ESTABLISH(mupip_load_ch);
pars.mvtype = MV_STR;
- pars.str.len = SIZEOF(open_params_list);
- pars.str.addr = (char *)open_params_list;
+ if (params_flag & IOP_REWIND)
+ {
+ pars.str.len = SIZEOF(open_params_list_rewind);
+ pars.str.addr = (char *)open_params_list_rewind;
+ } else { /* IOP_EOL */
+ pars.str.len = SIZEOF(open_params_list_default);
+ pars.str.addr = (char *)open_params_list_default;
+ }
val.mvtype = MV_STR;
val.str.len = fn_len;
val.str.addr = (char *)fn;
@@ -103,7 +124,17 @@ void file_input_close(void)
op_close(&val, &pars);
}
-int file_input_bin_get(char **in_ptr, ssize_t *file_offset, char **buff_base, boolean_t do_rts_error)
+void file_input_bin_init(char *line1_ptr, int line1_len)
+{
+ assert(buff1_ptr == buff1);
+ assert(line1_len < BUFF_SIZE);
+ assert(buff1_end == buff1_ptr);
+ assert(0 == buff1_ptr_file_offset);
+ memcpy(buff1_ptr, line1_ptr, line1_len);
+ buff1_end += line1_len;
+}
+
+int file_input_bin_get(char **in_ptr, off_t *file_offset, char **buff_base, boolean_t do_rts_error)
{
char *ptr;
int rd_cnt, rd_len, ret, s1;
@@ -120,8 +151,7 @@ int file_input_bin_get(char **in_ptr, ssize_t *file_offset, char **buff_base, bo
if (do_rts_error)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_PREMATEOF);
ret = ERR_PREMATEOF;
- }
- else if (-1 == rd_len)
+ } else if (-1 == rd_len)
{
if (do_rts_error)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_LOADFILERR, 2, load_fn_len, load_fn_ptr);
@@ -192,14 +222,44 @@ int file_input_bin_read(void)
return rdlen;
}
-int file_input_get(char **in_ptr)
+int file_input_get_xchar(char *in_ptr, int max_chars_to_read) /* uses opreadfl with a buffered getc call to read file content */
{
- char *ptr, *tmp_ptr;
- int rd_len, s1;
- mval val;
- static unsigned int mbuff_len = BUFF_SIZE;
- unsigned int new_mbuff_len, ret_len;
- static char *mbuff = buff1;
+ int rd_len;
+ mval val;
+
+ op_readfl(&val, max_chars_to_read, dollar_tlevel ? 0: NO_M_TIMEOUT);
+ rd_len = val.str.len;
+ if ((0 == rd_len) && io_curr_device.in->dollar.zeof)
+ return -1;
+ memcpy(in_ptr, val.str.addr, rd_len);
+ return rd_len;
+}
+
+int file_input_read_xchar(char *in_ptr, int max_chars_to_read) /* uses DOREADRL with read system api to read file content */
+{
+ int rd_len;
+ io_desc *iod;
+ d_rm_struct *d_rm;
+
+ iod = io_curr_device.in;
+ d_rm = (d_rm_struct *)iod->dev_sp;
+ assert(NULL != d_rm);
+ DOREADRL(d_rm->fildes, in_ptr, max_chars_to_read, rd_len);
+ return rd_len;
+}
+
+/* Returns
+ * -1 (FILE_INPUT_GET_ERROR) in case of errors,
+ * -2 (FILE_INPUT_GET_LINE2LONG) in case line length of read becomes > input max_len (assuming max_len is non-zero)
+ */
+int file_input_get(char **in_ptr, int max_len)
+{
+ char *ptr, *tmp_ptr;
+ int rd_len, s1;
+ mval val;
+ static char *mbuff = buff1;
+ static unsigned int mbuff_len = BUFF_SIZE;
+ unsigned int new_mbuff_len, ret_len;
ESTABLISH_RET(mupip_load_ch, 0);
ret_len = 0;
@@ -212,28 +272,29 @@ int file_input_get(char **in_ptr)
REVERT;
if (io_curr_device.in->dollar.x)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_PREMATEOF);
- return -1;
+ return FILE_INPUT_GET_ERROR;
}
- if (mbuff_len < ret_len + rd_len)
+ if (max_len && ((ret_len + rd_len) > max_len))
+ {
+ REVERT;
+ return FILE_INPUT_GET_LINE2LONG;
+ }
+ if (mbuff_len < (ret_len + rd_len))
{
new_mbuff_len = MAX((ret_len + rd_len), (2 * mbuff_len));
tmp_ptr = (char *)malloc(new_mbuff_len);
if (NULL == tmp_ptr)
{
REVERT;
- return -1;
+ return FILE_INPUT_GET_ERROR;
}
- if (mbuff != buff1)
- {
- memcpy(tmp_ptr, mbuff, (ret_len));
- free (mbuff);
- } else
- memcpy(tmp_ptr, buff1, (ret_len));
+ memcpy(tmp_ptr, mbuff, ret_len);
+ if (mbuff != buff1) /* do not free static array, free all later expansions (malloc buffers) */
+ free(mbuff);
mbuff = tmp_ptr;
mbuff_len = new_mbuff_len;
-
}
- memcpy((unsigned char *) (mbuff + ret_len), val.str.addr, rd_len);
+ memcpy((unsigned char *)(mbuff + ret_len), val.str.addr, rd_len);
ret_len += rd_len;
if ( !(io_curr_device.in->dollar.x) )
{
diff --git a/sr_unix/file_input.h b/sr_unix/file_input.h
index c8558ab..a8f1b40 100644
--- a/sr_unix/file_input.h
+++ b/sr_unix/file_input.h
@@ -12,13 +12,22 @@
#ifndef __FILE_INPUT_INPUT_H__
#define __FILE_INPUT_INPUT_H__
-void file_input_init(char *fn, short fn_len);
+#define FILE_INPUT_GET_ERROR -1
+#define FILE_INPUT_GET_LINE2LONG -2
+#define DO_RTS_ERROR_TRUE TRUE
+#define DO_RTS_ERROR_FALSE FALSE
+
+typedef enum {
+ IOP_EOL = 0x00,
+ IOP_REWIND = 0x01
+} open_params_flags;
+void file_input_init(char *fn, short fn_len, open_params_flags params_flag);
void file_input_close(void);
-int file_input_bin_get(char **in_ptr, ssize_t *file_offset, char **buff_base, boolean_t do_rts_error);
+void file_input_bin_init(char *line1_ptr, int line1_len);
+int file_input_bin_get(char **in_ptr, off_t *file_offset, char **buff_base, boolean_t do_rts_error);
int file_input_bin_read(void);
-int file_input_get(char **in_ptr);
-
-#define DO_RTS_ERROR_TRUE TRUE
-#define DO_RTS_ERROR_FALSE FALSE
+int file_input_get_xchar(char *in_ptr, int max_chars_to_read);
+int file_input_read_xchar(char *in_ptr, int max_chars_to_read);
+int file_input_get(char **in_ptr, int max_len);
#endif
diff --git a/sr_unix/ftok.c b/sr_unix/ftok.c
index 6ec3aa0..a17847d 100644
--- a/sr_unix/ftok.c
+++ b/sr_unix/ftok.c
@@ -24,10 +24,13 @@
#include "gtm_ipc.h"
#include <errno.h>
#include "gtm_string.h"
+#include "cli.h"
#define DEFAULT_ID 43
#define ID_PREFIX "-id="
+GBLDEF CLI_ENTRY *cmd_ary = NULL; /* The GTCM server does not have any command tables so initialize command array to NULL */
+
#define PrintUsage \
{ \
FPRINTF(stderr, "\nUsage:\n"); \
diff --git a/sr_unix/generate_help.csh b/sr_unix/generate_help.csh
new file mode 100644
index 0000000..4f41e09
--- /dev/null
+++ b/sr_unix/generate_help.csh
@@ -0,0 +1,102 @@
+#################################################################
+# #
+# Copyright 2014 Fidelity Infromation Services, Inc #
+# #
+# This source code contains the intellectual property #
+# of its copyright holder(s), and is made available #
+# under a license. If you do not know the terms of #
+# the license, please stop and do not read further. #
+# #
+#################################################################
+
+#
+# (re)Generate GT.M and Utility Help global directories and files on demand
+#
+# Parameters:
+# HLP file location (defaults to $gtm_pct)
+# Error log file (used to redirect output to error file in comlist.csh)
+
+
+set hlpdir = $1
+if ("" == "${hlpdir}") then
+ if (0 == $?gtm_pct) then
+ echo "HLP file location was not supplied and \$gtm_pct is not defined"
+ exit -1
+ endif
+ set hlpdir = ${gtm_pct}
+ if (! -e ${hlpdir}) then
+ echo "HLP file location does not exist"
+ exit -2
+ endif
+endif
+
+set errout = ""
+if ("" != "${2}") set errout = ">> $2"
+
+# Need write permissions to $gtm_dist
+if (! -w ${gtm_dist}) then
+ set restorePerms = `filetest -P $gtm_dist`
+ chmod ugo+w ${gtm_dist}
+ if ($status) then
+ echo "User does not have sufficient privileges to get write access to $gtm_dist, cannot update help"
+ exit -3
+ endif
+endif
+
+set script_stat = 0
+foreach hlp (${hlpdir}/*.hlp)
+ # Extract the HLP file name and fix-up the mumps to gtm
+ set prefix=${hlp:t:r:s/mumps/gtm/}
+
+ # If the HLP files are newer than the help database create a new one, otherwise skip it
+ if ( `filetest -C ${hlp}` > `filetest -C $gtm_dist/${prefix}help.dat` ) then
+ \rm -f ${gtm_dist}/${prefix}help.gld ${gtm_dist}/${prefix}help.dat
+ else
+ continue
+ endif
+
+ # Either help info does not exist or needs to be regenerated
+
+ # Define the global directory with the same prefix as the HLP file and
+ # use ${gtm_dist} in the file name to ensure dynamic lookup of the DAT
+ # for help information
+ setenv gtmgbldir ${gtm_dist}/${prefix}help.gld
+ ${gtm_dist}/mumps -run GDE <<GDE_in_help
+Change -segment DEFAULT -block=2048 -file=\$gtm_dist/${prefix}help.dat
+Change -region DEFAULT -record=1020 -key=255
+GDE_in_help
+
+ if ($status) then
+ @ script_stat++
+ echo "genreatehelp-E-hlp, Error creating GLD for ${hlp}" $errout
+ continue
+ endif
+
+ ${gtm_dist}/mupip create
+
+ if ($status) then
+ @ script_stat++
+ echo "genreatehelp-E-hlp, Error creating DAT for ${hlp}" $errout
+ continue
+ endif
+
+ ${gtm_dist}/mumps -direct <<GTM_in_gtmhelp
+Do ^GTMHLPLD
+${hlp}
+Halt
+GTM_in_gtmhelp
+
+ if ($status) then
+ @ script_stat++
+ echo "genreatehelp-E-hlp, Error while processing ${hlp}" $errout
+ continue
+ endif
+end
+
+# Restore read-only status
+if ($?restorePerms) then
+ chmod ${restorePerms} ${gtm_dist}
+endif
+
+exit ${script_stat}
+
diff --git a/sr_unix/get_src_line.c b/sr_unix/get_src_line.c
index a432a23..c35cafd 100644
--- a/sr_unix/get_src_line.c
+++ b/sr_unix/get_src_line.c
@@ -35,9 +35,12 @@
# include "gdsbt.h"
# include "gdsfhead.h"
# include "gv_trigger.h"
+# include "gtm_trigger.h"
# include "cdb_sc.h"
# include "t_retry.h"
# include "trigger_source_read_andor_verify.h"
+# include "gtm_trigger_trc.h"
+# include "zr_unlink_rtn.h"
#endif
#include "stack_frame.h"
#include "rtn_src_chksum.h"
@@ -59,14 +62,14 @@ LITDEF mval literal_null;
error_def(ERR_TXTSRCFMT);
error_def(ERR_SYSCALL);
-int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_t verifytrig)
+int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, rhdtyp **rtn_vec)
{
int srcrecs, *lt_ptr, size, line_indx, srcfilnamlen;
boolean_t found, added, eof_seen, srcstat;
mstr src;
rhdtyp *rtn_vector;
zro_ent *srcdir;
- mstr *base, *current, *top;
+ mstr *base, *current, *top, tmprtnname;
char buff[MAX_SRCLINE], *cptr, *srcfile_name;
char srcnamebuf[SIZEOF(mident_fixed) + STR_LIT_LEN(DOTM)];
routine_source *src_tbl;
@@ -95,6 +98,7 @@ int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_
* Determine which source we need.
*/
GTMTRIG_ONLY(IS_TRIGGER_RTN(&routine->str, is_trigger));
+ DBGIFTRIGR((stderr, "get_src_line: entered $tlevel=%d and $t_tries=%d\n", dollar_tlevel, t_tries));
if (WANT_CURRENT_RTN(routine))
{ /* we want $TEXT for the routine currently executing. */
rtn_vector = CURRENT_RHEAD_ADR(frame_pointer->rvector);
@@ -103,21 +107,30 @@ int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_
if (is_trigger)
{ /* Need source on a trigger. Get trigger source loaded and/or verified which may involve
* creating a TP fence and dealing with TP restarts.
- * ZPRINT wants a consistent view of triggers across multiple calls so it bypasses verification
- * after the first call. In this case, the trigger had better be found since the first call found it.
*/
- if (verifytrig)
+ /* trigger_source_read_andor_verify may alter the length part of the mstr to remove the +BREG
+ * region-name specification (the string component is unmodified). Pass in a copy of the mstr struct to
+ * avoid modification to routine->str as it affects the caller which relies on this variable being
+ * untouched.
+ */
+ tmprtnname = routine->str;
+ DEBUG_ONLY(rtn_vector = NULL;)
+ DBGTRIGR((stderr, "get_src_line: fetch source for %s\n", tmprtnname.addr));
+ rc = trigger_source_read_andor_verify(&tmprtnname, TRIGGER_SRC_LOAD, &rtn_vector);
+ if (0 != rc)
{
- rc = trigger_source_read_andor_verify(&routine->str, TRIGGER_SRC_LOAD);
- if (0 != rc)
- return SRCNOTAVAIL;
+ if (NULL != rtn_vec)
+ *rtn_vec = NULL;
+ return SRCNOTAVAIL;
}
- rtn_vector = find_rtn_hdr(&routine->str); /* Trigger routine should be loaded now */
if (NULL == rtn_vector)
{
- assert(verifytrig); /* Noverify trig should always be found */
- return SRCNOTAVAIL; /* Could happen if trigger name got modified or uniqueified */
+ if (NULL != rtn_vec)
+ *rtn_vec = NULL;
+ return OBJMODMISS;
}
+ DBGTRIGR((stderr, "get_src_line: source found @0x%lx(%d)\n", rtn_vector->trigr_handle,
+ ((gv_trigger_t *)rtn_vector->trigr_handle)->xecute_str.str.len));
} else
# endif
{
@@ -126,13 +139,20 @@ int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_
op_zlink(routine, NULL);
rtn_vector = find_rtn_hdr(&routine->str);
if (NULL == rtn_vector)
+ {
+ if (NULL != rtn_vec)
+ *rtn_vec = NULL;
return OBJMODMISS;
+ }
}
- USHBIN_ONLY(rtn_vector = op_rhd_ext(routine, (mval *)&literal_null, rtn_vector, NULL));
+ ARLINK_ONLY(rtn_vector = op_rhd_ext(routine, (mval *)&literal_null, rtn_vector, NULL));
}
+ if (NULL != rtn_vec)
+ *rtn_vec = rtn_vector;
if (!rtn_vector->src_full_name.len)
return SRCNOTAVAIL;
src_tbl = rtn_vector->source_code;
+ DBGIFTRIGR((stderr, "get_src_line: routine has source_code 0x%lx (%d)\n", src_tbl, (src_tbl)? src_tbl->srcrecs : 0));
if (NULL == src_tbl)
{
# ifdef GTM_TRIGGER
@@ -142,6 +162,7 @@ int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_
srcsize = ((gv_trigger_t *)rtn_vector->trigr_handle)->xecute_str.str.len;
assert(0 < srcsize);
assert(NULL != srcstart);
+ DBGTRIGR((stderr, "get_src_line: source is %d bytes\n%s\n", srcsize, srcstart));
/* Calculate source checksum */
if (NULL == memchr(srcstart, '\n', srcsize))
{ /* In this case, gtm_trigger_complink() would have written an extra newline character to the
@@ -186,12 +207,13 @@ int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_
srcstart = srcptr;
}
if (!rtn_src_chksum_match(get_ctx_checksum(&checksum_ctx), get_rtnhdr_checksum(rtn_vector)))
- { /* Should never happen with a trigger unless it ran into some restartable concurrency
- * issues. Assert we can restart and do it.
+ { /* Should never happen inside TP with a trigger unless it ran into some restartable
+ * concurrency issues. Assert we can restart and do it.
*/
- assertpro(0 < dollar_tlevel);
- assert(CDB_STAGNATE > t_tries);
- t_retry(cdb_sc_triggermod);
+ DBGTRIGR((stderr, "get_src_line: rtn_src_chksum_match failed dumping trigger structure\n"));
+ assert(NULL != rtn_vector->trigr_handle);
+ if (0 < dollar_tlevel)
+ t_retry(cdb_sc_triggermod);
}
} else
# endif
@@ -202,6 +224,7 @@ int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_
rtn_vector->source_code = src_tbl;
} else
srcstat |= src_tbl->srcstat;
+ DBGIFTRIGR((stderr, " get_src_line: $tlevel %d\t", dollar_tlevel));
lt_ptr = (int *)find_line_addr(rtn_vector, &label->str, 0, NULL);
if (!lt_ptr)
srcstat |= LABELNOTFOUND;
@@ -209,6 +232,7 @@ int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_
{
line_indx = (int)(lt_ptr - (int *)LNRTAB_ADR(rtn_vector));
line_indx += offset;
+ DBGIFTRIGR((stderr, "get_src_line: line_indx %d\n", line_indx));
if (line_indx == 0)
srcstat |= ZEROLINE;
else if (line_indx < 0)
@@ -221,6 +245,7 @@ int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_
/* DBGFPF((stderr, "get_src_line: returning string %.*s\n", (*srcret)->len, (*srcret)->addr)); */
}
}
+ DBGIFTRIGR((stderr, "get_src_line: exiting with srcstat %d\n", srcstat));
return srcstat;
}
@@ -308,7 +333,7 @@ STATICFNDEF boolean_t fill_src_tbl_via_mfile(routine_source **src_tbl_result, rh
srcstat = 0;
srcfile_name = malloc(rtn_vector->src_full_name.len + 1);
memcpy(srcfile_name, rtn_vector->src_full_name.addr, rtn_vector->src_full_name.len);
- *(srcfile_name + rtn_vector->src_full_name.len) = 0; /* ensure string is null terminated */
+ *(srcfile_name + rtn_vector->src_full_name.len) = '\0'; /* Ensure string is null terminated */
/* At this point, it is not clear if Fopen will handle zos tagging correctly in all cases.
* especially when tagged with other than ISO8859-1 or IBM-1047. When we resurrect the zOS
* platform, we need to test this out.
@@ -325,7 +350,7 @@ STATICFNDEF boolean_t fill_src_tbl_via_mfile(routine_source **src_tbl_result, rh
MEMCPY_LIT(&srcnamebuf[srcfilnamlen], DOTM);
src.addr = srcnamebuf;
src.len = INTCAST(srcfilnamlen + STR_LIT_LEN(DOTM));
- zro_search (0, 0, &src, &srcdir, TRUE);
+ zro_search(NULL, NULL, &src, &srcdir, TRUE);
if (srcdir)
{
srcfile_name = malloc(src.len + srcdir->str.len + 2);
diff --git a/sr_unix/geteditor.c b/sr_unix/geteditor.c
index b477689..07ba1e6 100644
--- a/sr_unix/geteditor.c
+++ b/sr_unix/geteditor.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -13,10 +13,11 @@
#include "gtm_string.h"
#include "gtm_stdlib.h"
-#include "gtm_stat.h"
+#include "gtm_unistd.h"
#include "eintr_wrappers.h"
#include "geteditor.h"
+#include "wbox_test_init.h"
GBLDEF mstr editor;
@@ -24,8 +25,7 @@ void geteditor(void)
{
char *edt, **pedt;
short len;
- int stat_res, iter;
- struct stat edt_stat;
+ int iter;
char *editor_list[] =
{
"/usr/bin/vi",
@@ -37,12 +37,11 @@ void geteditor(void)
edt = GETENV("EDITOR");
pedt = &editor_list[0];
do {
- STAT_FILE(edt, &edt_stat, stat_res);
- if (!stat_res)
+ if (0 == ACCESS(edt, (F_OK|X_OK))) /* if the file exists and is executable we are good */
break;
edt = *pedt++;
} while (edt);
-
+ WBTEST_ASSIGN_ONLY(WBTEST_BADEDITOR_GETEDITOR, edt, 0);
if (edt)
{
len = strlen(edt) + 1; /* for zero */
diff --git a/sr_unix/go_load.c b/sr_unix/go_load.c
index 64fb2f6..3883c65 100644
--- a/sr_unix/go_load.c
+++ b/sr_unix/go_load.c
@@ -39,6 +39,7 @@
#include <rtnhdr.h>
#include "gv_trigger.h"
#include "mu_interactive.h"
+#include "wbox_test_init.h"
GBLREF bool mupip_error_occurred;
GBLREF bool mu_ctrly_occurred;
@@ -59,7 +60,7 @@ error_def(ERR_RECLOAD);
#define GO_PUT_SUB 0
#define GO_PUT_DATA 1
#define GO_SET_EXTRACT 2
-#define DEFAULT_MAX_REC_SIZE 3096
+#define DEFAULT_MAX_REC_SIZE 3096
#define ISSUE_TRIGDATAIGNORE_IF_NEEDED(KEYLENGTH, PTR, HASHT_GBL) \
{ \
/* The ordering of the && below is important as the caller uses HASHT_GBL to be set to TRUE if the global pointed to \
@@ -74,11 +75,12 @@ error_def(ERR_RECLOAD);
void go_call_db(int routine, char *parm1, int parm2, int val_off1, int val_len1);
-void go_load(uint4 begin, uint4 end)
+void go_load(uint4 begin, uint4 end, char *line1_ptr, int line1_len, char *line2_ptr, int line2_len)
{
char *ptr;
int len, fmt, keylength, keystate;
- uint4 iter, max_data_len, max_subsc_len, key_count, max_rec_size;
+ uint4 max_data_len, max_subsc_len, max_rec_size;
+ gtm_uint64_t iter, tmp_rec_count, key_count;
mstr src, des;
unsigned char *rec_buff, ch;
boolean_t utf8_extract, format_error = FALSE, hasht_ignored = FALSE, hasht_gbl = FALSE;
@@ -88,17 +90,10 @@ void go_load(uint4 begin, uint4 end)
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)
+ len = line1_len;
+ ptr = line1_ptr;
+ if (0 <= len)
{
util_out_print("!AD", TRUE, len, ptr);
utf8_extract = ((len >= STR_LIT_LEN(UTF8_NAME)) &&
@@ -110,17 +105,12 @@ void go_load(uint4 begin, uint4 end)
else
gtm_putmsg_csa(CSA_ARG(NULL) 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;
- }
+ len = line2_len;
+ ptr = line2_ptr;
if (len >= 0)
{
util_out_print("!AD", TRUE, len, ptr);
@@ -131,16 +121,12 @@ void go_load(uint4 begin, uint4 end)
begin = 3;
for (iter = 3; iter < begin; iter++)
{
- len = file_input_get(&ptr);
+ len = file_input_get(&ptr, 0);
if (len < 0) /* The IO device has signalled an end of file */
{
gtm_putmsg_csa(CSA_ARG(NULL) 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);
+ util_out_print("Error reading record number: !@UQ\n", TRUE, &iter);
return;
}
}
@@ -149,6 +135,9 @@ void go_load(uint4 begin, uint4 end)
max_data_len = 0;
max_subsc_len = 0;
key_count = 0;
+ GTM_WHITE_BOX_TEST(WBTEST_FAKE_BIG_KEY_COUNT, key_count, 4294967196U); /* (2**32)-100=4294967196 */
+ max_rec_size = DEFAULT_MAX_REC_SIZE;
+ rec_buff = (unsigned char *)malloc(max_rec_size);
for (iter = begin - 1; ; )
{
if (++iter > end)
@@ -159,14 +148,15 @@ void go_load(uint4 begin, uint4 end)
break;
if (mu_ctrlc_occurred)
{
- util_out_print("!AD:!_ Key cnt: !UL max subsc len: !UL max data len: !UL", TRUE,
- LEN_AND_LIT("LOAD TOTAL"), key_count, max_subsc_len, max_data_len);
- util_out_print("Last LOAD record number: !UL", TRUE, key_count ? iter : 0);
+ util_out_print("!AD:!_ Key cnt: !@UQ max subsc len: !UL max data len: !UL", TRUE,
+ LEN_AND_LIT("LOAD TOTAL"), &key_count, max_subsc_len, max_data_len);
+ tmp_rec_count = key_count ? iter : 0;
+ util_out_print("Last LOAD record number: !@UQ", TRUE, &tmp_rec_count);
mu_gvis();
util_out_print(0, TRUE);
mu_ctrlc_occurred = FALSE;
}
- if (0 > (len = file_input_get(&ptr)))
+ if (0 > (len = file_input_get(&ptr, 0)))
break;
if (mupip_error_occurred)
{
@@ -205,7 +195,7 @@ void go_load(uint4 begin, uint4 end)
if (mupip_error_occurred)
{
mu_gvis();
- gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_RECLOAD, 1, iter);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_RECLOAD, 1, &iter);
gv_target = NULL;
gv_currkey->base[0] = '\0';
ONERROR_PROCESS;
@@ -225,7 +215,8 @@ void go_load(uint4 begin, uint4 end)
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);
+ util_out_print("Format error in record number: !@UQ!/With content:!/!AD",
+ TRUE, &iter, src.len, src.addr);
format_error = TRUE;
continue;
}
@@ -236,7 +227,7 @@ void go_load(uint4 begin, uint4 end)
if (mupip_error_occurred)
{
mu_gvis();
- gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_RECLOAD, 1, iter);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_RECLOAD, 1, &iter);
ONERROR_PROCESS;
}
key_count++;
@@ -245,7 +236,7 @@ void go_load(uint4 begin, uint4 end)
ISSUE_TRIGDATAIGNORE_IF_NEEDED(len, ptr, hasht_gbl);
if (hasht_gbl)
{
- if (0 > (len = file_input_get(&ptr)))
+ if (0 > (len = file_input_get(&ptr, 0)))
break;
iter++;
hasht_gbl = FALSE;
@@ -255,7 +246,7 @@ void go_load(uint4 begin, uint4 end)
if (mupip_error_occurred)
{
mu_gvis();
- gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_RECLOAD, 1, iter);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_RECLOAD, 1, &iter);
gv_target = NULL;
gv_currkey->base[0] = '\0';
ONERROR_PROCESS;
@@ -267,12 +258,12 @@ void go_load(uint4 begin, uint4 end)
iter--; /* Decrement as didn't load key */
break;
}
- if ((len = file_input_get(&ptr)) < 0)
+ if (0 > (len = file_input_get(&ptr, 0)))
break;
if (mupip_error_occurred)
{
mu_gvis();
- gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_RECLOAD, 1, iter);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_RECLOAD, 1, &iter);
break;
}
stringpool.free = stringpool.base;
@@ -282,7 +273,7 @@ void go_load(uint4 begin, uint4 end)
if (mupip_error_occurred)
{
mu_gvis();
- gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_RECLOAD, 1, iter);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_RECLOAD, 1, &iter);
ONERROR_PROCESS;
}
key_count++;
@@ -295,9 +286,10 @@ void go_load(uint4 begin, uint4 end)
gtm_putmsg_csa(CSA_ARG(cs_addrs) 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,
+ util_out_print("LOAD TOTAL!_!_Key Cnt: !@UQ 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);
+ tmp_rec_count = key_count ? (iter - 1) : 0;
+ util_out_print("Last LOAD record number: !@UQ\n", TRUE, &tmp_rec_count);
if (format_error)
mupip_exit(ERR_LOADFILERR);
}
diff --git a/sr_unix/grab_latch.c b/sr_unix/grab_latch.c
new file mode 100644
index 0000000..1f11cbe
--- /dev/null
+++ b/sr_unix/grab_latch.c
@@ -0,0 +1,84 @@
+/****************************************************************
+ * *
+ * Copyright 2014 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#ifdef DEBUG
+#include "gtm_unistd.h" /* for "getpid" */
+#endif
+
+#include "interlock.h"
+#include "performcaslatchcheck.h"
+#include "rel_quant.h"
+#include "sleep_cnt.h"
+#include "wcs_sleep.h"
+
+GBLREF int num_additional_processors;
+GBLREF uint4 process_id;
+GBLREF volatile int4 fast_lock_count; /* Stop interrupts while we have our parts exposed */
+
+/* Grab a latch. If cannot get it in "max_retries" attempts, return FALSE, else TRUE.
+ * Check for a max of 4 times whether holder pid is dead and if so salvage the lock.
+ * Dont do it frequently as it involves is_proc_alive check which is a system call.
+ */
+boolean_t grab_latch(sm_global_latch_ptr_t latch, int max_timeout_in_secs)
+{
+ int max_retries, retries, spins, maxspins, quarter_retries, next_cascheck, cursleep;
+
+ assert(process_id == getpid()); /* make sure "process_id" global variable is reliable (used below in an assert) */
+ if (process_id == latch->u.parts.latch_pid)
+ { /* already have lock */
+ assert(FALSE); /* dont expect caller to call us if we hold the lock already. in pro be safe and return */
+ return TRUE;
+ }
+ ++fast_lock_count; /* Disable interrupts (i.e. wcs_stale) for duration to avoid potential deadlocks */
+ /* Compute "max_retries" so total sleep time is "max_timeout_in_secs" seconds */
+ quarter_retries = max_timeout_in_secs * MILLISECS_IN_SEC;
+ DEBUG_ONLY(
+ if (!quarter_retries)
+ quarter_retries = 1; /* dbg call to do grab_latch_immediate, reset to just 1 iteration */
+ )
+ max_retries = quarter_retries * 4; /* 1 loop in 4 is sleep of 1 msec */
+ maxspins = num_additional_processors ? MAX_LOCK_SPINS(max_retries, num_additional_processors) : 1;
+ next_cascheck = max_retries - quarter_retries;
+ cursleep = MINSLPTIME;
+ for (retries = max_retries - 1; 0 < retries; retries--) /* - 1 so do rel_quant 3 times first */
+ {
+ for (spins = maxspins; 0 < spins; spins--)
+ { /* We better not hold it if trying to get it */
+ assert(latch->u.parts.latch_pid != process_id);
+ if (GET_SWAPLOCK(latch))
+ { /* Note that fast_lock_count is kept incremented for the duration that we hold the lock
+ * to prevent our dispatching an interrupt that could deadlock getting this lock
+ */
+ --fast_lock_count;
+ assert(0 <= fast_lock_count);
+ return TRUE;
+ }
+ }
+ /* Now that we have done a lot of spin, sleep a little. Do not use rel_quant as benchmarks done seem to
+ * suggest it is a more costly operation (system call + cpu overhead) in an environment with lots of processes.
+ */
+ wcs_sleep(cursleep++);
+ if (MAXSLPTIME == cursleep)
+ cursleep = MINSLPTIME; /* start all over again in sleep loop */
+ /* For a total of 3 times in this function, see if target is dead and/or wake it up */
+ if (retries == next_cascheck)
+ {
+ performCASLatchCheck(latch, TRUE);
+ next_cascheck -= quarter_retries;
+ }
+ }
+ --fast_lock_count;
+ assert(0 <= fast_lock_count);
+ assert(FALSE);
+ return FALSE;
+}
diff --git a/sr_unix/gt_timer.h b/sr_unix/gt_timer.h
index 002552a..6d520a7 100644
--- a/sr_unix/gt_timer.h
+++ b/sr_unix/gt_timer.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -83,17 +83,69 @@ typedef struct st_timer_alloc
struct st_timer_alloc *next;
} st_timer_alloc;
-#define MAX_TIMER_HNDLRS 10 /* Max # of safe timer handlers */
+#define MAX_SAFE_TIMER_HNDLRS 10 /* Max # of safe timer handlers */
#define GT_WAKE
+#define CANCEL_TIMERS cancel_unsafe_timers()
-/* Set each timer request to go for 10ms more than requested, since the
- * interval timer alarm will sometimes go off early on many UNIX systems.
- * 10ms is more than enough for all systems tested so far (SunOS, Solaris,
- * HP/UX, NonStop/UX)
+/* Uncomment the below #define if you want to print the status of the key timer-related variables as well as the entire timer queue
+ * when operations such as addition, cancelation, or handling of a timer occur.
+ *
+ * #define TIMER_DEBUGGING
*/
-#define SLACKTIME 10
-#define CANCEL_TIMERS cancel_unsafe_timers()
+#ifdef TIMER_DEBUGGING
+# define DUMP_TIMER_INFO(LOCATION) \
+{ \
+ int i; \
+ GT_TIMER *cur_timer; \
+ char *s_heartbeat_timer = "heartbeat_timer"; \
+ char *s_wcs_clean_dbsync = "wcs_clean_dbsync"; \
+ char *s_wcs_stale = "wcs_stale"; \
+ char *s_hiber_wake = "hiber_wake"; \
+ char *s_unknown = "unknown"; \
+ char *handler; \
+ \
+ cur_timer = (GT_TIMER *)timeroot; \
+ FPRINTF(stderr, "------------------------------------------------------\n" \
+ "%s\n---------------------------------\n" \
+ "Timer Info:\n" \
+ " system timer active: %d\n" \
+ " timer in handler: %d\n" \
+ " timer stack count: %d\n" \
+ " heartbeat started: %d\n", \
+ LOCATION, timer_active, timer_in_handler, timer_stack_count, heartbeat_started);\
+ FFLUSH(stderr); \
+ i = 0; \
+ while (cur_timer) \
+ { \
+ if ((void (*)())heartbeat_timer_ptr == cur_timer->handler) \
+ handler = s_heartbeat_timer; \
+ else if ((void (*)())wcs_clean_dbsync_fptr == cur_timer->handler) \
+ handler = s_wcs_clean_dbsync; \
+ else if ((void (*)())wcs_stale_fptr == cur_timer->handler) \
+ handler = s_wcs_stale; \
+ else if ((void (*)())hiber_wake == cur_timer->handler) \
+ handler = s_hiber_wake; \
+ else \
+ handler = s_unknown; \
+ FPRINTF(stderr, " - timer #%d:\n" \
+ " handler: %s\n" \
+ " safe: %d\n" \
+ " start_time: [at_sec: %ld; at_usec: %ld]\n" \
+ " expir_time: [at_sec: %ld; at_usec: %ld]\n", \
+ i, handler, cur_timer->safe, \
+ cur_timer->start_time.at_sec, cur_timer->start_time.at_usec, \
+ cur_timer->expir_time.at_sec, cur_timer->expir_time.at_usec); \
+ FFLUSH(stderr); \
+ cur_timer = cur_timer->next; \
+ i++; \
+ } \
+ FPRINTF(stderr, "------------------------------------------------------\n"); \
+ FFLUSH(stderr); \
+}
+#else
+# define DUMP_TIMER_INFO(LOCATION)
+#endif
int4 abs_time_comp(ABS_TIME *atp1, ABS_TIME *atp2);
void add_int_to_abs_time(ABS_TIME *atps, int4 ival, ABS_TIME *atpd);
diff --git a/sr_unix/gt_timers.c b/sr_unix/gt_timers.c
index bcbedf8..44bdc3b 100644
--- a/sr_unix/gt_timers.c
+++ b/sr_unix/gt_timers.c
@@ -26,7 +26,7 @@
*
* Following are top-level user-callable routines of this package:
*
- * void sys_get_cur_time(ABS_TIME *atp)
+ * void sys_get_curr_time(ABS_TIME *atp)
* fetch absolute time into stucture
*
* void hiber_start(uint4 hiber)
@@ -77,15 +77,10 @@
#include "util.h"
#include "sleep.h"
#include "error.h"
-#if defined(__osf__)
-# define HZ CLK_TCK
-#elif defined(__MVS__)
-# define HZ gtm_zos_HZ
-STATICDEF int gtm_zos_HZ = 100; /* see prealloc_gt_timers below */
-#endif
#ifdef ITIMER_REAL
# define BSD_TIMER
+# define USER_HZ 1000
#else
/* check def of time() including arg - see below; should be time_t
* (from sys/types.h) and traditionally unsigned long */
@@ -131,7 +126,7 @@ STATICDEF struct itimerval sys_timer, old_sys_timer;
STATICDEF boolean_t in_setitimer_error;
#endif
-#define DUMMY_SIG_NUM 0 /* following can be used to see why timer_handler was called */
+#define DUMMY_SIG_NUM 0 /* following can be used to see why timer_handler was called */
STATICDEF volatile GT_TIMER *timeroot = NULL; /* chain of pending timer requests in time order */
STATICDEF boolean_t first_timeset = TRUE;
@@ -139,14 +134,14 @@ STATICDEF struct sigaction prev_alrm_handler; /* save previous SIGALRM handler,
/* Chain of unused timer request blocks */
STATICDEF volatile GT_TIMER *timefree = NULL;
-STATICDEF volatile int4 num_timers_free; /* # of timers in the unused queue */
+STATICDEF volatile int4 num_timers_free; /* # of timers in the unused queue */
STATICDEF int4 timeblk_hdrlen;
STATICDEF volatile st_timer_alloc *timer_allocs = NULL;
-STATICDEF int safe_timer_cnt, timer_pop_cnt; /* Number of safe timers in queue/popped */
+STATICDEF int safe_timer_cnt, timer_pop_cnt; /* Number of safe timers in queue/popped */
STATICDEF TID *deferred_tids;
-STATICDEF timer_hndlr safe_handlers[MAX_TIMER_HNDLRS + 1]; /* +1 for NULL to terminate list, or can use safe_handlers_cnt */
+STATICDEF timer_hndlr safe_handlers[MAX_SAFE_TIMER_HNDLRS + 1]; /* +1 for NULL to terminate list */
STATICDEF int safe_handlers_cnt;
STATICDEF boolean_t stolen_timer = FALSE; /* only complain once, used in check_for_timer_pops() */
@@ -259,28 +254,11 @@ void set_blocksig(void)
/* Initialize group of timer blocks */
void prealloc_gt_timers(void)
-{ /* On certain boxes SYSCONF in this function might get called earlier than
- * the one in set_num_additional_processors(), so unset white_box_enabled
- * for this SYSCONF to avoid issues
- */
-# ifdef __MVS__
-# ifdef DEBUG
- boolean_t white_box_enabled = gtm_white_box_test_case_enabled;
- if (white_box_enabled)
- gtm_white_box_test_case_enabled = FALSE;
-# endif
- SYSCONF(_SC_CLK_TCK, gtm_zos_HZ); /* get the real value */
-# ifdef DEBUG
- if (white_box_enabled)
- gtm_white_box_test_case_enabled = TRUE;
-# endif
-# endif
-
- /* Preallocate some timer blocks. This will be all the timer blocks we hope to need.
+{ /* Preallocate some timer blocks. This will be all the timer blocks we hope to need.
* Allocate them with 8 bytes of possible data each.
* If more timer blocks are needed, we will allocate them as needed.
*/
- gt_timers_alloc(); /* Allocate timers */
+ gt_timers_alloc();
/* Now initialize the safe timers. Must be done dynamically to avoid the situation where this module always references all
* possible safe timers thus pulling extra stuff into executables that don't need or want it.
*
@@ -329,7 +307,7 @@ void hiber_start(uint4 hiber)
{ /* normally, if SIGALRMs are blocked, we must already be inside a timer handler, but someone can actually disable
* SIGALRMs, in which case we do not want this assert to trip in pro */
assert(1 <= timer_stack_count);
- NANOSLEEP(hiber);
+ SLEEP_USEC(hiber, TRUE);
} else
{
assertpro(1 > timer_stack_count); /* if SIGALRMs are not blocked, we cannot be inside a timer handler */
@@ -367,7 +345,7 @@ void hiber_start_wait_any(uint4 hiber)
/* Even though theoretically it is possible for any signal other than SIGALRM to discontinue the wait in sigsuspend,
* the intended use of this function targets only timer-scheduled events. For that reason, assert that SIGALRMs are
* not blocked prior to scheduling a timer, whose delivery we will be waiting upon, as otherwise we might end up
- * waiting indefinitely. Note, however, that the use of NANOSLEEP in hiber_start, explained in the accompanying
+ * waiting indefinitely. Note, however, that the use of SLEEP_USEC in hiber_start, explained in the accompanying
* comment, should not be required in hiber_start_wait_any, as we presently do not invoke this function in interrupt-
* induced code, and so we should not end up here with SIGALARMs blocked.
*/
@@ -378,10 +356,10 @@ void hiber_start_wait_any(uint4 hiber)
sigprocmask(SIG_SETMASK, &savemask, NULL); /* reset signal handlers */
}
-/* Wrapper function for start_timer() that is exposed for outside use. The function ensure that time_to_expir is positive. If
- * negative value or 0 is passed, set time_to_expir to SLACKTIME and invoke start_timer(). The reason we have not merged this
- * functionality with start_timer() is because there is no easy way to determine whether the function is invoked from inside
- * GT.M or by an external routine.
+/* Wrapper function for start_timer() that is exposed for outside use. The function ensures that time_to_expir is positive. If
+ * negative value or 0 is passed, set time_to_expir to 0 and invoke start_timer(). The reason we have not merged this functionality
+ * with start_timer() is because there is no easy way to determine whether the function is invoked from inside GT.M or by an
+ * external routine.
* Arguments: tid - timer id
* time_to_expir - time to expiration in msecs
* handler - pointer to handler routine
@@ -395,7 +373,7 @@ void gtm_start_timer(TID tid,
void *hdata)
{
if (0 >= time_to_expir)
- time_to_expir = SLACKTIME;
+ time_to_expir = 0;
start_timer(tid, time_to_expir, handler, hdata_len, hdata);
}
@@ -416,7 +394,8 @@ void start_timer(TID tid,
boolean_t safe_timer = FALSE, safe_to_add = FALSE;
int i;
- assertpro(0 < time_to_expir); /* Callers should verify non-zero time */
+ assertpro(0 <= time_to_expir); /* Callers should verify non-zero time */
+ DUMP_TIMER_INFO("At the start of start_timer()");
if (NULL == handler)
{
safe_to_add = TRUE;
@@ -451,6 +430,7 @@ void start_timer(TID tid,
sigprocmask(SIG_BLOCK, &blockalrm, &savemask); /* block SIGALRM signal */
start_timer_int(tid, time_to_expir, handler, hdata_len, hdata, safe_timer);
sigprocmask(SIG_SETMASK, &savemask, NULL); /* reset signal handlers */
+ DUMP_TIMER_INFO("At the end of start_timer()");
}
/* Internal version of start_timer that does not protect itself, assuming this has already been done.
@@ -460,7 +440,7 @@ STATICFNDEF void start_timer_int(TID tid, int4 time_to_expir, void (*handler)(),
{
ABS_TIME at;
- assert(0 != time_to_expir);
+ assert(0 <= time_to_expir);
sys_get_curr_time(&at);
if (first_timeset)
{
@@ -477,7 +457,9 @@ STATICFNDEF void start_timer_int(TID tid, int4 time_to_expir, void (*handler)(),
/* Check if # of free timer slots is less than minimum threshold. If so, allocate more of those while it is safe to do so */
if ((GT_TIMER_EXPAND_TRIGGER > num_timers_free) && (1 > timer_stack_count))
gt_timers_alloc();
+ DUMP_TIMER_INFO("Before invoking add_timer()");
add_timer(&at, tid, time_to_expir, handler, hdata_len, hdata, safe_timer); /* Put new timer in the queue. */
+ DUMP_TIMER_INFO("After invoking add_timer()");
if ((timeroot->tid == tid) || !timer_active)
start_first_timer(&at);
}
@@ -492,6 +474,7 @@ void cancel_timer(TID tid)
boolean_t first_timer;
sigprocmask(SIG_BLOCK, &blockalrm, &savemask); /* block SIGALRM signal */
+ DUMP_TIMER_INFO("At the start of cancel_timer()");
sys_get_curr_time(&at);
first_timer = (timeroot && (timeroot->tid == tid));
remove_timer(tid); /* remove it from the chain */
@@ -503,6 +486,7 @@ void cancel_timer(TID tid)
sys_canc_timer();
}
sigprocmask(SIG_SETMASK, &savemask, NULL);
+ DUMP_TIMER_INFO("At the end of cancel_timer()");
}
/* Clear the timers' state for the forked-off process. */
@@ -539,15 +523,8 @@ STATICFNDEF void sys_settimer(TID tid, ABS_TIME *time_to_expir, void (*handler)(
# ifdef BSD_TIMER
if (in_setitimer_error)
return;
- if ((time_to_expir->at_sec == 0) && (time_to_expir->at_usec < (1000000 / HZ)))
- {
- sys_timer.it_value.tv_sec = 0;
- sys_timer.it_value.tv_usec = 1000000 / HZ;
- } else
- {
- sys_timer.it_value.tv_sec = time_to_expir->at_sec;
- sys_timer.it_value.tv_usec = (gtm_tv_usec_t)time_to_expir->at_usec;
- }
+ sys_timer.it_value.tv_sec = time_to_expir->at_sec;
+ sys_timer.it_value.tv_usec = (gtm_tv_usec_t)time_to_expir->at_usec;
sys_timer.it_interval.tv_sec = sys_timer.it_interval.tv_usec = 0;
assert(1000000 > sys_timer.it_value.tv_usec);
if ((-1 == setitimer(ITIMER_REAL, &sys_timer, &old_sys_timer)) || WBTEST_ENABLED(WBTEST_SETITIMER_ERROR))
@@ -568,52 +545,53 @@ STATICFNDEF void sys_settimer(TID tid, ABS_TIME *time_to_expir, void (*handler)(
*/
STATICFNDEF void start_first_timer(ABS_TIME *curr_time)
{
- ABS_TIME eltime, interval;
+ ABS_TIME eltime;
GT_TIMER *tpop;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
+ DUMP_TIMER_INFO("At the start of start_first_timer()");
if ((1 < timer_stack_count) || (TRUE == timer_in_handler))
{
deferred_timers_check_needed = FALSE;
return;
}
if ((INTRPT_OK_TO_INTERRUPT == intrpt_ok_state) && !process_exiting)
- {
- while (timeroot) /* check if some timer expired while this function was getting invoked */
+ { /* Check if some timer expired while this function was getting invoked. */
+ while (timeroot)
{
eltime = sub_abs_time((ABS_TIME *)&timeroot->expir_time, curr_time);
- if ((0 <= eltime.at_sec) || (0 < timer_stack_count)) /* nothing has expired yet */
+ /* If nothing has expired yet, break. */
+ if ((0 < eltime.at_sec) || ((0 == eltime.at_sec) && (0 < eltime.at_usec)) || (0 < timer_stack_count))
break;
- timer_handler(DUMMY_SIG_NUM); /* otherwise, drive the handler */
+ /* Otherwise, drive the handler. */
+ timer_handler(DUMMY_SIG_NUM);
}
- if (timeroot) /* we still have a timer to set? */
+ /* Do we still have a timer to set? */
+ if (timeroot)
{
- add_int_to_abs_time(&eltime, SLACKTIME, &interval);
deferred_timers_check_needed = FALSE;
- sys_settimer(timeroot->tid, &interval, timeroot->handler); /* set system timer */
+ sys_settimer(timeroot->tid, &eltime, timeroot->handler);
}
- } else if (0 < safe_timer_cnt) /* there are some safe timers */
- {
- tpop = (GT_TIMER *)timeroot; /* regular timers are not allowed here, so only handle safe timers */
+ } else if (0 < safe_timer_cnt)
+ { /* There are some safe timers on the queue. */
+ tpop = (GT_TIMER *)timeroot;
while (tpop)
{
eltime = sub_abs_time((ABS_TIME *)&tpop->expir_time, curr_time);
if (tpop->safe)
- {
- if (0 > eltime.at_sec) /* at least one safe timer has expired */
- timer_handler(DUMMY_SIG_NUM); /* so, drive what we can */
+ { /* Regular timers cannot be processed here, so only handle safe timers, and only if expired. */
+ if ((0 > eltime.at_sec) || ((0 == eltime.at_sec) && (0 == eltime.at_usec)))
+ timer_handler(DUMMY_SIG_NUM);
else
- {
- add_int_to_abs_time(&eltime, SLACKTIME, &interval);
- sys_settimer(tpop->tid, &interval, tpop->handler);
- }
+ sys_settimer(tpop->tid, &eltime, tpop->handler);
break;
} else if (0 > eltime.at_sec)
deferred_timers_check_needed = TRUE;
tpop = tpop->next;
}
}
+ DUMP_TIMER_INFO("At the end of start_first_timer()");
}
/* Timer handler. This is the main handler routine that is being called by the kernel upon receipt
@@ -636,6 +614,7 @@ STATICFNDEF void timer_handler(int why)
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
+ DUMP_TIMER_INFO("At the start of timer_handler()");
if (SIGALRM == why)
{ /* If why is 0, we know that timer_handler() was called directly, so no need
* to check if the signal needs to be forwarded to appropriate thread.
@@ -763,6 +742,7 @@ STATICFNDEF void timer_handler(int why)
SET_ERROR_CONDITION(save_error_condition); /* restore error_condition & severity */
errno = save_errno; /* restore mainline errno by similar reasoning as mainline error_condition */
timer_stack_count--;
+ DUMP_TIMER_INFO("At the end of timer_handler()");
}
/* Find a timer given by tid in the timer chain.
diff --git a/sr_unix/gtm_env_init_sp.c b/sr_unix/gtm_env_init_sp.c
index 4c236ee..0286556 100644
--- a/sr_unix/gtm_env_init_sp.c
+++ b/sr_unix/gtm_env_init_sp.c
@@ -66,6 +66,8 @@
# define GTM_USESECSHR "$gtm_usesecshr"
/* GTM_TEST_FAKE_ENOSPC is used only in debug code so it does not have to go in gtm_logicals.h */
# define GTM_TEST_FAKE_ENOSPC "$gtm_test_fake_enospc"
+/* GTM_TEST_AUTORELINK_ALWAYS is used only in debug code so it does not have to go in gtm_logicals.h */
+# define GTM_TEST_AUTORELINK_ALWAYS "$gtm_test_autorelink_always"
#endif
#define DEFAULT_MUPIP_TRIGGER_ETRAP "IF $ZJOBEXAM()"
@@ -77,7 +79,6 @@
#endif
#define MAX_TRANS_NAME_LEN GTM_PATH_MAX
-GBLREF int4 gtm_shmflags; /* Shared memory flags for shmat() */
GBLREF uint4 gtm_principal_editing_defaults; /* ext_cap flags if tt */
GBLREF boolean_t is_gtm_chset_utf8;
GBLREF boolean_t utf8_patnumeric;
@@ -128,6 +129,7 @@ void gtm_env_init_sp(void)
char buf[MAX_TRANS_NAME_LEN], *token, cwd[GTM_PATH_MAX];
char *cwdptr, *trigger_etrap, *c, *end;
struct stat outbuf;
+ int gtm_autorelink_shm_min;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
@@ -156,9 +158,6 @@ void gtm_env_init_sp(void)
} /* else gtm_core_file/gtm_core_putenv remain null and we likely cannot generate proper core files */
}
# endif
- val.addr = GTM_SHMFLAGS;
- val.len = SIZEOF(GTM_SHMFLAGS) - 1;
- gtm_shmflags = (int4)trans_numeric(&val, &is_defined, TRUE); /* Flags vlaue (0 is undefined or bad) */
val.addr = GTM_QUIET_HALT;
val.len = SIZEOF(GTM_QUIET_HALT) - 1;
ret = logical_truth_value(&val, FALSE, &is_defined);
@@ -345,7 +344,7 @@ void gtm_env_init_sp(void)
{
init_relink_allowed(&trans); /* set TREF(relink_allowed) */
}
-# ifdef USHBIN_SUPPORTED
+# ifdef AUTORELINK_SUPPORTED
/* Set default or supplied value for $gtm_linktmpdir */
val.addr = GTM_LINKTMPDIR;
val.len = SIZEOF(GTM_LINKTMPDIR) - 1;
@@ -360,14 +359,15 @@ void gtm_env_init_sp(void)
}
}
assert(GTM_PATH_MAX > trans.len);
+ /* Remove trailing '/' from path */
+ while ((1 < trans.len) && ('/' == trans.addr[trans.len - 1]))
+ trans.len--;
(TREF(gtm_linktmpdir)).addr = malloc(trans.len + 1); /* +1 for '\0'; This memory is never freed */
(TREF(gtm_linktmpdir)).len = trans.len;
/* For now, we assume that if the environment variable is defined to NULL, anticipatory freeze is NOT in effect */
if (0 < trans.len)
- {
memcpy((TREF(gtm_linktmpdir)).addr, trans.addr, trans.len);
- ((TREF(gtm_linktmpdir)).addr)[trans.len] = '\0';
- }
+ ((TREF(gtm_linktmpdir)).addr)[trans.len] = '\0';
STAT_FILE((TREF(gtm_linktmpdir)).addr, &outbuf, stat_res);
if ((-1 == stat_res) || !S_ISDIR(outbuf.st_mode))
{ /* Either the directory doesn't exist or the entity is not a directory */
@@ -376,7 +376,24 @@ void gtm_env_init_sp(void)
(TREF(gtm_linktmpdir)).len = SIZEOF(DEFAULT_GTM_TMP) - 1;
(TREF(gtm_linktmpdir)).addr = DEFAULT_GTM_TMP;
}
-# endif
+ /* See if gtm_autorelink_shm is set */
+ val.addr = GTM_AUTORELINK_SHM;
+ val.len = SIZEOF(GTM_AUTORELINK_SHM) - 1;
+ gtm_autorelink_shm_min = trans_numeric(&val, &is_defined, TRUE);
+ if (!is_defined || !gtm_autorelink_shm_min)
+ TREF(relinkctl_shm_min_index) = 0;
+ else
+ {
+ gtm_autorelink_shm_min = (2 <= gtm_autorelink_shm_min) ? ceil_log2_32bit(gtm_autorelink_shm_min) : 0;
+ TREF(relinkctl_shm_min_index) = gtm_autorelink_shm_min;
+ }
+ /* See if gtm_autorelink_keeprtn is set */
+ val.addr = GTM_AUTORELINK_KEEPRTN;
+ val.len = SIZEOF(GTM_AUTORELINK_KEEPRTN) - 1;
+ TREF(gtm_autorelink_keeprtn) = logical_truth_value(&val, FALSE, &is_defined);
+ if (!is_defined)
+ TREF(gtm_autorelink_keeprtn) = FALSE;
+# endif /* AUTORELINK_SUPPORTED */
# ifdef DEBUG
/* DEBUG-only option to bypass 'easy' methods of things and always use gtmsecshr for IPC cleanups, wakeups, file removal,
* etc. Basically use gtmsecshr for anything where it is an option - helps with testing gtmsecshr for proper operation.
@@ -392,6 +409,12 @@ void gtm_env_init_sp(void)
TREF(gtm_test_fake_enospc) = logical_truth_value(&val, FALSE, &is_defined);
if (!is_defined)
TREF(gtm_test_fake_enospc) = FALSE;
+ /* DEBUG-only option to enable autorelink on all directories in $zroutines (except for shlib directories) */
+ val.addr = GTM_TEST_AUTORELINK_ALWAYS;
+ val.len = SIZEOF(GTM_TEST_AUTORELINK_ALWAYS) - 1;
+ TREF(gtm_test_autorelink_always) = logical_truth_value(&val, FALSE, &is_defined);
+ if (!is_defined)
+ TREF(gtm_test_autorelink_always) = FALSE;
# endif
# ifdef GTMDBGFLAGS_ENABLED
val.addr = GTMDBGFLAGS;
diff --git a/sr_unix/gtm_exit_handler.c b/sr_unix/gtm_exit_handler.c
index adee853..39d1147 100644
--- a/sr_unix/gtm_exit_handler.c
+++ b/sr_unix/gtm_exit_handler.c
@@ -53,81 +53,125 @@ GBLREF boolean_t need_core; /* Core file should be created */
GBLREF boolean_t created_core; /* core file was created */
GBLREF unsigned int core_in_progress;
GBLREF boolean_t dont_want_core;
-GBLREF int4 process_id;
GBLREF boolean_t exit_handler_active;
-GBLREF boolean_t pool_init;
-GBLREF jnlpool_addrs jnlpool;
-GBLREF jnlpool_ctl_ptr_t jnlpool_ctl;
GBLREF boolean_t is_tracing_on;
+static enum rundown_state attempting;
+
#ifdef DEBUG
GBLREF int process_exiting;
-GBLREF boolean_t ok_to_UNWIND_in_exit_handling;
#endif
+/* Note: This macro uses local variables "attempting", "error_seen" and "actual_exi_condition" */
+#define RUNDOWN_STEP(THISSTATE, NEXTSTATE, ERRCODE, STMT) \
+{ \
+ if (THISSTATE == attempting) \
+ { \
+ if (!error_seen) \
+ { \
+ STMT; \
+ } else \
+ { \
+ if (!actual_exi_condition) \
+ actual_exi_condition = exi_condition; \
+ if (0 != ERRCODE) \
+ { \
+ PRN_ERROR; \
+ dec_err(VARLSTCNT(1) ERRCODE); \
+ } \
+ } \
+ error_seen = FALSE; \
+ attempting++; \
+ } \
+ assert(NEXTSTATE == (THISSTATE + 1)); \
+}
+
+#define MPROF_RUNDOWN_MACRO \
+{ \
+ if (is_tracing_on) \
+ turn_tracing_off(NULL); \
+}
+
+#define LOCK_RUNDOWN_MACRO \
+{ \
+ SET_PROCESS_EXITING_TRUE; \
+ CANCEL_TIMERS; /* Cancel all unsafe timers - No unpleasant surprises */ \
+ secshr_db_clnup(NORMAL_TERMINATION); \
+ if (dollar_tlevel) \
+ OP_TROLLBACK(0); \
+ zcall_halt(); \
+ op_lkinit(); \
+ op_unlock(); \
+ op_zdeallocate(NO_M_TIMEOUT); \
+}
+
+#define IO_RUNDOWN_MACRO \
+{ \
+ /* Invoke cleanup routines for all the shared libraries loaded during external call initialisation. \
+ * The cleanup routines are not mandatory routines, but if defined, will be invoked before \
+ * closing the shared library. \
+ */ \
+ for (package_ptr = TREF(extcall_package_root); package_ptr; package_ptr = package_ptr->next_package) \
+ { \
+ if (package_ptr->package_clnup_rtn) \
+ package_ptr->package_clnup_rtn(); \
+ fgn_closepak(package_ptr->package_handle, INFO); \
+ } \
+ relinkctl_rundown(TRUE, TRUE); /* decrement relinkctl-attach & rtnobj-reference counts */ \
+ assert(process_exiting); \
+ if (MUMPS_CALLIN & invocation_mode) \
+ { \
+ flush_pio(); \
+ io_rundown(RUNDOWN_EXCEPT_STD); \
+ } else \
+ io_rundown(NORMAL_RUNDOWN); \
+ GTMCRYPT_CLOSE; \
+}
+
+error_def(ERR_GVRUNDOWN);
+error_def(ERR_LKRUNDOWN);
+error_def(ERR_MPROFRUNDOWN);
+
+enum rundown_state
+{
+ rundown_state_mprof,
+ rundown_state_lock,
+ rundown_state_db,
+ rundown_state_io,
+ rundown_state_last
+};
+
void gtm_exit_handler(void)
{
- struct sigaction act;
- struct extcall_package_list *package_ptr;
- DCL_THREADGBL_ACCESS;
+ struct sigaction act;
+ struct extcall_package_list *package_ptr;
+ boolean_t error_seen;
+ int4 actual_exi_condition;
+ DCL_THREADGBL_ACCESS;
- SETUP_THREADGBL_ACCESS;
+ SETUP_THREADGBL_ACCESS;
if (exit_handler_active) /* Don't recurse if exit handler exited */
return;
- if (is_tracing_on)
- turn_tracing_off(NULL);
exit_handler_active = TRUE;
- SET_PROCESS_EXITING_TRUE;
- CANCEL_TIMERS; /* Cancel all unsafe timers - No unpleasant surprises */
- ESTABLISH(lastchance1);
- secshr_db_clnup(NORMAL_TERMINATION);
- if (dollar_tlevel)
- OP_TROLLBACK(0);
- zcall_halt();
- op_lkinit();
- op_unlock();
- op_zdeallocate(NO_M_TIMEOUT);
- REVERT;
-
- ESTABLISH(lastchance2);
- gv_rundown();
- REVERT;
-
- ESTABLISH(lastchance3);
- /* Invoke cleanup routines for all the shared libraries loaded during external call initialisation.
- * The cleanup routines are not mandatory routines, but if defined, will be invoked before
- * closing the shared library.
+ attempting = rundown_state_mprof;
+ actual_exi_condition = 0;
+ ESTABLISH_NORET(exi_ch, error_seen);
+ RUNDOWN_STEP(rundown_state_mprof, rundown_state_lock, ERR_MPROFRUNDOWN, MPROF_RUNDOWN_MACRO);
+ RUNDOWN_STEP(rundown_state_lock, rundown_state_db, ERR_LKRUNDOWN, LOCK_RUNDOWN_MACRO);
+ RUNDOWN_STEP(rundown_state_db, rundown_state_io, ERR_GVRUNDOWN, gv_rundown());
+ /* We pass 0 (not ERR_IORUNDOWN) below to avoid displaying any error if io_rundown fails. One reason we have
+ * seen an external filter M program fail is with a "SYSTEM-E-ENO32, Broken pipe" error if the source or receiver
+ * server (that is communicating with it through a pipe device) closes its end of the pipe and we do not want that
+ * to be treated as an error in rundown (it is how a pipe close happens normally).
*/
- for (package_ptr = TREF(extcall_package_root); package_ptr; package_ptr = package_ptr->next_package)
- {
- if (package_ptr->package_clnup_rtn)
- package_ptr->package_clnup_rtn();
- fgn_closepak(package_ptr->package_handle, INFO);
- }
- relinkctl_rundown(TRUE);
- /* We know of at least one case where the below code would error out. That is if this were a replication external
- * filter M program halting out after the other end of the pipe has been closed by the source server. In this case,
- * the io_rundown call below would error out and would invoke the lastchance3 condition handler which will do an
- * UNWIND that will return from gtm_exit_handler right away. To avoid an assert in the UNWIND macro (that checks
- * we never do UNWINDs while process_exiting is set to TRUE) set a debug-only variable to TRUE. This variable is
- * also checked by the assert in the UNWIND macro (see <C9K06_003278_test_failures/resolution_v2.txt> for details).
- */
- assert(process_exiting);
- DEBUG_ONLY(ok_to_UNWIND_in_exit_handling = TRUE;)
- if (MUMPS_CALLIN & invocation_mode)
- {
- flush_pio();
- io_rundown(RUNDOWN_EXCEPT_STD);
- } else
- io_rundown(NORMAL_RUNDOWN);
- DEBUG_ONLY(ok_to_UNWIND_in_exit_handling = FALSE;)
- GTMCRYPT_CLOSE;
+ RUNDOWN_STEP(rundown_state_io, rundown_state_last, 0, IO_RUNDOWN_MACRO);
REVERT;
-
print_exit_stats();
if (need_core && !created_core && !dont_want_core) /* We needed to core */
{
++core_in_progress;
DUMP_CORE; /* This will not return */
}
+ if (actual_exi_condition && !(MUMPS_CALLIN & invocation_mode))
+ PROCDIE(actual_exi_condition);
}
diff --git a/sr_unix/gtm_ipc.h b/sr_unix/gtm_ipc.h
index a76c82d..7e09c0f 100644
--- a/sr_unix/gtm_ipc.h
+++ b/sr_unix/gtm_ipc.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Serivces, Inc *
+ * Copyright 2001, 2014 Fidelity Information Serivces, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -39,4 +39,8 @@
key_t gtm_ftok(const char *path, int id);
+#define IPC_REMOVED(ERRNO) ((EINVAL == ERRNO) || (EIDRM == ERRNO)) /* EIDRM is only on Linux */
+#define SEM_REMOVED(ERRNO) IPC_REMOVED(ERRNO)
+#define SHM_REMOVED(ERRNO) IPC_REMOVED(ERRNO)
+
#endif
diff --git a/sr_unix/gtm_logicals.h b/sr_unix/gtm_logicals.h
index 1a01a22..812431d 100644
--- a/sr_unix/gtm_logicals.h
+++ b/sr_unix/gtm_logicals.h
@@ -16,14 +16,15 @@
#define GTM_DIST_LOG "$gtm_dist"
/* Database */
-#define GTM_GBLDIR "$gtmgbldir"
#define GTM_BLKUPGRADE_FLAG "$gtm_blkupgrade_flag"
#define GTM_DBFILEXT_SYSLOG_DISABLE "$gtm_dbfilext_syslog_disable"
#define GTM_ENV_XLATE "$gtm_env_translate"
#define GTM_FULLBLOCKWRITES "$gtm_fullblockwrites"
#define GTM_GDSCERT "$gtm_gdscert"
#define GTM_GVDUPSETNOOP "$gtm_gvdupsetnoop"
+#define GTM_GBLDIR "$gtmgbldir"
#define GTM_GVUNDEF_FATAL "$gtm_gvundef_fatal"
+#define GTM_POOLLIMIT "$gtm_poollimit"
#define GTM_TP_ALLOCATION_CLUE "$gtm_tp_allocation_clue"
#define GTM_TPNOTACIDTIME "$gtm_tpnotacidtime"
#define GTM_TPRESTART_LOG_DELTA "$gtm_tprestart_log_delta"
@@ -85,7 +86,6 @@
/* Database */
#define GTM_TMP_ENV "$gtm_tmp"
-#define GTM_SHMFLAGS "$gtm_shmatflags"
#define GTM_TRIGGER_ETRAP "$gtm_trigger_etrap"
#define GTM_SNAPTMPDIR "$gtm_snaptmpdir"
#define GTM_DB_STARTUP_MAX_WAIT "$gtm_db_startup_max_wait"
@@ -113,6 +113,8 @@
/* [Auto]Relink related */
#define GTM_LINK "$gtm_link"
#define GTM_LINKTMPDIR "$gtm_linktmpdir"
+#define GTM_AUTORELINK_SHM "$gtm_autorelink_shm"
+#define GTM_AUTORELINK_KEEPRTN "$gtm_autorelink_keeprtn" /* do not let go of objects in rtnobj shm */
/* Miscellaneous */
#define GTM_ERROR_ON_JNL_FILE_LOST "$gtm_error_on_jnl_file_lost"
diff --git a/sr_unix/gtm_permissions.c b/sr_unix/gtm_permissions.c
index e4d5ab9..9fc30a3 100644
--- a/sr_unix/gtm_permissions.c
+++ b/sr_unix/gtm_permissions.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2009, 2013 Fidelity Information Services, Inc *
+ * Copyright 2009, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -137,7 +137,7 @@ int gtm_permissions(struct stat *stat_buff, int *user_id, int *group_id, int *pe
/* set no permissions as a default in case none of our conditions match */
*perm = 0;
- assertpro((PERM_FILE == target_type) || (PERM_IPC == target_type));
+ assertpro((PERM_FILE & target_type) || (PERM_IPC & target_type));
if (0006 & stat_buff->st_mode)
{
/* file is accessible to other */
@@ -145,10 +145,10 @@ int gtm_permissions(struct stat *stat_buff, int *user_id, int *group_id, int *pe
*user_id = stat_buff->st_uid;
if (opener_in_file_group || opener_is_root) /* otherwise, use default gid */
*group_id = stat_buff->st_gid;
- if (PERM_FILE == target_type)
+ if (PERM_FILE & target_type)
*perm = (!opener_in_file_group && !opener_is_root && (0020 & stat_buff->st_mode))
? 0666 : (stat_buff->st_mode & 0666);
- else if (PERM_IPC == target_type)
+ else if (PERM_IPC & target_type)
*perm = 0666;
} else if (0600 & stat_buff->st_mode && !(0066 & stat_buff->st_mode))
{
@@ -160,9 +160,9 @@ int gtm_permissions(struct stat *stat_buff, int *user_id, int *group_id, int *pe
*user_id = stat_buff->st_uid;
*group_id = stat_buff->st_gid;
}
- if (PERM_FILE == target_type)
+ if (PERM_FILE & target_type)
*perm = 0600; /* read write for user */
- else if (PERM_IPC == target_type)
+ else if (PERM_IPC & target_type)
*perm = 0600; /* read write for user */
} else if (0060 & stat_buff->st_mode && !(0606 & stat_buff->st_mode))
{
@@ -171,9 +171,9 @@ int gtm_permissions(struct stat *stat_buff, int *user_id, int *group_id, int *pe
*user_id = stat_buff->st_uid;
*group_id = stat_buff->st_gid; /* use file group */
assert(opener_in_file_group || opener_is_root);
- if (PERM_FILE == target_type)
+ if (PERM_FILE & target_type)
*perm = stat_buff->st_mode & 0060; /* use file permissions, masked for group read/write */
- if (PERM_IPC == target_type)
+ if (PERM_IPC & target_type)
*perm = 0660; /* read/write for group - all readers need write for ipc */
} else
{
@@ -183,9 +183,9 @@ int gtm_permissions(struct stat *stat_buff, int *user_id, int *group_id, int *pe
if (opener_is_root) /* otherwise, use default uid */
*user_id = stat_buff->st_uid;
*group_id = stat_buff->st_gid; /* use file group */
- if (PERM_FILE == target_type)
+ if (PERM_FILE & target_type)
*perm = stat_buff->st_mode & 0660; /* use file permissions, masked for user/group read/write */
- if (PERM_IPC == target_type)
+ if (PERM_IPC & target_type)
*perm = 0660; /* read/write for user/group - all readers need write for ipc */
} else
{
@@ -195,16 +195,16 @@ int gtm_permissions(struct stat *stat_buff, int *user_id, int *group_id, int *pe
{
*group_id = lib_gid; /* use restricted group */
assert(gtm_member_group_id(process_uid, *group_id));
- if (PERM_FILE == target_type)
+ if (PERM_FILE & target_type)
*perm = 0660; /* user/group read/write */
- if (PERM_IPC == target_type)
+ if (PERM_IPC & target_type)
*perm = 0660; /* read/write for user/group - all readers need write for ipc */
} else
{
/* use default group */
- if (PERM_FILE == target_type)
+ if (PERM_FILE & target_type)
*perm = 0666; /* read/write for all */
- else if (PERM_IPC == target_type)
+ else if (PERM_IPC & target_type)
*perm = 0666; /* read/write for all - all readers need write for ipc */
}
} else if (!opener_is_file_owner && opener_in_file_group)
@@ -213,31 +213,34 @@ int gtm_permissions(struct stat *stat_buff, int *user_id, int *group_id, int *pe
if (owner_in_file_group)
{
*group_id = stat_buff->st_gid; /* use file group */
- if (PERM_FILE == target_type)
+ if (PERM_FILE & target_type)
*perm = stat_buff->st_mode & 0660; /* use masked file permissions */
- if (PERM_IPC == target_type)
+ if (PERM_IPC & target_type)
*perm = 0660; /* read/write for user/group - all readers need write for ipc */
} else if (gtm_group_restricted)
{
*group_id = lib_gid; /* use restricted group */
assert(gtm_member_group_id(process_uid, *group_id));
- if (PERM_FILE == target_type)
+ if (PERM_FILE & target_type)
*perm = 0660; /* user/group read/write */
- if (PERM_IPC == target_type)
+ if (PERM_IPC & target_type)
*perm = 0660; /* read/write for user/group - all readers need write for ipc */
} else
{
*group_id = stat_buff->st_gid; /* use file group */
- if (PERM_FILE == target_type)
+ if (PERM_FILE & target_type)
*perm = 0666; /* read/write for all - ensure file owner read/write access */
- else if (PERM_IPC == target_type)
+ else if (PERM_IPC & target_type)
*perm = 0666; /* read/write for all - all readers need write for ipc */
}
}
}
}
+ if (target_type & PERM_EXEC)
+ *perm |= ((*perm & 0444) >> 2); /* Grab the read bits, shift them to the exec bit position, and add them back in. */
+
/* if we never set *perm, return error value */
if (*perm == 0)
{
diff --git a/sr_unix/gtm_permissions.h b/sr_unix/gtm_permissions.h
index cc37088..91a9e70 100644
--- a/sr_unix/gtm_permissions.h
+++ b/sr_unix/gtm_permissions.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2009, 2013 Fidelity Information Services, Inc *
+ * Copyright 2009, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -16,8 +16,9 @@
enum perm_target_types
{
- PERM_FILE, /* request permissions for creating a new file */
- PERM_IPC /* request permissions for initializing IPCs (shm/sem) */
+ PERM_FILE = 0x01, /* request permissions for creating a new file */
+ PERM_IPC = 0x02, /* request permissions for initializing IPCs (shm/sem) */
+ PERM_EXEC = 0x80 /* request execute permissions, masked with the above */
};
struct perm_diag_data
diff --git a/sr_unix/gtm_semutils.h b/sr_unix/gtm_semutils.h
index fefc96b..f64f44c 100644
--- a/sr_unix/gtm_semutils.h
+++ b/sr_unix/gtm_semutils.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2011, 2013 Fidelity Information Services, Inc *
+ * Copyright 2011, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -71,7 +71,7 @@ boolean_t do_blocking_semop(int semid, enum gtm_semtype semtype, uint4 start_hrt
\
lcl_msgstr = (gtm_ftok_sem == SEMTYPE) ? "SEMWT2LONG_FTOK_SUCCEEDED: semop for the ftok semaphore succeeded" \
: "SEMWT2LONG_ACCSEM_SUCCEEDED: semop for the ftok semaphore succeeded"; \
- send_msg(VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_STR(lcl_msgstr)); \
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_STR(lcl_msgstr)); \
} \
}
@@ -124,7 +124,7 @@ boolean_t do_blocking_semop(int semid, enum gtm_semtype semtype, uint4 start_hrt
rts_error(VARLSTCNT(11) DBFILERR_PARAMS(REG), CRITSEMFAIL_PARAMS(REG), \
SEMKEYINUSE_PARAMS(UDI)); \
} else \
- GTMASSERT; \
+ assertpro(FALSE); \
} else if (ERR_MAXSEMGETRETRY == RETSTAT->status2) \
{ \
rts_error(VARLSTCNT(7) DBFILERR_PARAMS(REG), ERR_MAXSEMGETRETRY, 1, MAX_SEMGET_RETRIES); \
@@ -140,7 +140,7 @@ boolean_t do_blocking_semop(int semid, enum gtm_semtype semtype, uint4 start_hrt
rts_error(VARLSTCNT(13) DBFILERR_PARAMS(REG), \
SEMWT2LONG_PARAMS(REG, RETSTAT, GTM_SEMTYPE, tot_wait_time)); \
} else \
- GTMASSERT; \
+ assertpro(FALSE); \
}
/* Set the value of semaphore number 2 ( = FTOK_SEM_PER_ID - 1) as GTM_ID. This way, in case of an orphaned
@@ -184,6 +184,4 @@ boolean_t do_blocking_semop(int semid, enum gtm_semtype semtype, uint4 start_hrt
return FALSE; \
}
-#define SEM_REMOVED(ERRNO) ((EINVAL == ERRNO) || (EIDRM == ERRNO)) /* EIDRM is only on Linux */
-
#endif /* GTM_SEMUTILS_H */
diff --git a/sr_unix/gtm_startup.c b/sr_unix/gtm_startup.c
index 0ded3c0..5d674b4 100644
--- a/sr_unix/gtm_startup.c
+++ b/sr_unix/gtm_startup.c
@@ -59,7 +59,6 @@
#include "generic_signal_handler.h"
#include "init_secshr_addrs.h"
#include "zcall_package.h"
-#include "geteditor.h"
#include "getzdir.h"
#include "getzmode.h"
#include "getzprocess.h"
@@ -92,6 +91,8 @@
#include "heartbeat_timer.h"
#include "gt_timers_add_safe_hndlrs.h"
#include "continue_handler.h"
+#include "jobsp.h" /* For gcall.h */
+#include "gcall.h" /* For ojchildparms() */
GBLDEF void (*restart)() = &mum_tstart;
#ifdef __MVS__
@@ -217,7 +218,6 @@ void gtm_startup(struct startup_vector *svec)
INVOKE_INIT_SECSHR_ADDRS;
getzprocess();
getzmode();
- geteditor();
zcall_init();
cmd_qlf.qlf = glb_cmd_qlf.qlf;
cache_init();
@@ -309,7 +309,13 @@ void gtm_startup(struct startup_vector *svec)
assert(FALSE == curr_symval->alias_activity);
curr_symval->alias_activity = TRUE;
lvzwr_init((enum zwr_init_types)0, (mval *)NULL);
+ TREF(in_zwrite) = FALSE;
curr_symval->alias_activity = FALSE;
+ if ((GTM_IMAGE == image_type) && (NULL != svec->base_addr))
+ /* We are in the grandchild at this point. This call is made to greet local variables sent from the midchild. There
+ * is no symbol table for locals before this point so we have to greet them here, after creating the symbol table.
+ */
+ ojchildparms(NULL, NULL, NULL);
if ((NULL != (TREF(mprof_env_gbl_name)).str.addr))
turn_tracing_on(TADR(mprof_env_gbl_name), TRUE, (TREF(mprof_env_gbl_name)).str.len > 0);
return;
diff --git a/sr_unix/gtm_stdio.h b/sr_unix/gtm_stdio.h
index 3b63fbd..5db6e5d 100644
--- a/sr_unix/gtm_stdio.h
+++ b/sr_unix/gtm_stdio.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2013 Fidelity Information Services, Inc *
+ * Copyright 2010, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -22,15 +22,23 @@
#include <stdio.h>
+#ifdef UNIX
/* If interrupted, this function has previously caused hangs to do a subsequent gtm_putmsg() invocation from
- * generic_signal_handler(), so just defer interrupts to be safe.
+ * generic_signal_handler(), so just defer interrupts to be safe. UNIX is a GT.M-specific compiler switch, which
+ * we expect to be undefined for any non-GT.M compilation that might include this file.
*/
-#define FDOPEN(VAR, FILE_DES, MODE) \
+# define FDOPEN(VAR, FILE_DES, MODE) \
{ \
DEFER_INTERRUPTS(INTRPT_IN_FDOPEN); \
VAR = fdopen(FILE_DES, MODE); \
ENABLE_INTERRUPTS(INTRPT_IN_FDOPEN); \
}
+#else
+# define FDOPEN(VAR, FILE_DES, MODE) \
+{ \
+ VAR = fdopen(FILD_DES, MODE); \
+}
+#endif
#define FGETS(strg, n, strm, fgets_res) (fgets_res = fgets(strg,n,strm))
#define Fopen fopen
diff --git a/sr_unix/gtm_tls.h b/sr_unix/gtm_tls.h
index 6a26e8e..d68e183 100644
--- a/sr_unix/gtm_tls.h
+++ b/sr_unix/gtm_tls.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2013 Fidelity Information Services, Inc *
+ * Copyright 2013, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -9,8 +9,8 @@
* *
****************************************************************/
-#ifndef _GTM_TLS_H
-#define _GTM_TLS_H
+#ifndef GTM_TLS_H
+#define GTM_TLS_H
#define gtm_tls_get_error (*gtm_tls_get_error_fptr)
#define gtm_tls_errno (*gtm_tls_errno_fptr)
@@ -70,7 +70,7 @@
#define gtm_tls_session_close intrsafe_gtm_tls_session_close
#define gtm_tls_fini intrsafe_gtm_tls_fini
-#undef _GTM_TLS_INTERFACE_H /* Allows us to include gtm_tls_interface.h twice. */
+#undef GTM_TLS_INTERFACE_H /* Allows us to include gtm_tls_interface.h twice. */
#include "gtm_tls_interface.h" /* BYPASSOK : intentional duplicate include. */
GBLREF gtm_tls_ctx_t *tls_ctx;
diff --git a/sr_unix/gtm_tls_impl.c b/sr_unix/gtm_tls_impl.c
index 920e345..10e53c5 100644
--- a/sr_unix/gtm_tls_impl.c
+++ b/sr_unix/gtm_tls_impl.c
@@ -49,7 +49,186 @@ STATICDEF DH *dh512, *dh1024; /* Diffie-Hellman structures for Ephemeral Diffi
* EXP: Export Ciphers.
* MD5 : MD5 message digest.
*/
-#define CIPHER_LIST "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"
+#define REPL_CIPHER_LIST "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"
+
+#define OPTIONEND ':'
+#define OPTIONENDSTR ":"
+#define OPTIONNOT '!'
+#define DEFINE_SSL_OP(OP_DEF) { #OP_DEF , OP_DEF }
+struct gtm_ssl_options
+{
+ const char *opt_str;
+ long opt_val;
+};
+STATICDEF struct gtm_ssl_options gtm_ssl_verify_mode_list[] =
+{
+ DEFINE_SSL_OP(SSL_VERIFY_PEER),
+ DEFINE_SSL_OP(SSL_VERIFY_NONE),
+ DEFINE_SSL_OP(SSL_VERIFY_FAIL_IF_NO_PEER_CERT),
+ DEFINE_SSL_OP(SSL_VERIFY_CLIENT_ONCE),
+ {NULL, 0}
+};
+STATICDEF struct gtm_ssl_options gtm_ssl_options_list[] =
+{
+#ifdef SSL_OP_MICROSOFT_SESS_ID_BUG
+ DEFINE_SSL_OP(SSL_OP_MICROSOFT_SESS_ID_BUG),
+#endif
+#ifdef SSL_OP_NETSCAPE_CHALLENGE_BUG
+ DEFINE_SSL_OP(SSL_OP_NETSCAPE_CHALLENGE_BUG),
+#endif
+#ifdef SSL_OP_LEGACY_SERVER_CONNECT
+ DEFINE_SSL_OP(SSL_OP_LEGACY_SERVER_CONNECT),
+#endif
+#ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
+ DEFINE_SSL_OP(SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG),
+#endif
+#ifdef SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG
+ DEFINE_SSL_OP(SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG),
+#endif
+#ifdef SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER
+ DEFINE_SSL_OP(SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER),
+#endif
+#ifdef SSL_OP_SAFARI_ECDHE_ECDSA_BUG
+ DEFINE_SSL_OP(SSL_OP_SAFARI_ECDHE_ECDSA_BUG),
+#endif
+#ifdef SSL_OP_SSLEAY_080_CLIENT_DH_BUG
+ DEFINE_SSL_OP(SSL_OP_SSLEAY_080_CLIENT_DH_BUG),
+#endif
+#ifdef SSL_OP_TLS_D5_BUG
+ DEFINE_SSL_OP(SSL_OP_TLS_D5_BUG),
+#endif
+#ifdef SSL_OP_TLS_BLOCK_PADDING_BUG
+ DEFINE_SSL_OP(SSL_OP_TLS_BLOCK_PADDING_BUG),
+#endif
+#ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING
+ DEFINE_SSL_OP(SSL_OP_MSIE_SSLV2_RSA_PADDING),
+#endif
+#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
+ DEFINE_SSL_OP(SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS),
+#endif
+#ifdef SSL_OP_ALL
+ DEFINE_SSL_OP(SSL_OP_ALL),
+#endif
+#ifdef SSL_OP_NO_QUERY_MTU
+ DEFINE_SSL_OP(SSL_OP_NO_QUERY_MTU),
+#endif
+#ifdef SSL_OP_COOKIE_EXCHANGE
+ DEFINE_SSL_OP(SSL_OP_COOKIE_EXCHANGE),
+#endif
+#ifdef SSL_OP_NO_TICKET
+ DEFINE_SSL_OP(SSL_OP_NO_TICKET),
+#endif
+#ifdef SSL_OP_CISCO_ANYCONNECT
+ DEFINE_SSL_OP(SSL_OP_CISCO_ANYCONNECT),
+#endif
+#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
+ DEFINE_SSL_OP(SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION),
+#endif
+#ifdef SSL_OP_NO_COMPRESSION
+ DEFINE_SSL_OP(SSL_OP_NO_COMPRESSION),
+#endif
+#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
+ DEFINE_SSL_OP(SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION),
+#endif
+#ifdef SSL_OP_SINGLE_ECDH_USE
+ DEFINE_SSL_OP(SSL_OP_SINGLE_ECDH_USE),
+#endif
+#ifdef SSL_OP_SINGLE_DH_USE
+ DEFINE_SSL_OP(SSL_OP_SINGLE_DH_USE),
+#endif
+#ifdef SSL_OP_EPHEMERAL_RSA
+ DEFINE_SSL_OP(SSL_OP_EPHEMERAL_RSA),
+#endif
+#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
+ DEFINE_SSL_OP(SSL_OP_CIPHER_SERVER_PREFERENCE),
+#endif
+#ifdef SSL_OP_TLS_ROLLBACK_BUG
+ DEFINE_SSL_OP(SSL_OP_TLS_ROLLBACK_BUG),
+#endif
+#ifdef SSL_OP_NO_SSLv2
+ DEFINE_SSL_OP(SSL_OP_NO_SSLv2),
+#endif
+#ifdef SSL_OP_NO_SSLv3
+ DEFINE_SSL_OP(SSL_OP_NO_SSLv3),
+#endif
+#ifdef SSL_OP_NO_TLSv1
+ DEFINE_SSL_OP(SSL_OP_NO_TLSv1),
+#endif
+#ifdef SSL_OP_NO_TLSv1_2
+ DEFINE_SSL_OP(SSL_OP_NO_TLSv1_2),
+#endif
+#ifdef SSL_OP_NO_TLSv1_1
+ DEFINE_SSL_OP(SSL_OP_NO_TLSv1_1),
+#endif
+#ifdef SSL_OP_PKCS1_CHECK_1
+ DEFINE_SSL_OP(SSL_OP_PKCS1_CHECK_1),
+#endif
+#ifdef SSL_OP_PKCS1_CHECK_2
+ DEFINE_SSL_OP(SSL_OP_PKCS1_CHECK_2),
+#endif
+#ifdef SSL_OP_NETSCAPE_CA_DN_BUG
+ DEFINE_SSL_OP(SSL_OP_NETSCAPE_CA_DN_BUG),
+#endif
+#ifdef SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG
+ DEFINE_SSL_OP(SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG),
+#endif
+#ifdef SSL_OP_CRYPTOPRO_TLSEXT_BUG
+ DEFINE_SSL_OP(SSL_OP_CRYPTOPRO_TLSEXT_BUG),
+#endif
+ {NULL, 0}
+};
+
+STATICDEF long parse_SSL_options(struct gtm_ssl_options *opt_table, size_t opt_table_size, const char *options, long current,
+ long *clear);
+STATICDEF long parse_SSL_options(struct gtm_ssl_options *opt_table, size_t opt_table_size, const char *options, long current,
+ long *clear)
+{
+ int negate;
+ size_t num_options, index, optionlen;
+ long bitmask;
+ const char *charptr, *optionend;
+
+ if (NULL == options)
+ return 0;
+ negate = 0;
+ bitmask = current;
+ num_options = opt_table_size/SIZEOF(struct gtm_ssl_options);
+ for (charptr = options; *charptr; charptr = optionend)
+ {
+ if (OPTIONEND == *charptr)
+ if ('\0' == *++charptr)
+ break;
+ optionend = strstr((const char *)charptr, OPTIONENDSTR);
+ if (NULL == optionend)
+ optionend = charptr + strlen(charptr);
+ if (OPTIONNOT == *charptr)
+ {
+ negate = TRUE;
+ charptr++;
+ } else
+ negate = FALSE;
+ optionlen = optionend - charptr;
+ for (index = 0; num_options > index ; index++)
+ {
+ if (NULL == opt_table[index].opt_str)
+ break;
+ if (0 == strncmp(opt_table[index].opt_str, charptr, optionlen))
+ {
+ if (negate)
+ {
+ bitmask &= ~opt_table[index].opt_val;
+ if (NULL != clear)
+ *clear |= opt_table[index].opt_val;
+ } else
+ bitmask |= opt_table[index].opt_val;
+ break;
+ }
+ }
+ if (num_options <= index)
+ ; /* option not found - ignore */
+ }
+ return bitmask;
+}
#ifdef DEBUG_SSL
#define SSL_DPRINT(FP, ...) {fprintf(FP, __VA_ARGS__); fflush(FP);} /* BYPASSOK -- cannot use FFLUSH. */
@@ -206,6 +385,8 @@ STATICFNDEF int init_dhparams(void)
int rv1, rv2;
const char *dh512_fn, *dh1024_fn;
+ if (dh1024)
+ return 0; /* already have */
rv1 = config_lookup_string(>m_tls_cfg, "tls.dh512", &dh512_fn);
rv2 = config_lookup_string(>m_tls_cfg, "tls.dh1024", &dh1024_fn);
if (!rv1 && !rv2)
@@ -229,7 +410,7 @@ STATICFNDEF int init_dhparams(void)
STATICFNDEF DH *tmp_dh_callback(SSL *ssl, int is_export, int keylength)
{
- assert(dh512 && dh1024 && (512 <= keylength));
+ assert(dh512 && dh1024 && ((512 == keylength) || (1024 == keylength)));
return (512 == keylength) ? dh512 : dh1024;
}
@@ -245,14 +426,15 @@ const char *gtm_tls_get_error(void)
gtm_tls_ctx_t *gtm_tls_init(int version, int flags)
{
- const char *CAfile = NULL, *CApath = NULL, *crl, *CAptr;
+ const char *CAfile = NULL, *CApath = NULL, *crl, *CAptr, *cipher_list, *options_string, *verify_mode_string;
char *config_env;
- int rv, rv1, rv2, fips_requested, fips_enabled;
+ int rv, rv1, rv2, fips_requested, fips_enabled, verify_mode;
# if (((LIBCONFIG_VER_MAJOR == 1) && (LIBCONFIG_VER_MINOR >= 4)) || (LIBCONFIG_VER_MAJOR > 1))
int verify_depth, session_timeout;
# else
long int verify_depth, session_timeout;
# endif
+ long options_mask, options_current, options_clear;
SSL_CTX *ctx;
X509_STORE *store;
X509_LOOKUP *lookup;
@@ -274,8 +456,6 @@ gtm_tls_ctx_t *gtm_tls_init(int version, int flags)
return NULL; /* Relevant error detail populated in the above macro. */
}
OpenSSL_add_all_algorithms();
- OpenSSL_add_all_ciphers();
- OpenSSL_add_all_digests();
/* Setup function pointers to symbols exported by libgtmshr.so. */
if (0 != gc_load_gtmshr_symbols())
return NULL;
@@ -308,6 +488,13 @@ gtm_tls_ctx_t *gtm_tls_init(int version, int flags)
/* Get global SSL configuration parameters */
if (config_lookup_int(cfg, "tls.verify-depth", &verify_depth))
SSL_CTX_set_verify_depth(ctx, verify_depth);
+ if (CONFIG_TRUE == config_lookup_string(cfg, "tls.verify-mode", &verify_mode_string))
+ {
+ verify_mode = (int)parse_SSL_options(>m_ssl_verify_mode_list[0], SIZEOF(gtm_ssl_verify_mode_list),
+ verify_mode_string, (long)0, NULL);
+ SSL_CTX_set_verify(ctx, verify_mode, NULL);
+ } else
+ flags |= GTMTLS_OP_ABSENT_VERIFYMODE;
rv1 = config_lookup_string(cfg, "tls.CAfile", &CAfile);
rv2 = config_lookup_string(cfg, "tls.CApath", &CApath);
/* Setup trust locations for peer verifications. This adds on to any trust locations that was previously loaded. */
@@ -375,25 +562,43 @@ gtm_tls_ctx_t *gtm_tls_init(int version, int flags)
SSL_CTX_set_timeout(ctx, session_timeout);
} else
SSL_CTX_set_timeout(ctx, DEFAULT_SESSION_TIMEOUT);
- if (0 >= SSL_CTX_set_cipher_list(ctx, CIPHER_LIST))
+ if (CONFIG_FALSE == config_lookup_string(cfg, "tls.cipher-list", &cipher_list))
+ cipher_list = NULL;
+ else if (('\0' != cipher_list[0]) && (0 >= SSL_CTX_set_cipher_list(ctx, cipher_list)))
{
- GC_APPEND_OPENSSL_ERROR("Failed to add Cipher-List command string: %s.", CIPHER_LIST);
+ GC_APPEND_OPENSSL_ERROR("Failed to add Cipher-List command string: %s.", cipher_list);
SSL_CTX_free(ctx);
config_destroy(cfg);
return NULL;
+ } /* use OpenSSL default */
+ if (CONFIG_TRUE == config_lookup_string(cfg, "tls.ssl-options", &options_string))
+ {
+ options_current = SSL_CTX_get_options(ctx);
+ options_clear = 0;
+ options_mask = parse_SSL_options(>m_ssl_options_list[0], SIZEOF(gtm_ssl_options_list), options_string,
+ options_current, &options_clear);
+ if (0 != options_mask)
+ options_mask = SSL_CTX_set_options(ctx, options_mask);
+ if (0 != options_clear)
+ options_mask = SSL_CTX_clear_options(ctx, options_clear);
}
gtm_tls_ctx = MALLOC(SIZEOF(gtm_tls_ctx_t));
gtm_tls_ctx->ctx = ctx;
+ if (NULL == cipher_list)
+ flags |= GTMTLS_OP_ABSENT_CIPHER;
+ else if ('\0' == cipher_list[0])
+ flags |= GTMTLS_OP_DEFAULT_CIPHER;
gtm_tls_ctx->flags = flags;
gtm_tls_ctx->fips_mode = fips_enabled;
gtm_tls_ctx->compile_time_version = OPENSSL_VERSION_NUMBER;
gtm_tls_ctx->runtime_version = SSLeay();
+ gtm_tls_ctx->version = version;
return gtm_tls_ctx;
}
void gtm_tls_prefetch_passwd(gtm_tls_ctx_t *tls_ctx, char *env_name)
{
- char *env_name_ptr, *env_value, prompt[256];
+ char *env_name_ptr, *env_value, prompt[GTM_PASSPHRASE_MAX_ASCII + 1];
gtmtls_passwd_list_t *pwent_node;
passwd_entry_t *pwent;
@@ -404,7 +609,7 @@ void gtm_tls_prefetch_passwd(gtm_tls_ctx_t *tls_ctx, char *env_name)
assert(PASSPHRASE_ENVNAME_MAX > STRLEN(env_name_ptr));
assert(SIZEOF(GTMTLS_PASSWD_ENV_PREFIX) - 1 < STRLEN(env_name_ptr));
env_name_ptr += (SIZEOF(GTMTLS_PASSWD_ENV_PREFIX) - 1);
- SNPRINTF(prompt, 256, "Enter passphrase for TLSID %s: ", env_name_ptr);
+ SNPRINTF(prompt, GTM_PASSPHRASE_MAX_ASCII, "Enter passphrase for TLSID %s: ", env_name_ptr);
pwent = NULL;
if (0 == gc_update_passwd(env_name, &pwent, prompt, TRUE))
{
@@ -420,10 +625,16 @@ void gtm_tls_prefetch_passwd(gtm_tls_ctx_t *tls_ctx, char *env_name)
gtm_tls_socket_t *gtm_tls_socket(gtm_tls_ctx_t *tls_ctx, gtm_tls_socket_t *prev_socket, int sockfd, char *id, int flags)
{
- int len;
- char cfg_path[MAX_CONFIG_LOOKUP_PATHLEN], input_env_name[PASSPHRASE_ENVNAME_MAX], *env_name_ptr;
- char prompt[256];
- const char *cert, *private_key, *format;
+ int len, verify_mode, verify_mode_set, nocert, nopkey;
+ long options_mask, options_current, options_clear;
+# if (((LIBCONFIG_VER_MAJOR == 1) && (LIBCONFIG_VER_MINOR >= 4)) || (LIBCONFIG_VER_MAJOR > 1))
+ int verify_depth, session_timeout;
+# else
+ long int verify_depth, session_timeout;
+# endif
+ char cfg_path[MAX_CONFIG_LOOKUP_PATHLEN], input_env_name[PASSPHRASE_ENVNAME_MAX + 1], *env_name_ptr;
+ char prompt[GTM_PASSPHRASE_MAX_ASCII + 1];
+ const char *cert, *private_key, *format, *cipher_list, *options_string, *verify_mode_string;
FILE *fp;
SSL *ssl;
SSL_CTX *ctx;
@@ -447,105 +658,191 @@ gtm_tls_socket_t *gtm_tls_socket(gtm_tls_ctx_t *tls_ctx, gtm_tls_socket_t *prev_
return NULL;
}
- if (VERIFY_PEER(flags))
+ if ('\0' != id[0])
+ {
+ SNPRINTF(cfg_path, MAX_CONFIG_LOOKUP_PATHLEN, "tls.%s.verify-mode", id);
+ if (CONFIG_TRUE == config_lookup_string(cfg, cfg_path, &verify_mode_string))
+ {
+ verify_mode = (int)parse_SSL_options(>m_ssl_verify_mode_list[0], SIZEOF(gtm_ssl_verify_mode_list),
+ verify_mode_string, (long)0, NULL);
+ if (SSL_VERIFY_PEER & verify_mode)
+ flags |= GTMTLS_OP_VERIFY_PEER;
+ verify_mode_set = TRUE;
+ } else if (GTMTLS_OP_ABSENT_VERIFYMODE & tls_ctx->flags)
+ {
+ verify_mode = (GTMTLS_OP_VERIFY_PEER & flags) ? SSL_VERIFY_PEER : SSL_VERIFY_NONE;
+ verify_mode_set = TRUE;
+ } else
+ verify_mode_set = FALSE;
+ SNPRINTF(cfg_path, MAX_CONFIG_LOOKUP_PATHLEN, "tls.%s.cipher-list", id);
+ if (CONFIG_TRUE == config_lookup_string(cfg, cfg_path, &cipher_list))
+ {
+ if ('\0' == cipher_list[0]) /* use default instead of tls.cipher-list if empty string */
+ cipher_list = (GTMTLS_OP_SOCKET_DEV & flags) ? SSL_DEFAULT_CIPHER_LIST : REPL_CIPHER_LIST;
+ } else
+ cipher_list = NULL;
+ } else if (!CLIENT_MODE(flags))
+ { /* server mode needs certificate and thus tlsid */
+ UPDATE_ERROR_STRING("Server mode requires a certificate but no TLSID specified");
+ SSL_free(ssl);
+ return NULL;
+ } else
+ {
+ assert(GTMTLS_OP_SOCKET_DEV & flags);
+ cipher_list = NULL;
+ if (GTMTLS_OP_ABSENT_VERIFYMODE & tls_ctx->flags)
+ {
+ verify_mode = (GTMTLS_OP_VERIFY_PEER & flags) ? SSL_VERIFY_PEER : SSL_VERIFY_NONE;
+ verify_mode_set = TRUE;
+ } else
+ verify_mode_set = FALSE;
+ }
+ if (verify_mode_set)
+ SSL_set_verify(ssl, verify_mode, NULL);
+ if (NULL == cipher_list)
+ { /* no cipher-list in labelled section or no section */
+ if (0 != ((GTMTLS_OP_ABSENT_CIPHER | GTMTLS_OP_DEFAULT_CIPHER) &tls_ctx->flags))
+ { /* no or default cipher specified top level */
+ cipher_list = (GTMTLS_OP_SOCKET_DEV & flags) ? SSL_DEFAULT_CIPHER_LIST : REPL_CIPHER_LIST;
+ }
+ }
+ if ((NULL != cipher_list) && (0 >= SSL_set_cipher_list(ssl, cipher_list)))
+ {
+ GC_APPEND_OPENSSL_ERROR("Failed to add Cipher-List command string: %s.", cipher_list);
+ SSL_free(ssl);
+ return NULL;
+ }
+ if ('\0' != id[0])
{
/* First lookup the certificate and private key associated with the provided id in the configuration file. */
SNPRINTF(cfg_path, MAX_CONFIG_LOOKUP_PATHLEN, "tls.%s.cert", id);
if (!config_lookup_string(cfg, cfg_path, &cert))
{
- UPDATE_ERROR_STRING("Certificate corresponding to TLSID: %s not found in configuration file.", id);
- SSL_free(ssl);
- return NULL;
- }
-
+ if (!CLIENT_MODE(flags))
+ {
+ UPDATE_ERROR_STRING("Certificate corresponding to TLSID: %s not found in configuration file.", id);
+ SSL_free(ssl);
+ return NULL;
+ } else
+ nocert = TRUE;
+ } else
+ nocert = FALSE;
SNPRINTF(cfg_path, MAX_CONFIG_LOOKUP_PATHLEN, "tls.%s.key", id);
- if (!config_lookup_string(cfg, cfg_path, &private_key))
+ if (config_lookup_string(cfg, cfg_path, &private_key))
{
- UPDATE_ERROR_STRING("Private Key corresponding to TLSID: %s not found in configuration file.", id);
- SSL_free(ssl);
- return NULL;
- }
-
+ if (nocert)
+ {
+ UPDATE_ERROR_STRING("Private key but no certificate corresponding to TLSID:"
+ " %s in configuration file.", id);
+ SSL_free(ssl);
+ return NULL;
+ }
+ } else if (!nocert)
+ private_key = cert; /* assume both in one file */
/* Verify that the format, if specified, is of PEM type as that's the only kind we support now. */
SNPRINTF(cfg_path, MAX_CONFIG_LOOKUP_PATHLEN, "tls.%s.format", id);
if (config_lookup_string(cfg, cfg_path, &format))
{
+ if (nocert)
+ {
+ UPDATE_ERROR_STRING("Format but no certificate corresponding to TLSID: %s in configuration file.",
+ id);
+ SSL_free(ssl);
+ return NULL;
+ }
if (((SIZEOF("PEM") - 1) != strlen(format))
- || (format[0] != 'P') || (format[1] != 'E') || (format[2] != 'M'))
+ || (format[0] != 'P') || (format[1] != 'E') || (format[2] != 'M'))
{
UPDATE_ERROR_STRING("Unsupported format type %s found for TLSID: %s.", format, id);
SSL_free(ssl);
return NULL;
}
}
- /* Setup the certificate to be used for this connection */
- if (!SSL_use_certificate_file(ssl, cert, SSL_FILETYPE_PEM))
+ if (!nocert)
{
- GC_APPEND_OPENSSL_ERROR("Failed to add certificate %s.", cert);
- SSL_free(ssl);
- return NULL;
- }
-
- /* Before setting up the private key, check-up on the password for the private key. */
- SNPRINTF(input_env_name, PASSPHRASE_ENVNAME_MAX, GTMTLS_PASSWD_ENV_PREFIX "%s", id);
- if (NULL != (pwent_node = gtmtls_passwd_listhead))
- { /* Lookup to see if we have already prefetched the password. */
- while (NULL != pwent_node)
+ /* Setup the certificate to be used for this connection */
+ if (!SSL_use_certificate_file(ssl, cert, SSL_FILETYPE_PEM))
{
- env_name_ptr = pwent_node->pwent->env_name;
- len = STRLEN(env_name_ptr);
- assert(len < PASSPHRASE_ENVNAME_MAX);
- assert(len > SIZEOF(GTMTLS_PASSWD_ENV_PREFIX) - 1);
- if ((len == STRLEN(input_env_name)) && (0 == strncmp(input_env_name, env_name_ptr, len)))
- break;
- pwent_node = pwent_node->next;
+ GC_APPEND_OPENSSL_ERROR("Failed to add certificate %s.", cert);
+ SSL_free(ssl);
+ return NULL;
}
- }
- if (NULL == pwent_node)
- { /* Lookup failed. Create a new entry for the given id. */
- pwent = NULL;
- SNPRINTF(prompt, 256, "Enter passphrase for TLSID %s:", id);
- if (0 != gc_update_passwd(input_env_name, &pwent, prompt, GTMTLS_OP_INTERACTIVE_MODE & tls_ctx->flags))
+ /* Before setting up the private key, check-up on the password for the private key. */
+ SNPRINTF(input_env_name, PASSPHRASE_ENVNAME_MAX, GTMTLS_PASSWD_ENV_PREFIX "%s", id);
+ if (NULL != (pwent_node = gtmtls_passwd_listhead))
+ { /* Lookup to see if we have already prefetched the password. */
+ while (NULL != pwent_node)
+ {
+ env_name_ptr = pwent_node->pwent->env_name;
+ len = STRLEN(env_name_ptr);
+ assert(len < PASSPHRASE_ENVNAME_MAX);
+ assert(len > SIZEOF(GTMTLS_PASSWD_ENV_PREFIX) - 1);
+ if ((len == STRLEN(input_env_name)) && (0 == strncmp(input_env_name, env_name_ptr, len)))
+ break;
+ pwent_node = pwent_node->next;
+ }
+ }
+ if (NULL == pwent_node)
+ { /* Lookup failed. Create a new entry for the given id. */
+ pwent = NULL;
+ SNPRINTF(prompt, GTM_PASSPHRASE_MAX_ASCII, "Enter passphrase for TLSID %s:", id);
+ if (0 != gc_update_passwd(input_env_name, &pwent, prompt, 0))
+ {
+ SSL_free(ssl);
+ return NULL;
+ }
+ pwent_node = MALLOC(SIZEOF(gtmtls_passwd_list_t));
+ pwent_node->next = gtmtls_passwd_listhead;
+ pwent_node->pwent = pwent;
+ gtmtls_passwd_listhead = pwent_node;
+ } else
+ pwent = pwent_node->pwent;
+ assert((NULL != pwent) && (NULL != pwent_node));
+ /* Setup the private key corresponding to the certificate and the callback function to obtain
+ * the password for the key. We cannot use the much simpler SSL_use_PrivateKey file to load
+ * the private key file because we want fine grained control on the password callback mechanism.
+ * For this purpose, use the PEM_read_PrivateKey function which
+ * supports callbacks for individual private keys.
+ */
+ fp = fopen(private_key, "r");
+ if (NULL != fp)
{
+ evp_pkey = PEM_read_PrivateKey(fp, &evp_pkey, &passwd_callback, pwent);
+ fclose(fp);
+ } else
+ evp_pkey = NULL;
+ if (NULL == evp_pkey)
+ {
+ if (NULL == fp)
+ {
+ UPDATE_ERROR_STRING("Private Key corresponding to TLSID:"
+ " %s - error opening file %s: %s.", id, private_key, strerror(errno));
+ } else if (ERR_GET_REASON(ERR_peek_error()) == PEM_R_NO_START_LINE)
+ { /* give clearer error if only cert given but it doesn't have the key */
+ UPDATE_ERROR_STRING("Private Key corresponding to TLSID:"
+ " %s not found in configuration file.", id);
+ } else
+ {
+ GC_APPEND_OPENSSL_ERROR("Failed to read private key %s.", private_key);
+ }
+ SSL_free(ssl);
+ return NULL;
+ }
+ if (!SSL_use_PrivateKey(ssl, evp_pkey))
+ {
+ GC_APPEND_OPENSSL_ERROR("Failed to use private key %s.", private_key);
+ SSL_free(ssl);
+ return NULL;
+ }
+ /* Verify that private key matches the certificate */
+ if (!SSL_check_private_key(ssl))
+ {
+ GC_APPEND_OPENSSL_ERROR("Consistency check failed for private key: %s and certificate: %s\n",
+ private_key, cert);
SSL_free(ssl);
return NULL;
}
- pwent_node = MALLOC(SIZEOF(gtmtls_passwd_list_t));
- pwent_node->next = gtmtls_passwd_listhead;
- pwent_node->pwent = pwent;
- gtmtls_passwd_listhead = pwent_node;
- } else
- pwent = pwent_node->pwent;
- assert((NULL != pwent) && (NULL != pwent_node));
- /* Setup the private key corresponding to the certificate and the callback function to obtain the password for the
- * key. We cannot use the much simpler SSL_use_PrivateKey file to load the private key file because we want fine
- * grained control on the password callback mechanism. For this purpose, use the PEM_read_PrivateKey function which
- * supports callbacks for individual private keys.
- */
- fp = fopen(private_key, "r");
- evp_pkey = PEM_read_PrivateKey(fp, &evp_pkey, &passwd_callback, pwent);
- fclose(fp); /* Close the file irrespective of whether the above function succeeded or failed. */
- if (NULL == evp_pkey)
- {
- GC_APPEND_OPENSSL_ERROR("Failed to read private key %s.", private_key);
- SSL_free(ssl);
- return NULL;
- }
- if (!SSL_use_PrivateKey(ssl, evp_pkey))
- {
- GC_APPEND_OPENSSL_ERROR("Failed to use private key %s.", private_key);
- SSL_free(ssl);
- return NULL;
- }
- /* Verify that private key matches the certificate */
- if (!SSL_check_private_key(ssl))
- {
- GC_APPEND_OPENSSL_ERROR("Consistency check failed for private key: %s and certificate: %s\n",
- private_key, cert);
- SSL_free(ssl);
- return NULL;
}
- SSL_set_verify(ssl, SSL_VERIFY_PEER, NULL);
}
/* OpenSSL does not recommend enabling compression as the current state of the SSL/TLS protocol does not specify identifiers
* for compression libraries thereby allowing for incompatibilities when different SSL/TLS implementations are used in the
@@ -561,7 +858,26 @@ gtm_tls_socket_t *gtm_tls_socket(gtm_tls_ctx_t *tls_ctx, gtm_tls_socket_t *prev_
compression = SSL_COMP_get_compression_methods();
sk_SSL_COMP_zero(compression);
# endif
- if (0 == (GTMTLS_OP_CLIENT_MODE & flags))
+ if ('\0' != id[0])
+ {
+ SNPRINTF(cfg_path, MAX_CONFIG_LOOKUP_PATHLEN, "tls.%s.ssl-options", id);
+ if (CONFIG_TRUE == config_lookup_string(cfg, cfg_path, &options_string))
+ {
+ options_current = SSL_get_options(ssl);
+ options_clear = 0;
+ options_mask = parse_SSL_options(>m_ssl_options_list[0], SIZEOF(gtm_ssl_options_list), options_string,
+ options_current, &options_clear);
+ if (0 != options_mask)
+ options_mask = SSL_set_options(ssl, options_mask);
+ if (0 != options_clear)
+ options_mask = SSL_clear_options(ssl, options_clear);
+
+ }
+ SNPRINTF(cfg_path, MAX_CONFIG_LOOKUP_PATHLEN, "tls.%s.verify-depth", id);
+ if (CONFIG_TRUE == config_lookup_int(cfg, cfg_path, &verify_depth))
+ SSL_set_verify_depth(ssl, verify_depth);
+ }
+ if (!CLIENT_MODE(flags))
{ /* Socket created for server mode operation. Set a session ID context for session resumption at the time of
* reconnection.
*/
@@ -572,10 +888,10 @@ gtm_tls_socket_t *gtm_tls_socket(gtm_tls_ctx_t *tls_ctx, gtm_tls_socket_t *prev_
return NULL;
}
/* Set up Ephemeral Diffie-Hellman key exchange callback. This callback is invoked whenever, during the connection
- * time, OpenSSL requires Diffie-Hellman key parameters. The SSL_OP_SINGLE_DH_USE is turned on so that the same
- * private key is not used for each session. This means a little extra computation during the time of handshake, but
- * is recommended by the OpenSSL community.
- */
+ * time, OpenSSL requires Diffie-Hellman key parameters. The SSL_OP_SINGLE_DH_USE is turned on so that the same
+ * private key is not used for each session. This means a little extra computation during the time of handshake, but
+ * is recommended by the OpenSSL community.
+ */
if (-1 == init_dhparams())
{
SSL_free(ssl);
@@ -602,6 +918,8 @@ gtm_tls_socket_t *gtm_tls_socket(gtm_tls_ctx_t *tls_ctx, gtm_tls_socket_t *prev_
socket = prev_socket;
socket->flags = flags;
socket->ssl = ssl;
+ socket->gtm_ctx = tls_ctx;
+ strncpy(socket->tlsid, (const char *)id, SIZEOF(socket->tlsid));
/* Now, store the `socket' structure in the `SSL' structure so that we can get it back in a callback that receives an
* `SSL' structure. Ideally, we should be using SSL_set_ex_data/SSL_get_ex_data family of functions. But, these functions
* operate on a specific index (obtained by calling SSL_get_ex_new_index). But, since the library should potentially
@@ -617,7 +935,7 @@ int gtm_tls_connect(gtm_tls_socket_t *socket)
{
int rv;
- assert(socket->flags & GTMTLS_OP_CLIENT_MODE);
+ assert(CLIENT_MODE(socket->flags));
DBG_VERIFY_SOCK_IS_BLOCKING(GET_SOCKFD(socket->ssl));
if (NULL != socket->session)
{ /* Old session available. Reuse it. */
@@ -648,10 +966,20 @@ int gtm_tls_accept(gtm_tls_socket_t *socket)
int gtm_tls_renegotiate(gtm_tls_socket_t *socket)
{
int rv;
+ gtm_tls_ctx_t *tls_ctx;
DBG_VERIFY_SOCK_IS_BLOCKING(GET_SOCKFD(socket->ssl));
if (0 >= (rv = SSL_renegotiate(socket->ssl)))
return ssl_error(socket->ssl, rv);
+# ifdef TLS_RENEGOTIATE_NO_HANDSHAKE
+ tls_ctx = socket->gtm_ctx;
+ assert(tls_ctx);
+ if (GTMTLS_OP_INTERACTIVE_MODE & tls_ctx->flags)
+ { /* avoid hanging until client does I/O */
+ socket->flags |= GTMTLS_OP_RENEGOTIATE_REQUESTED;
+ return 0;
+ }
+# endif
do
{
if (0 < (rv = SSL_do_handshake(socket->ssl)))
@@ -766,6 +1094,8 @@ int gtm_tls_get_conn_info(gtm_tls_socket_t *socket, gtm_tls_conn_info *conn_info
if (-1 == format_ASN1_TIME(X509_get_notAfter(peer), conn_info->not_after, MAX_TIME_STRLEN))
SNPRINTF(conn_info->not_after, MAX_TIME_STRLEN, "Bad certificate date");
X509_free(peer);
+ if (GTM_TLS_API_VERSION_SOCK <= socket->gtm_ctx->version)
+ conn_info->options = SSL_get_options(ssl);
return 0;
} else
{
@@ -811,9 +1141,8 @@ int gtm_tls_cachedbytes(gtm_tls_socket_t *socket)
void gtm_tls_socket_close(gtm_tls_socket_t *socket)
{
- assert(socket);
tls_errno = 0;
- if (NULL == socket->ssl)
+ if ((NULL == socket) || (NULL == socket->ssl))
return;
DBG_VERIFY_SOCK_IS_BLOCKING(GET_SOCKFD(socket->ssl));
/* Invoke SSL_shutdown to close the SSL/TLS connection. Although the protocol (and the OpenSSL library) supports
diff --git a/sr_unix/gtm_tls_impl.h b/sr_unix/gtm_tls_impl.h
index 82abc2d..39ef2e0 100644
--- a/sr_unix/gtm_tls_impl.h
+++ b/sr_unix/gtm_tls_impl.h
@@ -8,8 +8,8 @@
* the license, please stop and do not read further. *
* *
****************************************************************/
-#ifndef _GTM_TLS_IMPL_H
-#define _GTM_TLS_IMPL_H
+#ifndef GTM_TLS_IMPL_H
+#define GTM_TLS_IMPL_H
STATICFNDEF int format_ASN1_TIME(ASN1_TIME *tm, char *buf, int maxlen);
STATICFNDEF int ssl_generic_vfy_callback(int preverify_ok, X509_STORE_CTX *ctx);
@@ -29,6 +29,7 @@ typedef struct gtmtls_passwd_list_struct
#define GET_SOCKFD(TLS) SSL_get_fd((SSL *)TLS)
#define VERIFY_PEER(FLAGS) (FLAGS & GTMTLS_OP_VERIFY_PEER)
+#define CLIENT_MODE(FLAGS) (FLAGS & GTMTLS_OP_CLIENT_MODE)
#define DEFAULT_SESSION_TIMEOUT 3600 /* Old sessions can be reused upto 1 hour since the creation time. */
#ifdef DEBUG
diff --git a/sr_unix/gtm_tls_interface.h b/sr_unix/gtm_tls_interface.h
index e984308..7c60630 100644
--- a/sr_unix/gtm_tls_interface.h
+++ b/sr_unix/gtm_tls_interface.h
@@ -9,13 +9,14 @@
* *
****************************************************************/
-#ifndef _GTM_TLS_INTERFACE_H
-#define _GTM_TLS_INTERFACE_H
+#ifndef GTM_TLS_INTERFACE_H
+#define GTM_TLS_INTERFACE_H
-#ifndef _GTM_TLS_INTERFACE_DEFINITIONS_INCLUDED
-#define _GTM_TLS_INTERFACE_DEFINITIONS_INCLUDED
+#ifndef GTM_TLS_INTERFACE_DEFINITIONS_INCLUDED
+#define GTM_TLS_INTERFACE_DEFINITIONS_INCLUDED
-#define GTM_TLS_API_VERSION 0x00000001
+#define GTM_TLS_API_VERSION 0x00000002
+#define GTM_TLS_API_VERSION_SOCK 0x00000002 /* when TLS sockets added */
#define MAX_X509_LEN 256
#define MAX_ALGORITHM_LEN 64
@@ -37,7 +38,16 @@
#define GTMTLS_WANT_WRITE -3
#define GTMTLS_PASSWD_ENV_PREFIX "gtmtls_passwd_"
+/* below also defined in gtmcrypt_util.h so prevent redefinition in gtm_tls_impl.h */
+#ifndef GTM_PASSPHRASE_MAX
+#define GTM_PASSPHRASE_MAX 512 /* obfuscated */
+#define GTM_PASSPHRASE_MAX_ASCII (GTM_PASSPHRASE_MAX / 2)
+#elif GTM_PASSPHRASE_MAX != 512
+#error "GTM-E-GTMTLSINTERFACE different values for GTM_PASSPHRASE_MAX"
+#endif
+/* Note these flags may be in either the ctx or ssl structures but not all
+ * may have meaning in both. */
/* Whether the library is loaded in an interactive environment so that password prompting can happen if needed. */
#define GTMTLS_OP_INTERACTIVE_MODE 0x00000001
/* Turn-on compression for SSL/TLS protocol. */
@@ -46,6 +56,18 @@
#define GTMTLS_OP_CLIENT_MODE 0x00000004
/* Peer verification is needed. */
#define GTMTLS_OP_VERIFY_PEER 0x00000008
+/* Socket device */
+#define GTMTLS_OP_SOCKET_DEV 0x00000010
+/* No cipher list specifed at top tls level */
+#define GTMTLS_OP_ABSENT_CIPHER 0x00000020
+/* Default cipher list used */
+#define GTMTLS_OP_DEFAULT_CIPHER 0x00000040
+/* REPL_CIPHER_LIST used */
+#define GTMTLS_OP_REPL_CIPHER 0x00000080
+/* No verify mode specifed at top tls level */
+#define GTMTLS_OP_ABSENT_VERIFYMODE 0x00000100
+/* Server requested renegotiation without waiting for handshake */
+#define GTMTLS_OP_RENEGOTIATE_REQUESTED 0x00000200
#define GTMTLS_IS_FIPS_MODE(CTX) (TRUE == CTX->fips_mode)
#define GTMTLS_RUNTIME_LIB_VERSION(CTX) (CTX->runtime_version)
@@ -67,15 +89,11 @@ typedef struct gtm_tls_conn_info_struct
char issuer[MAX_X509_LEN]; /* CA who issued the certificate. */
char not_before[MAX_TIME_STRLEN]; /* Date before which the certificate is not valid. */
char not_after[MAX_TIME_STRLEN]; /* Date after which the certificate is not valid. */
+ /* items after this added for GTM_TLS_API_VERSION_SOCK */
+ long options; /* bitmask of SSL options */
+ int renegotiation_pending; /* no handshake yet */
} gtm_tls_conn_info;
-typedef struct gtm_tls_session_struct
-{
- int flags;
- void *ssl;
- void *session;
-} gtm_tls_socket_t;
-
typedef struct gtm_tls_ctx_struct
{
int flags;
@@ -83,9 +101,19 @@ typedef struct gtm_tls_ctx_struct
unsigned long compile_time_version; /* OpenSSL version that this library is compiled with. */
unsigned long runtime_version; /* OpenSSL version that this library is currently running with. */
void *ctx;
+ int version; /* GTM_TLS_API_VERSION */
} gtm_tls_ctx_t;
-#endif /* _GTM_TLS_INTERFACE_DEFINITIONS_INCLUDED */
+typedef struct gtm_tls_session_struct
+{
+ int flags;
+ void *ssl;
+ void *session;
+ char tlsid[MAX_TLSID_LEN + 1];
+ gtm_tls_ctx_t *gtm_ctx;
+} gtm_tls_socket_t;
+
+#endif /* GTM_TLS_INTERFACE_DEFINITIONS_INCLUDED */
/* Note: The below function prototypes should be kept in sync with the corresponding declarations/definitions in sr_unix/gtm_tls.h
* and sr_unix/gtm_tls_funclist.h.
diff --git a/sr_unix/gtm_trigger.c b/sr_unix/gtm_trigger.c
index dd96b71..2732a05 100644
--- a/sr_unix/gtm_trigger.c
+++ b/sr_unix/gtm_trigger.c
@@ -91,6 +91,7 @@ GBLREF mval dollar_ztrap;
GBLREF mval gtm_trigger_etrap;
GBLREF mstr *dollar_ztname;
GBLREF mval *dollar_ztdata;
+GBLREF mval *dollar_ztdelim;
GBLREF mval *dollar_ztoldval;
GBLREF mval *dollar_ztriggerop;
GBLREF mval *dollar_ztupdate;
@@ -260,7 +261,7 @@ CONDITION_HANDLER(gtm_trigger_complink_ch)
CONDITION_HANDLER(gtm_trigger_ch)
{ /* Condition handler for trigger execution - This handler is pushed on first for a given trigger level, then
- * mdb_condition_handler is pushed on so will appearr multiple times as trigger depth increases. There is
+ * mdb_condition_handler is pushed on so will appear multiple times as trigger depth increases. There is
* always an mdb_condition_handler behind us for an earlier trigger level and we let it handle severe
* errors for us as it gives better diagnostics (e.g. GTM_FATAL_ERROR dumps) in addition to the file core dump.
*/
@@ -449,7 +450,7 @@ int gtm_trigger_complink(gv_trigger_t *trigdsc, boolean_t dolink)
PUSH_MV_STENT(MVST_MSAV);
mv_chain->mv_st_cont.mvs_msav.v = dollar_zsource;
mv_chain->mv_st_cont.mvs_msav.addr = &dollar_zsource;
- TREF(trigger_compile) = TRUE; /* Set flag so compiler knows this is a special trigger compile */
+ TREF(trigger_compile) = TRUE; /* Set flag so compiler knows this is a special trigger compile */
op_zcompile(&zcompprm, TRUE); /* Compile but don't use $ZCOMPILE qualifiers */
TREF(trigger_compile) = FALSE; /* compile_source_file() establishes handler so always returns */
if (0 != TREF(dollar_zcstatus))
@@ -472,7 +473,9 @@ int gtm_trigger_complink(gv_trigger_t *trigdsc, boolean_t dolink)
# ifdef GEN_TRIGLINKFAIL_ERROR
UNLINK(objname); /* delete object before it can be used */
# endif
+ TREF(trigger_compile) = TRUE; /* Overload flag so we know it is a trigger link */
op_zlink(&zlfile, (mval *)&literal_null); /* need cast due to "extern const" attributes */
+ TREF(trigger_compile) = FALSE; /* If doesn't return, condition handler will clear */
/* No return here if link fails for some reason */
trigdsc->rtn_desc.rt_adr = find_rtn_hdr(&trigdsc->rtn_desc.rt_name);
/* Verify can find routine we just put there. Catastrophic if not */
@@ -528,8 +531,8 @@ int gtm_trigger(gv_trigger_t *trigdsc, gtm_trigger_parms *trigprm)
if (0 != gtm_trigger_complink(trigdsc, TRUE))
{
PRN_ERROR; /* Leave record of what error caused the compilation failure if any */
- rts_error_csa(CSA_ARG(cs_addrs)
- VARLSTCNT(4) ERR_TRIGCOMPFAIL, 2, trigdsc->rtn_desc.rt_name.len, trigdsc->rtn_desc.rt_name.addr);
+ rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_TRIGCOMPFAIL, 2,
+ trigdsc->rtn_desc.rt_name.len - 1, trigdsc->rtn_desc.rt_name.addr);
}
}
assert(trigdsc->rtn_desc.rt_adr);
@@ -608,6 +611,7 @@ int gtm_trigger(gv_trigger_t *trigdsc, gtm_trigger_parms *trigprm)
mv_st_ent->mv_st_cont.mvs_trigr.savextref.len = extnam_str.len;
mv_st_ent->mv_st_cont.mvs_trigr.ztname_save = dollar_ztname;
mv_st_ent->mv_st_cont.mvs_trigr.ztdata_save = dollar_ztdata;
+ mv_st_ent->mv_st_cont.mvs_trigr.ztdelim_save = dollar_ztdelim;
mv_st_ent->mv_st_cont.mvs_trigr.ztoldval_save = dollar_ztoldval;
mv_st_ent->mv_st_cont.mvs_trigr.ztriggerop_save = dollar_ztriggerop;
mv_st_ent->mv_st_cont.mvs_trigr.ztupdate_save = dollar_ztupdate;
@@ -618,17 +622,19 @@ int gtm_trigger(gv_trigger_t *trigdsc, gtm_trigger_parms *trigprm)
mv_st_ent->mv_st_cont.mvs_trigr.gtm_trigdsc_last_save = trigdsc;
mv_st_ent->mv_st_cont.mvs_trigr.gtm_trigprm_last_save = trigprm;
# endif
- /* If this is a spanning node update, a spanning node condition handler may be at the front of the line. However,
- * the condition handler just behind it should be either mdb_condition_handler or ch_at_trigger_init.
+ /* If this is a spanning node or spanning region update, a spanning node/region condition handler may be ahead.
+ * However, the handler just behind it should be either mdb_condition_handler or ch_at_trigger_init.
*/
assert(((0 == gtm_trigger_depth)
- && (((ch_at_trigger_init == ctxt->ch)
- || ((ch_at_trigger_init == (ctxt - 1)->ch)
- && ((&gvcst_put_ch == ctxt->ch) || (&gvcst_kill_ch == ctxt->ch))))))
- || ((0 < gtm_trigger_depth)
- && (((&mdb_condition_handler == ctxt->ch)
- || ((&mdb_condition_handler == (ctxt - 1)->ch)
- && ((&gvcst_put_ch == ctxt->ch) || (&gvcst_kill_ch == ctxt->ch)))))));
+ && (((ch_at_trigger_init == ctxt->ch)
+ || ((ch_at_trigger_init == (ctxt - 1)->ch)
+ && ((&gvcst_put_ch == ctxt->ch) || (&gvcst_kill_ch == ctxt->ch)
+ || (&gvcst_spr_kill_ch == ctxt->ch))))))
+ || ((0 < gtm_trigger_depth)
+ && (((&mdb_condition_handler == ctxt->ch)
+ || ((&mdb_condition_handler == (ctxt - 1)->ch)
+ && ((&gvcst_put_ch == ctxt->ch) || (&gvcst_kill_ch == ctxt->ch)
+ || (&gvcst_spr_kill_ch == ctxt->ch)))))));
mv_st_ent->mv_st_cont.mvs_trigr.ctxt_save = ctxt;
mv_st_ent->mv_st_cont.mvs_trigr.gtm_trigger_depth_save = gtm_trigger_depth;
if (0 == gtm_trigger_depth)
@@ -682,6 +688,7 @@ int gtm_trigger(gv_trigger_t *trigdsc, gtm_trigger_parms *trigprm)
/* Set new value of trigger ISVs. Previous values already saved in trigger base frame */
dollar_ztname = &trigdsc->rtn_desc.rt_name;
dollar_ztdata = (mval *)trigprm->ztdata_new;
+ dollar_ztdelim = (mval *)trigprm->ztdelim_new;
dollar_ztoldval = trigprm->ztoldval_new;
dollar_ztriggerop = (mval *)trigprm->ztriggerop_new;
dollar_ztupdate = trigprm->ztupdate_new;
diff --git a/sr_unix/gtm_trigger.h b/sr_unix/gtm_trigger.h
index edc84bf..ca486f5 100644
--- a/sr_unix/gtm_trigger.h
+++ b/sr_unix/gtm_trigger.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010 Fidelity Information Services, Inc *
+ * Copyright 2010, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -30,19 +30,16 @@
* if we are eligible for this unwind. If not, this is an out-of-design condition we need to protect
* against.
*/
-#define TRIGGER_BASE_FRAME_UNWIND_IF_NOMANSLAND \
-{ \
- if (SFT_TRIGR & frame_pointer->type) \
- { \
- if (INTRPT_IN_TRIGGER_NOMANS_LAND == intrpt_ok_state) \
- { /* Remove this errant frame and continue to restart */ \
- DBGTRIGR((stderr, "%s: trigger-no-mans-land situation - removing trigger " \
- "base frame\n", __FILE__)); \
- gtm_trigger_fini(FALSE, FALSE); \
- } else \
- /* Bad mojo - not in trigger-no-mans-land - unknown issue to protect against */ \
- GTMASSERT; \
- } \
+#define TRIGGER_BASE_FRAME_UNWIND_IF_NOMANSLAND \
+{ \
+ if (SFT_TRIGR & frame_pointer->type) \
+ { \
+ assertpro(INTRPT_IN_TRIGGER_NOMANS_LAND == intrpt_ok_state); \
+ /* Remove this errant frame and continue to restart */ \
+ DBGTRIGR((stderr, "%s: trigger-no-mans-land situation - removing trigger " \
+ "base frame\n", __FILE__)); \
+ gtm_trigger_fini(FALSE, FALSE); \
+ } \
}
typedef enum
@@ -63,6 +60,7 @@ typedef struct
*/
const mval *ztdata_new; /* $Data status of trigger value being Set/Killed - points to a constant mval
* in mtables.c */
+ const mval *ztdelim_new; /* mval to set into $ZTDELIM - points to a string pool entry */
const mval *ztriggerop_new; /* Opcode type invoking the trigger - points to a constant mval in mtables.c */
mval *ztupdate_new; /* mval to set into $ZTUPDATE.
* Points to stringpool at "gtm_trigger" entry - is NOT updated by the function */
diff --git a/sr_unix/gtm_trigger_trc.h b/sr_unix/gtm_trigger_trc.h
index c199339..e0079df 100644
--- a/sr_unix/gtm_trigger_trc.h
+++ b/sr_unix/gtm_trigger_trc.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2012 Fidelity Information Services, Inc *
+ * Copyright 2010, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -21,11 +21,13 @@
/* #include "have_crit.h" for DBGFPF/FFLUSH/INTRPT_IN_FFLUSH */
/* #define DEBUG_TRIGR */
#if defined(DEBUG_TRIGR) && defined(GTM_TRIGGER)
+# define DBGIFTRIGR(x) if (is_trigger) DBGFPF(x)
# define DBGTRIGR(x) DBGFPF(x)
# define DBGTRIGR_ONLY(x) x
# include "gtm_stdio.h"
# include "gtmio.h"
#else
+# define DBGIFTRIGR(x)
# define DBGTRIGR(x)
# define DBGTRIGR_ONLY(x)
#endif
diff --git a/sr_unix/gtmci.c b/sr_unix/gtmci.c
index 0bdfce2..a848d52 100644
--- a/sr_unix/gtmci.c
+++ b/sr_unix/gtmci.c
@@ -214,6 +214,7 @@ int gtm_is_main_thread()
int gtm_cij(const char *c_rtn_name, char **arg_blob, int count, int *arg_types, unsigned int *io_vars_mask,
unsigned int *has_ret_value)
{
+ boolean_t need_rtnobj_shm_free;
callin_entry_list *entry;
mstr label, routine;
int has_return, i, len;
@@ -283,7 +284,10 @@ int gtm_cij(const char *c_rtn_name, char **arg_blob, int count, int *arg_types,
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CINOENTRY, 2, LEN_AND_STR(c_rtn_name));
lref_parse((unsigned char*)entry->label_ref.addr, &routine, &label, &i);
/* The 3rd argument is NULL because we will get lnr_adr via lab_proxy. */
- if(!job_addr(&routine, &label, 0, (char **)&base_addr, NULL))
+ /* See comment in ojstartchild.c about "need_rtnobj_shm_free". It is not used here because we will
+ * decrement rtnobj reference counts at exit time in relinkctl_rundown (called by gtm_exit_handler).
+ */
+ if (!job_addr(&routine, &label, 0, (char **)&base_addr, NULL, &need_rtnobj_shm_free))
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBLABOFF);
memset(¶m_blk, 0, SIZEOF(param_blk));
param_blk.rtnaddr = (void *)base_addr;
@@ -521,6 +525,7 @@ int gtm_cij(const char *c_rtn_name, char **arg_blob, int count, int *arg_types,
/* Common work-routine for gtm_ci() and gtm_cip() to drive callin */
int gtm_ci_exec(const char *c_rtn_name, void *callin_handle, int populate_handle, va_list temp_var)
{
+ boolean_t need_rtnobj_shm_free;
va_list var;
callin_entry_list *entry;
mstr label, routine;
@@ -596,7 +601,10 @@ int gtm_ci_exec(const char *c_rtn_name, void *callin_handle, int populate_handle
entry = callin_handle;
lref_parse((unsigned char*)entry->label_ref.addr, &routine, &label, &i);
/* 3rd argument is NULL because we will get lnr_adr via lab_proxy */
- if(!job_addr(&routine, &label, 0, (char **)&base_addr, NULL))
+ /* See comment in ojstartchild.c about "need_rtnobj_shm_free". It is not used here because we will
+ * decrement rtnobj reference counts at exit time in relinkctl_rundown (called by gtm_exit_handler).
+ */
+ if (!job_addr(&routine, &label, 0, (char **)&base_addr, NULL, &need_rtnobj_shm_free))
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBLABOFF);
memset(¶m_blk, 0, SIZEOF(param_blk));
param_blk.rtnaddr = (void *)base_addr;
diff --git a/sr_unix/gtmcrypt_interface.h b/sr_unix/gtmcrypt_interface.h
index 267d85f..1887daf 100644
--- a/sr_unix/gtmcrypt_interface.h
+++ b/sr_unix/gtmcrypt_interface.h
@@ -67,12 +67,12 @@ gtm_char_t *gtmcrypt_strerror(void);
* encryption and decryption state objects is that for every encryption and decryption operation the initial IV is used, effectively
* reverting to the original state.
*
- * Arguments: handle Pointer which should get pointed to the database encryption state object.
+ * Arguments: handle Pointer to the database encryption state object supplied by the caller and filled in by this routine.
* hash Hash of the key.
* iv Initialization vector to use for encryption or decryption.
*
- * Returns: 0 if the key was found and database encryption and decryption state objects were initialized or existed already; -1
- * otherwise.
+ * Returns: 0 if the routine found the key, and either found existing database encryption and decryption state objects or
+ * initialized them; -1 otherwise.
*/
gtm_status_t gtmcrypt_init_db_cipher_context_by_hash(gtmcrypt_key_t *handle, gtm_string_t hash, gtm_string_t iv);
/***********************************************************************************************************************************
@@ -82,13 +82,15 @@ gtm_status_t gtmcrypt_init_db_cipher_context_by_hash(gtmcrypt_key_t *handle, gtm
* relying on the same key require individual encryption and decryption state objects as their states evolve with each encryption or
* decryption operation.
*
- * Arguments: handle Pointer which should get pointed to the device encryption or decryption state object.
+ * Arguments: handle Pointer to the database encryption state object supplied by the caller and filled in by this
+ * routine.
* keyname Name of the key.
* iv Initialization vector to use for encryption or decryption.
* operation Flag indicating whether encryption or decryption is desired; use GTMCRYPT_OP_ENCRYPT or
* GTMCRYPT_OP_DECRYPT, respectively.
*
- * Returns: 0 if the key was found and device encryption or decryption state object was initialized; -1 otherwise.
+ * Returns: 0 if the routine found the key, and either found existing database encryption and decryption state objects or
+ * initialized them; -1 otherwise.
*/
gtm_status_t gtmcrypt_init_device_cipher_context_by_keyname(gtmcrypt_key_t *handle, gtm_string_t keyname,
gtm_string_t iv, gtm_int_t operation);
@@ -98,18 +100,18 @@ gtm_status_t gtmcrypt_init_device_cipher_context_by_keyname(gtmcrypt_key_t *hand
* configuration file in case of devices, or a path to a database file otherwise.
*
* Arguments: keyname Name of the key.
- * hash_dest Pointer to the location where the key's hash is to be copied.
+ * hash_dest Pointer to the location for this routine to copy the key's hash.
*
- * Returns: 0 if the key was found and key's hash was copied to the specified location; -1 otherwise.
+ * Returns: 0 if the routine found the key and copied its hash to the specified location; -1 otherwise.
*/
gtm_status_t gtmcrypt_obtain_db_key_hash_by_keyname(gtm_string_t keyname, gtm_string_t *hash_dest);
/***********************************************************************************************************************************
* Release the specified encryption or decryption state object, also releasing the decryption state if database encryption state is
* specified.
*
- * Arguments: handle Encryption or decryption state object to release.
+ * Arguments: handle Pointer to the encryption or decryption state object to release.
*
- * Returns: 0 if the operation was successful; -1 otherwise.
+ * Returns: 0 if the operation succeeded; -1 otherwise.
*/
gtm_status_t gtmcrypt_release_key(gtmcrypt_key_t handle);
/***********************************************************************************************************************************
@@ -124,17 +126,17 @@ gtm_status_t gtmcrypt_release_key(gtmcrypt_key_t handle);
* at. With Gcrypt, on the other hand, modifying the IV (iv_mode != GTMCRYPT_IV_CONTINUE) before an operation influences the
* subsequent IV-non-modifying (iv_mode == GTMCRYPT_IV_CONTINUE) operations.
*
- * Arguments: handle Encryption state object to use.
- * unencr_block Block where unencrypted data is read from.
- * unencr_block_len Length of the unencrypted (and encrypted) data block.
- * encr_block Block where encrypted data is put into.
- * operation Flag indicating whether encryption or decryption is desired; use GTMCRYPT_OP_ENCRYPT or
+ * Arguments: handle Encryption state object.
+ * unencr_block Block of unencrypted data.
+ * unencr_block_len Length of the unencrypted and encrypted data blocks.
+ * encr_block Block of encrypted data.
+ * operation Flag indicating whether to perform encryption or decryption; use GTMCRYPT_OP_ENCRYPT or
* GTMCRYPT_OP_DECRYPT, respectively.
- * iv_mode Flag indicating whether the initialization vector (IV) should be changed prior to the
- * operation; use GTMCRYPT_IV_CONTINUE to proceed without changing the IV, GTMCRYPT_IV_SET to
- * set the IV the value supplied in the iv argument, and GTMCRYPT_IV_RESET to reset the IV to
- * the value specified at initialization.
- * iv Initialization vector to set the encryption state to when iv_mode is GTMCRYPT_IV_SET.
+ * iv_mode Flag indicating whether to change the initialization vector (IV) prior to the operation; use
+ * GTMCRYPT_IV_CONTINUE to proceed without changing the IV, GTMCRYPT_IV_SET to set the IV the
+ * value supplied in the iv argument, and GTMCRYPT_IV_RESET to reset the IV to the value
+ * specified at initialization.
+ * iv Initialization vector for the encryption state to take when iv_mode is GTMCRYPT_IV_SET.
*
* Returns: 0 if the operation succeeded; -1 otherwise.
*/
@@ -143,8 +145,8 @@ gtm_status_t gtmcrypt_encrypt_decrypt(gtmcrypt_key_t handle, gtm_char_t *src_blo
/***********************************************************************************************************************************
* Compare the keys associated with two encryption or decryption state objects.
*
- * Arguments: handle1 First ecryption or decryption state object to use.
- * handle2 Second ecryption or decryption state object to use.
+ * Arguments: handle1 First encryption or decryption state object.
+ * handle2 Second encryption or decryption state object.
*
* Returns: 1 if both encryption or decryption state objects use the same key; 0 otherwise.
*/
diff --git a/sr_unix/gtmcrypt_util.c b/sr_unix/gtmcrypt_util.c
index 560976b..b870932 100644
--- a/sr_unix/gtmcrypt_util.c
+++ b/sr_unix/gtmcrypt_util.c
@@ -52,9 +52,9 @@ GBLDEF gtm_free_fnptr_t gtm_free_fnptr;
#define Tcsetattr(FDESC, WHEN, TERMPTR, RC, ERRNO) \
{ \
- sigset_t block_ttinout; \
- sigset_t oldset; \
- int rc; \
+ sigset_t block_ttinout; \
+ sigset_t oldset; \
+ int rc; \
\
sigemptyset(&block_ttinout); \
sigaddset(&block_ttinout, SIGTTIN); \
@@ -113,9 +113,9 @@ void gtm_gcry_log_handler(void *opaque, int level, const char *fmt, va_list arg_
return;
}
-int gc_read_passwd(char *prompt, char *buf, int maxlen)
+int gc_read_passwd(char *prompt, char *buf, int maxlen, void *tty)
{
- struct termios new_tty, old_tty;
+ struct termios new_tty, old_tty, *tty_copy;
int fd, status, save_errno, istty, i, rv;
char c;
@@ -126,11 +126,22 @@ int gc_read_passwd(char *prompt, char *buf, int maxlen)
fd = fileno(stdin);
if (FALSE != (istty = isatty(fd)))
{ /* Turn off terminal echo. */
- if (0 != (status = tcgetattr(fd, &old_tty)))
+ status = tcgetattr(fd, &old_tty);
+ if (0 != status)
{
- UPDATE_ERROR_STRING("Failed to obtain passphrase from terminal. %s", strerror(errno));
+ UPDATE_ERROR_STRING("Unable to set up terminal for safe password entry. Will not request passphrase. %s",
+ strerror(errno));
return -1;
}
+ if (NULL != tty)
+ { /* In case a pointer was passed for the current terminal state, avoid a race condition with a potential
+ * interrupt by first assigning a pointer for the allocated space to a local variable and only then
+ * updating the passed-in pointer.
+ */
+ tty_copy = (struct termios *)MALLOC(SIZEOF(struct termios));
+ memcpy(tty_copy, &old_tty, SIZEOF(struct termios));
+ *((struct termios **)tty) = tty_copy;
+ }
new_tty = old_tty;
new_tty.c_lflag &= ~ECHO;
/* GT.M terminal settings has ICANON and ICRNL turned-off. This causes the terminal to be treated
@@ -142,7 +153,8 @@ int gc_read_passwd(char *prompt, char *buf, int maxlen)
Tcsetattr(fd, TCSAFLUSH, &new_tty, status, save_errno);
if (-1 == status)
{
- UPDATE_ERROR_STRING("Failed to obtain passphrase from terminal. %s", strerror(save_errno));
+ UPDATE_ERROR_STRING("Unable to set up terminal for safe password entry. Will not request passphrase. %s",
+ strerror(save_errno));
return -1;
}
}
@@ -181,7 +193,7 @@ int gc_read_passwd(char *prompt, char *buf, int maxlen)
Tcsetattr(fd, TCSAFLUSH, &old_tty, status, save_errno);
if (-1 == status)
{
- UPDATE_ERROR_STRING("Failed to obtain passphrase from terminal. %s", strerror(save_errno));
+ UPDATE_ERROR_STRING("Unable to restore terminal settings. %s", strerror(save_errno));
return -1;
}
}
@@ -357,7 +369,7 @@ int gc_update_passwd(char *name, passwd_entry_t **ppwent, char *prompt, int inte
gc_freeup_pwent(pwent);
return -1;
}
- if (-1 == gc_read_passwd(prompt, passwd, GTM_PASSPHRASE_MAX))
+ if (-1 == gc_read_passwd(prompt, passwd, GTM_PASSPHRASE_MAX, NULL))
{
gc_freeup_pwent(pwent);
return -1;
diff --git a/sr_unix/gtmcrypt_util.h b/sr_unix/gtmcrypt_util.h
index 9b32999..8457c06 100644
--- a/sr_unix/gtmcrypt_util.h
+++ b/sr_unix/gtmcrypt_util.h
@@ -8,8 +8,8 @@
* the license, please stop and do not read further. *
* *
****************************************************************/
-#ifndef __GTMCRYPT_UTIL_H
-#define __GTMCRYPT_UTIL_H
+#ifndef GTMCRYPT_UTIL_H
+#define GTMCRYPT_UTIL_H
#if !defined(DEBUG) && defined(assert)
# undef assert
@@ -28,7 +28,9 @@
#define MAX_GTMCRYPT_STR_ARG_LEN 256
#define MAX_GTMCRYPT_ERR_STRLEN 2048
-#define GTM_PASSPHRASE_MAX 512
+/* next two defines also in gtm_tls_interface.h and should be kept in sync */
+#define GTM_PASSPHRASE_MAX 512 /* obfuscated */
+#define GTM_PASSPHRASE_MAX_ASCII (GTM_PASSPHRASE_MAX / 2)
#define PASSPHRASE_ENVNAME_MAX 64
#define GTMCRYPT_DEFAULT_PASSWD_PROMPT "Enter Passphrase: "
@@ -36,7 +38,6 @@
#define GTMCRYPT_FIPS_ENV "gtmcrypt_FIPS"
-
#define GC_H2D(C, RES, MULT) \
{ \
if ((C >= 'A') && (C <= 'F')) \
@@ -49,7 +50,6 @@
RES = -1; \
}
-
/* Convert SOURCE, sequence of hexadecimal characters, into decimal representation. LEN denotes the length of the SOURCE string.
* NOTE: Hexadecimal characters, presented in SOURCE string, has to be in upper case.
*/
@@ -198,7 +198,7 @@
/* Libgcrypt specific error handling. */
#define GC_APPEND_GCRY_ERROR(ERR, ...) \
{ \
- char *errptr, *end; \
+ char *errptr, *end; \
\
errptr = >mcrypt_err_string[0]; \
end = errptr + MAX_GTMCRYPT_ERR_STRLEN; \
@@ -235,7 +235,7 @@ GBLREF char gtmcrypt_err_string[MAX_GTMCRYPT_ERR_STRLEN];
int gc_load_gtmshr_symbols(void);
void gtm_gcry_log_handler(void *opaque, int level, const char *fmt, va_list arg_ptr);
-int gc_read_passwd(char *prompt, char *buf, int maxlen);
+int gc_read_passwd(char *prompt, char *buf, int maxlen, void *tty);
int gc_mask_unmask_passwd(int nparm, gtm_string_t *in, gtm_string_t *out);
void gc_freeup_pwent(passwd_entry_t *pwent);
int gc_update_passwd(char *name, passwd_entry_t **ppwent, char *prompt, int interactive);
diff --git a/sr_unix/gtminstall.sh b/sr_unix/gtminstall.sh
index b8cdd1d..3e94416 100644
--- a/sr_unix/gtminstall.sh
+++ b/sr_unix/gtminstall.sh
@@ -263,6 +263,11 @@ case ${gtm_hostos}_${gtm_arch} in
gtm_ftp_dirname="hpux_ia64"
gtm_flavor="ia64"
gtm_install_flavor="IA64" ;;
+ linux_i586) gtm_sf_dirname="GT.M-x86-Linux"
+ gtm_ftp_dirname="linux"
+ gtm_flavor="i586"
+ gtm_install_flavor="x86"
+ gtm_shlib_support="N" ;;
linux_i686) gtm_sf_dirname="GT.M-x86-Linux"
gtm_ftp_dirname="linux"
gtm_flavor="i686"
diff --git a/sr_unix/gtminstall_Solaris.sh b/sr_unix/gtminstall_Solaris.sh
index 69a5f18..e81f579 100644
--- a/sr_unix/gtminstall_Solaris.sh
+++ b/sr_unix/gtminstall_Solaris.sh
@@ -263,6 +263,11 @@ case ${gtm_hostos}_${gtm_arch} in
gtm_ftp_dirname="hpux_ia64"
gtm_flavor="ia64"
gtm_install_flavor="IA64" ;;
+ linux_i586) gtm_sf_dirname="GT.M-x86-Linux"
+ gtm_ftp_dirname="linux"
+ gtm_flavor="i586"
+ gtm_install_flavor="x86"
+ gtm_shlib_support="N" ;;
linux_i686) gtm_sf_dirname="GT.M-x86-Linux"
gtm_ftp_dirname="linux"
gtm_flavor="i686"
diff --git a/sr_unix/gtmio.h b/sr_unix/gtmio.h
index b4dfabc..1a2c9a2 100644
--- a/sr_unix/gtmio.h
+++ b/sr_unix/gtmio.h
@@ -17,10 +17,8 @@
* Loop until open succeeds or fails with other than EINTR.
* Opens with O_DSYNC/O_SYNC in direct mode where possible.
* Else opens only with O_DSYNC or O_SYNC.
- * OPEN_OBJECT_FILE
- * Opens the object file and waits till it gets a lock(shr/excl).
- * Sets default perms if it creates a new file.
- * CLOSE_OBJECT_FILE - close the object file after releasing the lock on it.
+ * OPEN_OBJECT_FILE Opens the object file.
+ * CLOSE_OBJECT_FILE Close the object file.
* CLOSEFILE Loop until close succeeds for fails with other than EINTR.
* CLOSEFILE_RESET
* Loop until close succeeds for fails with other than EINTR.
@@ -193,10 +191,8 @@ error_def(ERR_PREMATEOF);
#else
#define LOCK_IS_ALLOWED(FDESC, STATUS) STATUS = 0
#endif
-#define OPEN_OBJECT_FILE(FNAME, FFLAG, FDESC) FDESC = open_object_file(FNAME, FFLAG);
-
+#define OPEN_OBJECT_FILE(FNAME, FFLAG, FDESC) OPENFILE(FNAME, FFLAG, FDESC)
#define CLOSE_OBJECT_FILE(FDESC, RC) CLOSEFILE_RESET(FDESC, RC)
-
#define CLOSEFILE(FDESC, RC) \
{ \
do \
@@ -616,7 +612,7 @@ error_def(ERR_PREMATEOF);
the CHUNK_SIZE, no need to read once again since it is in BLOCKING mode, in which case it will return -1. \
So in the first read itself (after a successful read) break from the infinite loop. This variable is TRUE \
if DOREADRLTO2 macro is called for a CHUNK_SIZE read. In other places (eg: iorm_get) it will be FALSE. \
- */ \
+ */ \
if (UTF_VAR_PF) \
break; \
} else if (EINTR != errno || TOFLAG) \
@@ -832,11 +828,4 @@ typedef struct
fflush(STREAM); \
ENABLE_INTERRUPTS(INTRPT_IN_FFLUSH); \
}
-
-/* Prototypes */
-int open_object_file(const char *fname, int fflag);
-int mk_tmp_object_file(const char *object_fname, int object_fname_len);
-void rename_tmp_object_file(const char *object_fname);
-void init_object_file_name(void);
-
#endif
diff --git a/sr_unix/gtmprofile.gtc b/sr_unix/gtmprofile.gtc
index 7e12f5e..c999109 100644
--- a/sr_unix/gtmprofile.gtc
+++ b/sr_unix/gtmprofile.gtc
@@ -164,12 +164,12 @@ if [ $gtm_dist != "$old_gtm_dist" ] ; then
if [ -d $gtm_dist/plugin/o/utf8 ] ; then
gtmroutines=`$gtm_dist/mumps -run %XCMD 'set x=$ztrnlnm("gtm_dist")_"/plugin/o/utf8/*."_$ztrnlnm("tmp_gtm_shlib") for set y=$zsearch(x) quit:""=y write y," "'`"$gtm_dist/plugin/o/utf8($gtm_dist/plugin/r) $gtmroutines"
fi
- gtmroutines=`$gtm_dist/mumps -run %XCMD 'set x=$ztrnlnm("gtmdir")_"/"_$ztrnlnm("gtmver")_"/o/utf8/*."_$ztrnlnm("tmp_gtm_shlib") for set y=$zsearch(x) quit:""=y write y," "'`"$gtmdir/$gtmver/o/utf8($gtmdir/$gtmver/r $gtmdir/r) $gtmroutines"
+ gtmroutines=`$gtm_dist/mumps -run %XCMD 'set x=$ztrnlnm("gtmdir")_"/"_$ztrnlnm("gtmver")_"/o/utf8/*."_$ztrnlnm("tmp_gtm_shlib") for set y=$zsearch(x) quit:""=y write y," "'`"$gtmdir/$gtmver/o/utf8*($gtmdir/$gtmver/r $gtmdir/r) $gtmroutines"
else
if [ -d $gtm_dist/plugin/o ] ; then
gtmroutines=`$gtm_dist/mumps -run %XCMD 'set x=$ztrnlnm("gtm_dist")_"/plugin/o/*."_$ztrnlnm("tmp_gtm_shlib") for set y=$zsearch(x) quit:""=y write y," "'`"$gtm_dist/plugin/o($gtm_dist/plugin/r) $gtmroutines"
fi
- gtmroutines=`$gtm_dist/mumps -run %XCMD 'set x=$ztrnlnm("gtmdir")_"/"_$ztrnlnm("gtmver")_"/o/*."_$ztrnlnm("tmp_gtm_shlib") for set y=$zsearch(x) quit:""=y write y," "'`"$gtmdir/$gtmver/o($gtmdir/$gtmver/r $gtmdir/r) $gtmroutines"
+ gtmroutines=`$gtm_dist/mumps -run %XCMD 'set x=$ztrnlnm("gtmdir")_"/"_$ztrnlnm("gtmver")_"/o/*."_$ztrnlnm("tmp_gtm_shlib") for set y=$zsearch(x) quit:""=y write y," "'`"$gtmdir/$gtmver/o*($gtmdir/$gtmver/r $gtmdir/r) $gtmroutines"
fi
fi
export gtmroutines
@@ -253,6 +253,12 @@ if [ $gtm_dist != "$old_gtm_dist" ] ; then
if [ -z "$gtm_retention" ] ; then
gtm_retention=42 ; export gtm_retention
fi
+ # Set & uncomment these as required
+ # Refer to the GT.M Administration & Operations Guide for complete list of GT.M environment variables
+ # export gtm_autorelink_keeprtn=1 # leave auto-relinked object code in the shared memory repositories
+ # export gtm_linktmpdir= # put relinkctl files in location other than $gtm_tmp
+ # export gtm_baktmpdir= # location for MUPIP BACKUP temporary snapshot files
+ # export gtm_snaptmpdir= # location for MUPIP INTEG temporary snapshot files
# Set environment variables for plugins in $gtm_dist/plugin
tmp_gtm_tmp=`uname -s`
diff --git a/sr_unix/gtmrecv_process.c b/sr_unix/gtmrecv_process.c
index 35c1bdd..e0ebbe2 100644
--- a/sr_unix/gtmrecv_process.c
+++ b/sr_unix/gtmrecv_process.c
@@ -198,14 +198,12 @@ error_def(ERR_INSNOTJOINED);
error_def(ERR_INSROLECHANGE);
error_def(ERR_INSUNKNOWN);
error_def(ERR_JNLNEWREC);
-error_def(ERR_JNLRECFMT);
error_def(ERR_JNLSETDATA2LONG);
error_def(ERR_NOSUPPLSUPPL);
error_def(ERR_PRIMARYNOTROOT);
error_def(ERR_RCVRMANYSTRMS);
error_def(ERR_REPL2OLD);
error_def(ERR_REPLCOMM);
-error_def(ERR_REPLGBL2LONG);
error_def(ERR_REPLINSTNOHIST);
error_def(ERR_REPLINSTREAD);
error_def(ERR_REPLNOTLS);
@@ -213,7 +211,6 @@ error_def(ERR_REPLTRANS2BIG);
error_def(ERR_REPLXENDIANFAIL);
error_def(ERR_RESUMESTRMNUM);
error_def(ERR_REUSEINSTNAME);
-error_def(ERR_SECNODZTRIGINTP);
error_def(ERR_SECONDAHEAD);
error_def(ERR_STRMNUMIS);
error_def(ERR_SUPRCVRNEEDSSUPSRC);
@@ -486,11 +483,11 @@ STATICFNDEF int repl_tr_endian_convert(unsigned char remote_jnl_ver, uchar_ptr_t
}
if (IS_SET_KILL_ZKILL_ZTWORM_LGTRIG_ZTRIG(rectype))
{
- /* This code will need changes in case the jnl-ver changes from V24 to V25 so add an assert to
+ /* This code will need changes in case the jnl-ver changes from V25 to V26 so add an assert to
* alert to that possibility. Once the code is fixed for the new jnl format, change the assert
* to reflect the new latest jnl-ver.
*/
- assert(JNL_VER_THIS == V24_JNL_VER);
+ assert(JNL_VER_THIS == V25_JNL_VER);
/* To better understand the logic below (particularly the use of hardcoded offsets), see comment
* in repl_filter.c (search for "struct_jrec_upd layout" for the various jnl versions we support).
*/
@@ -959,12 +956,13 @@ void gtmrecv_repl_send(repl_msg_ptr_t msgp, int4 type, int4 len, char *msgtypest
*/
void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg, boolean_t is_rcvr_srvr)
{
- boolean_t remote_side_is_supplementary, grab_lock_needed;
+ boolean_t remote_side_is_supplementary, grab_lock_needed, lms_group_different;
repl_inst_hdr_ptr_t inst_hdr;
repl_instinfo_msg_t instinfo_msg;
repl_inst_uuid *strm_start, *strm_top, *strm_info;
FILE *log_fp;
int reuse_slot, first_usable_slot;
+ uint4 creator_pid;
seq_num strm_jnl_seqno;
sgmnt_addrs *repl_csa;
DCL_THREADGBL_ACCESS;
@@ -975,8 +973,25 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg,
remote_side_is_supplementary = need_instinfo_msg->is_supplementary;
remote_side->is_supplementary = remote_side_is_supplementary;
assert(remote_side->endianness_known); /* ensure remote_side->cross_endian is reliable */
- if (remote_side->cross_endian)
- ENDIAN_CONVERT_REPL_INST_UUID(&need_instinfo_msg->lms_group_info);
+ /* If the remote source server is <= V62000 it would have endian converted "need_instinfo_msg" ONLY IF
+ * src_jnl_ver < rcv_jnl_ver. If remote source server is > V62000 it would have endian converted unconditionally.
+ * So we dont need to do the endian conversion in either of those cases. The need_instinfo_msg->proto_ver will let
+ * us distinguish the > V62000 vs <= V62000 case. But if src version is <= V62000, we cannot easily distinguish what
+ * the other side's jnl_ver is so we dont know if the source server would have endian converted or not. We work around
+ * it by assuming that pids are limited to a max of 2**24 and so the most significant byte of the 4-byte pid should be 0.
+ * This trick might not work always in case an OS supports > 2**24 pid number (I dont know of any now) OR if both the
+ * most and least significant bytes of the 4-byte pid are 0, but if it does not, the worst we will see is a) an incorrect
+ * INSNOTJOINED error issued by the receiver server OR b) an incorrect lms_group_info copied over into the instance file
+ * (which will soon elicit some other related error). We can address (a) by trying out endian converting again below to
+ * see if that prevents the error and if so use that instead but we cannot address (b) with this trick.
+ * We can live with since the fix for (b) is to upgrade the receiver side to GTM V62001 or higher.
+ */
+ if (remote_side->cross_endian && (REPL_PROTO_VER_XENDIANFIXES > need_instinfo_msg->proto_ver))
+ {
+ creator_pid = need_instinfo_msg->lms_group_info.creator_pid;
+ if (!(creator_pid & 0xff) && (creator_pid & 0xff000000))
+ ENDIAN_CONVERT_REPL_INST_UUID(&need_instinfo_msg->lms_group_info);
+ }
assert(is_rcvr_srvr && (NULL != gtmrecv_log_fp) || !is_rcvr_srvr && (NULL == gtmrecv_log_fp));
assert(!is_rcvr_srvr || !repl_csa->hold_onto_crit);
assert(is_rcvr_srvr || !jgbl.onlnrlbk || repl_csa->hold_onto_crit);
@@ -1045,7 +1060,26 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg,
if (memcmp(&need_instinfo_msg->lms_group_info, &inst_hdr->lms_group_info, SIZEOF(inst_hdr->lms_group_info)))
{ /* Source and Receiver are part of DIFFERENT LMS Groups. If this instance is supplementary and remote
* side is not supplementary then we expect them to be different. Otherwise issue error.
+ * Note that because of an issue with endian-conversion (see big comment at start of this function),
+ * it is possible this lms_group_info would be good (i.e. passed the memcmp) if endian-converted. So
+ * try that once and if it still fails, go ahead with issuing an error.
*/
+ lms_group_different = TRUE;
+ if (remote_side->cross_endian && (REPL_PROTO_VER_XENDIANFIXES > need_instinfo_msg->proto_ver))
+ {
+ ENDIAN_CONVERT_REPL_INST_UUID(&need_instinfo_msg->lms_group_info);
+ if (!memcmp(&need_instinfo_msg->lms_group_info,
+ &inst_hdr->lms_group_info, SIZEOF(inst_hdr->lms_group_info)))
+ lms_group_different = FALSE; /* stay with converted lms_group_info as it is good */
+ else
+ { /* neither works so return to the original */
+ ENDIAN_CONVERT_REPL_INST_UUID(&need_instinfo_msg->lms_group_info);
+ }
+ }
+ } else
+ lms_group_different = FALSE;
+ if (lms_group_different)
+ {
if (!inst_hdr->is_supplementary || remote_side_is_supplementary)
{
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_INSNOTJOINED, 4,
@@ -1781,23 +1815,17 @@ STATICFNDEF void process_tr_buff(int msg_type)
write_len = out_size;
else
{
- assert(EREPL_INTLFILTER_SECNODZTRIGINTP == repl_errno);
- if (EREPL_INTLFILTER_BADREC == repl_errno)
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JNLRECFMT);
- else if (EREPL_INTLFILTER_DATA2LONG == repl_errno)
+ if (EREPL_INTLFILTER_DATA2LONG == repl_errno)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_JNLSETDATA2LONG, 2,
jnl_source_datalen, jnl_dest_maxdatalen);
else if (EREPL_INTLFILTER_NEWREC == repl_errno)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_JNLNEWREC, 2,
(unsigned int)jnl_source_rectype,
(unsigned int)jnl_dest_maxrectype);
- else if (EREPL_INTLFILTER_REPLGBL2LONG == repl_errno)
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REPLGBL2LONG);
- else if (EREPL_INTLFILTER_SECNODZTRIGINTP == repl_errno)
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_SECNODZTRIGINTP, 1,
- &recvpool_ctl->jnl_seqno);
- else /* (EREPL_INTLFILTER_INCMPLREC == repl_errno) */
- assertpro(repl_errno != repl_errno);
+ else
+ {
+ INT_FILTER_RTS_ERROR(recvpool_ctl->jnl_seqno, repl_errno); /* no return */
+ }
}
} else
memcpy(repl_filter_buff, recvpool.recvdata_base + write_off, write_len);
@@ -2677,7 +2705,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
boolean_t uncmpfail, send_cross_endian, recvpool_prepared, copied_to_recvpool;
gtmrecv_local_ptr_t gtmrecv_local;
gtm_time4_t ack_time;
- int4 msghdrlen, strm_num;
+ int4 msghdrlen, strm_num, processed_hdrlen;
int4 need_histinfo_num;
int cmpret;
int msg_type, msg_len;
@@ -2860,8 +2888,8 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
DO_FLOW_CONTROL(write_loc);
}
if (xoff_sent && GTMRECV_XOFF_LOG_CNT <= xoff_msg_log_cnt)
- { /* update process is still running slow, Force wait before logging any message. */
- SHORT_SLEEP(REPL_POLL_WAIT >> 10); /* approximate in ms */
+ { /* Update process is still running slow; force wait before logging any message. */
+ SHORT_SLEEP(MILLISECS_IN_SEC - 1); /* Sleep for one second. */
REPL_DPRINT1("Waiting for Update Process to clear recvpool space\n");
xoff_msg_log_cnt = 0;
} else if (xoff_sent)
@@ -2936,7 +2964,8 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
msg_type = (((repl_msg_ptr_t)buffp)->type & REPL_TR_CMP_MSG_TYPE_MASK);
if (REPL_TR_CMP_JNL_RECS == msg_type)
{
- msg_len = ((repl_msg_ptr_t)buffp)->len - REPL_MSG_HDRLEN;
+ processed_hdrlen = REPL_MSG_HDRLEN;
+ msg_len = ((repl_msg_ptr_t)buffp)->len - processed_hdrlen;
gtmrecv_repl_cmpmsglen = msg_len;
gtmrecv_repl_uncmpmsglen = (((repl_msg_ptr_t)buffp)->type >> REPL_TR_CMP_MSG_TYPE_BITS);
assert(0 < gtmrecv_repl_uncmpmsglen);
@@ -2945,9 +2974,9 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
* since 8-byte aligned length would have been sent by the source server anyways.
*/
msg_len = ROUND_UP(msg_len, REPL_MSG_ALIGN);
- buffp += REPL_MSG_HDRLEN;
+ buffp += processed_hdrlen;
exp_data_len = gtmrecv_repl_uncmpmsglen;
- buff_unprocessed -= REPL_MSG_HDRLEN;
+ buff_unprocessed -= processed_hdrlen;
GTMRECV_SET_BUFF_TARGET_CMPBUFF(gtmrecv_repl_cmpmsglen, gtmrecv_repl_uncmpmsglen,
gtmrecv_cur_cmpmsglen);
} else if (REPL_TR_CMP_JNL_RECS2 == msg_type)
@@ -2958,6 +2987,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
if (msghdrlen > buff_unprocessed) /* Did not receive the full-header. */
break; /* Break out of here and read more data first. */
msghdrlen = REPL_MSG_HDRLEN; /* reset to regular msg hdr length for future messages */
+ processed_hdrlen = REPL_MSG_HDRLEN2;
cmpmsgp = (repl_cmpmsg_ptr_t)buffp;
if (remote_side->cross_endian)
{
@@ -2968,16 +2998,17 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
gtmrecv_repl_uncmpmsglen = cmpmsgp->uncmplen;
assert(0 < gtmrecv_repl_uncmpmsglen);
assert(REPL_TR_CMP_THRESHOLD <= gtmrecv_repl_uncmpmsglen);
- msg_len = ((repl_msg_ptr_t)buffp)->len - REPL_MSG_HDRLEN2;
+ msg_len = ((repl_msg_ptr_t)buffp)->len - processed_hdrlen;
/* Unlike REPL_TR_CMP_JNL_RECS message, msg_len is guaranteed to be 8-byte aligned here */
- buffp += REPL_MSG_HDRLEN2;
+ buffp += processed_hdrlen;
exp_data_len = gtmrecv_repl_uncmpmsglen;
- buff_unprocessed -= REPL_MSG_HDRLEN2;
+ buff_unprocessed -= processed_hdrlen;
GTMRECV_SET_BUFF_TARGET_CMPBUFF(gtmrecv_repl_cmpmsglen, gtmrecv_repl_uncmpmsglen,
gtmrecv_cur_cmpmsglen);
} else
{
- msg_len = ((repl_msg_ptr_t)buffp)->len - REPL_MSG_HDRLEN;
+ processed_hdrlen = REPL_MSG_HDRLEN;
+ msg_len = ((repl_msg_ptr_t)buffp)->len - processed_hdrlen;
exp_data_len = msg_len;
if (REPL_TR_JNL_RECS == msg_type || REPL_OLD_TRIPLE == msg_type || REPL_HISTREC == msg_type)
{
@@ -2991,8 +3022,8 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
PREPARE_RECVPOOL_FOR_WRITE(exp_data_len, 0);
DEBUG_ONLY(recvpool_prepared = TRUE);
} /* for REPL_TR_CMP_JNL_RECS{2}, receive pool is prepared after uncompression */
- buffp += REPL_MSG_HDRLEN;
- buff_unprocessed -= REPL_MSG_HDRLEN;
+ buffp += processed_hdrlen;
+ buff_unprocessed -= processed_hdrlen;
}
assert(0 <= buff_unprocessed);
assert(0 == (msg_len % REPL_MSG_ALIGN));
@@ -3477,13 +3508,6 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
assert(IF_INVALID != repl_filter_cur2old[remote_jnl_ver - JNL_VER_EARLIEST_REPL]);
assert(IF_NONE != repl_filter_cur2old[remote_jnl_ver - JNL_VER_EARLIEST_REPL]);
gtmrecv_filter |= INTERNAL_FILTER;
- /* Any time the ^#t global format version is bumped, the below
- * assert will trip. This way, anyone who bumps the trigger label
- * ensures that the internal filter routines in repl_filter.c are
- * accordingly changed to upgrade triggers before applying them
- * on the current database which supports the latest ^#t format.
- */
- assert(0 == MEMCMP_LIT(HASHT_GBL_CURLABEL, "2"));
gtmrecv_alloc_filter_buff(gtmrecv_max_repl_msglen);
} else
{
@@ -3662,8 +3686,8 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
buff_unprocessed += buffered_data_len;
data_len += buffered_data_len;
if (buffp_start != buff_start)
- memmove(buff_start, buffp_start, buff_unprocessed + REPL_MSG_HDRLEN);
- buffp = buff_start + REPL_MSG_HDRLEN; /* + REPL_MSG_HDRLEN since we already processed the header. */
+ memmove(buff_start, buffp_start, buff_unprocessed + processed_hdrlen);
+ buffp = buff_start + processed_hdrlen;
} else if (0 != buff_unprocessed)
{ /* We have an incomplete header. Move it to the beginning of the allocated buffer space. */
memmove(buff_start, buffp, buff_unprocessed);
diff --git a/sr_unix/gtmsecshr.c b/sr_unix/gtmsecshr.c
index 42e536e..84750e6 100644
--- a/sr_unix/gtmsecshr.c
+++ b/sr_unix/gtmsecshr.c
@@ -312,7 +312,7 @@ void gtmsecshr_init(char_ptr_t argv[], char **rundir, int *rundir_len)
gtmsecshr_mesg mesg;
struct stat stat_buf;
char *gtm_tmp_ptr;
- int rc;
+ int status;
int lib_gid;
struct stat dist_stat_buff;
# ifdef _AIX
@@ -452,8 +452,8 @@ void gtmsecshr_init(char_ptr_t argv[], char **rundir, int *rundir_len)
realpathbef[reclen-- - 1] = '\0'; /* Overwrite nl with null and decr length */
newtz = malloc(reclen); /* putenv arg must be new - no stack vars */
strcpy(newtz, realpathbef);
- rc = putenv(newtz);
- if (0 != rc)
+ PUTENV(status, newtz);
+ if (0 != status)
{
save_errno = errno;
send_msg_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_GTMSECSHRSTART, 3,
@@ -507,9 +507,9 @@ void gtmsecshr_init(char_ptr_t argv[], char **rundir, int *rundir_len)
/* Close standard IO devices - we don't need/want them as all IO goes to operator log. Else we would have IO devices
* tied to whatever process started gtmsecshr up which we definitely don't want.
*/
- CLOSEFILE(0, rc); /* No stdin */
- CLOSEFILE(1, rc); /* No stdout */
- CLOSEFILE(2, rc); /* No stderr */
+ CLOSEFILE(0, status); /* No stdin */
+ CLOSEFILE(1, status); /* No stdout */
+ CLOSEFILE(2, status); /* No stderr */
/* Init signal handling which works slightly different than in other utilities - gtmsecshr has its own handler which
* *calls* generic_signal_handler (which always returns for gtmsecshr) - we then drive our normal exit handling.
*/
@@ -519,7 +519,7 @@ void gtmsecshr_init(char_ptr_t argv[], char **rundir, int *rundir_len)
{ /* Close the file only if we have it open. This is to avoid a CLOSEFAIL error in case of
* trying to close an invalid file descriptor.
*/
- CLOSEFILE_IF_OPEN(file_des, rc);
+ CLOSEFILE_IF_OPEN(file_des, status);
}
if (-1 == CHDIR(P_tmpdir)) /* Switch to temporary directory as CWD */
{
diff --git a/sr_unix/gtmsource.c b/sr_unix/gtmsource.c
index dc6a7f5..6d46812 100644
--- a/sr_unix/gtmsource.c
+++ b/sr_unix/gtmsource.c
@@ -381,6 +381,7 @@ int gtmsource()
sgtm_putmsg(print_msg, VARLSTCNT(3) ERR_REPLINSTFREEZECOMMENT, 1, jnlpool.jnlpool_ctl->freeze_comment);
repl_log(gtmsource_log_fp, TRUE, TRUE, print_msg);
}
+ gtmsource_local->jnlfileonly = gtmsource_options.jnlfileonly;
do
{ /* If mode is passive, go to sleep. Wakeup every now and then and check to see if I have to become active. */
gtmsource_state = gtmsource_local->gtmsource_state = GTMSOURCE_START;
@@ -420,7 +421,7 @@ int gtmsource()
}
QWASSIGN(gtmsource_local->read_addr, jnlpool.jnlpool_ctl->write_addr);
gtmsource_local->read = jnlpool.jnlpool_ctl->write;
- gtmsource_local->read_state = READ_POOL;
+ gtmsource_local->read_state = gtmsource_local->jnlfileonly ? READ_FILE : READ_POOL;
read_jnl_seqno = gtmsource_local->read_jnl_seqno;
assert(read_jnl_seqno <= jnlpool.jnlpool_ctl->jnl_seqno);
if (read_jnl_seqno < jnlpool.jnlpool_ctl->jnl_seqno)
diff --git a/sr_unix/gtmsource.h b/sr_unix/gtmsource.h
index 4ccf6b6..8514df8 100644
--- a/sr_unix/gtmsource.h
+++ b/sr_unix/gtmsource.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2006, 2013 Fidelity Information Services, Inc.*
+ * Copyright 2006, 2014 Fidelity Information Services, Inc.*
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -31,10 +31,6 @@
*/
#define MERRORS_ARRAY_SZ (2 * 1024) /* 2k should be enough for a while */
-#ifdef VMS
-#define MAX_GSEC_KEY_LEN 32 /* 31 is allowed + 1 for NULL terminator */
-#endif
-
enum
{
READ_POOL,
@@ -350,10 +346,12 @@ typedef struct
int4 shutdown_time; /* Time allowed for shutdown in seconds */
char filter_cmd[MAX_FILTER_CMD_LEN]; /* command to run to invoke the external filter (if needed) */
global_latch_t gtmsource_srv_latch;
+ boolean_t jnlfileonly; /* Current source server is only reading from journal files */
# ifdef GTM_TLS
uint4 next_renegotiate_time; /* Time (in future) at which the next SSL/TLS renegotiation happens. */
int4 num_renegotiations; /* Number of SSL/TLS renegotiations that happened so far. */
# endif
+ int4 padding; /* Keep size % 8 == 0 */
} gtmsource_local_struct;
#if defined(__osf__) && defined(__alpha)
@@ -387,14 +385,6 @@ typedef gtmsource_local_struct *gtmsource_local_ptr_t;
#define JNLPOOL_CRIT_SIZE (JNLPOOL_CRIT_SPACE + SIZEOF(mutex_spin_parms_struct) + SIZEOF(node_local))
#define JNLDATA_BASE_OFF (JNLPOOL_CTL_SIZE + JNLPOOL_CRIT_SIZE + REPL_INST_HDR_SIZE + GTMSRC_LCL_SIZE + GTMSOURCE_LOCAL_SIZE)
-#ifdef VMS
-typedef struct
-{
- char name[MAX_GSEC_KEY_LEN];
- struct dsc$descriptor_s desc;
-} t_vms_shm_key;
-#endif
-
/* the below structure has various fields that point to different sections of the journal pool */
typedef struct
{
@@ -405,11 +395,6 @@ typedef struct
repl_inst_hdr_ptr_t repl_inst_filehdr; /* pointer to the instance file header section in the journal pool */
gtmsrc_lcl_ptr_t gtmsrc_lcl_array; /* pointer to the gtmsrc_lcl array section in the journal pool */
sm_uc_ptr_t jnldata_base; /* pointer to the start of the actual journal record data */
-#ifdef VMS
- sm_uc_ptr_t shm_range[2];
- t_vms_shm_key vms_jnlpool_key;
- int4 shm_lockid;
-#endif
} jnlpool_addrs;
#if defined(__osf__) && defined(__alpha)
@@ -459,6 +444,7 @@ typedef struct
boolean_t setfreeze; /* TRUE if -FREEZE was specified with a value, FALSE otherwise */
boolean_t freezeval; /* TRUE for -FREEZE=ON, FALSE for -FREEZE=OFF */
boolean_t setcomment; /* TRUE if -COMMENT was specified, FALSE otherwise */
+ boolean_t jnlfileonly; /* TRUE if -JNLFILEONLY was specified, FALSE otherwise */
int4 cmplvl;
int4 shutdown_time;
int4 buffsize;
diff --git a/sr_unix/gtmsource_get_opt.c b/sr_unix/gtmsource_get_opt.c
index 51478df..eaf9eff 100644
--- a/sr_unix/gtmsource_get_opt.c
+++ b/sr_unix/gtmsource_get_opt.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2006, 2013 Fidelity Information Services, Inc.*
+ * Copyright 2006, 2014 Fidelity Information Services, Inc.*
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -470,5 +470,6 @@ int gtmsource_get_opt(void)
else
gtmsource_options.showfreeze = TRUE;
}
+ gtmsource_options.jnlfileonly = (CLI_PRESENT == cli_present("JNLFILEONLY"));
return(0);
}
diff --git a/sr_unix/gtmsource_process.c b/sr_unix/gtmsource_process.c
index 07d8f03..339709d 100644
--- a/sr_unix/gtmsource_process.c
+++ b/sr_unix/gtmsource_process.c
@@ -220,13 +220,9 @@ error_def(ERR_JNLNEWREC);
error_def(ERR_JNLSETDATA2LONG);
error_def(ERR_REPLCOMM);
error_def(ERR_REPLFTOKSEM);
-error_def(ERR_REPLGBL2LONG);
error_def(ERR_REPLINSTNOHIST);
-error_def(ERR_REPLNOMULTILINETRG);
error_def(ERR_REPLNOTLS);
-error_def(ERR_REPLRECFMT);
error_def(ERR_REPLXENDIANFAIL);
-error_def(ERR_SECNODZTRIGINTP);
error_def(ERR_TRIG2NOTRIG);
error_def(ERR_TLSRENEGOTIATE);
error_def(ERR_TEXT);
@@ -1090,11 +1086,6 @@ int gtmsource_process(void)
else
remote_side->null_subs_xform = FALSE;
gtmsource_filter |= INTERNAL_FILTER;
- /* Any time the ^#t global format version is bumped, the below assert will trip. This way, anyone who bumps
- * the trigger label ensures that the internal filter routines in repl_filter.c are accordingly changed to
- * downgrade triggers before sending them across to a receiver that understands ONLY the prior ^#t format.
- */
- assert(0 == MEMCMP_LIT(HASHT_GBL_CURLABEL, "2"));
gtmsource_alloc_filter_buff(gtmsource_msgbufsiz);
} else
{
@@ -1540,12 +1531,8 @@ int gtmsource_process(void)
* do at this point.
*/
assert(intfilter_error);
- assert((EREPL_INTLFILTER_BADREC == repl_errno)
- || (EREPL_INTLFILTER_REPLGBL2LONG == repl_errno)
- || (EREPL_INTLFILTER_SECNODZTRIGINTP == repl_errno)
- || (EREPL_INTLFILTER_MULTILINEXECUTE == repl_errno));
assert(filter_seqno == pre_read_seqno);
- INT_FILTER_RTS_ERROR(filter_seqno); /* no return */
+ INT_FILTER_RTS_ERROR(filter_seqno, repl_errno); /* no return */
}
}
assert(send_tr_len && (0 == (send_tr_len % REPL_MSG_ALIGN)));
@@ -1671,12 +1658,8 @@ int gtmsource_process(void)
* the receiever server will communicate the appropriate sequence number as
* part of the histinfo exchange.
*/
- assert((EREPL_INTLFILTER_BADREC == repl_errno)
- || (EREPL_INTLFILTER_REPLGBL2LONG == repl_errno)
- || (EREPL_INTLFILTER_SECNODZTRIGINTP == repl_errno)
- || (EREPL_INTLFILTER_MULTILINEXECUTE == repl_errno));
assert(filter_seqno <= post_read_seqno);
- INT_FILTER_RTS_ERROR(filter_seqno); /* no return */
+ INT_FILTER_RTS_ERROR(filter_seqno, repl_errno); /* no return */
}
jnlpool.gtmsource_local->read_jnl_seqno = post_read_seqno;
if (GTMSOURCE_FH_FLUSH_INTERVAL <= difftime(gtmsource_now, gtmsource_last_flush_time))
diff --git a/sr_unix/gtmsource_process_ops.c b/sr_unix/gtmsource_process_ops.c
index 8646799..58b2f46 100644
--- a/sr_unix/gtmsource_process_ops.c
+++ b/sr_unix/gtmsource_process_ops.c
@@ -1384,11 +1384,16 @@ boolean_t gtmsource_get_instance_info(boolean_t *secondary_was_rootprimary, seq_
needinst_msg.lms_group_info = jnlpool.repl_inst_filehdr->lms_group_info;
/* Need to byteswap a few multi-byte fields to take into account the receiver endianness */
assert(remote_side->endianness_known); /* only then is remote_side->cross_endian reliable */
- if (remote_side->cross_endian && (this_side->jnl_ver < remote_side->jnl_ver))
+ /* Starting GT.M V62001, the receiver server expects an endian converted lms_group_info. So endian
+ * convert in that case. Pre-V62001, the receiver unconditionally did the endian conversion. So skip
+ * endian conversion in the source side in that case.
+ */
+ if (remote_side->cross_endian && (REPL_PROTO_VER_XENDIANFIXES <= remote_side->proto_ver))
ENDIAN_CONVERT_REPL_INST_UUID(&needinst_msg.lms_group_info);
needinst_msg.proto_ver = REPL_PROTO_VER_THIS;
needinst_msg.is_rootprimary = !(jnlpool.jnlpool_ctl->upd_disabled);
needinst_msg.is_supplementary = jnlpool.repl_inst_filehdr->is_supplementary;
+ needinst_msg.jnl_ver = JNL_VER_THIS;
gtmsource_repl_send((repl_msg_ptr_t)&needinst_msg, "REPL_NEED_INSTINFO", MAX_SEQNO, INVALID_SUPPL_STRM);
if ((GTMSOURCE_CHANGING_MODE == gtmsource_state) || (GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state))
return FALSE; /* send did not succeed */
diff --git a/sr_unix/gtmsource_readfiles.c b/sr_unix/gtmsource_readfiles.c
index 9ed8342..014776c 100644
--- a/sr_unix/gtmsource_readfiles.c
+++ b/sr_unix/gtmsource_readfiles.c
@@ -814,7 +814,7 @@ static void increase_buffer(unsigned char **buff, int *buflen, int buffer_needed
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
LEN_AND_LIT("Error extending buffer space while reading files. Malloc error"), alloc_status);
}
- REPL_DPRINT3("Old gtmsource_msgp = 0x%llx; New gtmsource_msgp = 0x%llx\n", (long long)old_msgp, (long long)gtmsource_msgp);
+ REPL_DPRINT3("Old gtmsource_msgp = 0x%llx; New gtmsource_msgp = 0x%llx\n", old_msgp, gtmsource_msgp);
REPL_DPRINT2("Old *buff = 0x%llx\n", *buff);
*buff = (unsigned char *)gtmsource_msgp + (*buff - old_msgp);
REPL_DPRINT2("New *buff = 0x%llx\n", *buff);
@@ -1000,7 +1000,7 @@ static tr_search_state_t do_linear_search(repl_ctl_element *ctl, uint4 lo_addr,
srch_status->seqno = rec_jnl_seqno;
}
if (ctl->max_seqno < rec_jnl_seqno)
- CTL_SET_MAX_SEQNO(ctl, rec_jnl_seqno, b->recaddr, b->recaddr, DO_EOF_ADDR_CHECK);
+ CTL_SET_MAX_SEQNO(ctl, rec_jnl_seqno, b->recaddr, b->recaddr, SKIP_EOF_ADDR_CHECK);
QWASSIGN(ctl->seqno, rec_jnl_seqno);
ctl->tn = ((jrec_prefix *)b->recbuff)->tn;
if (QWEQ(rec_jnl_seqno, read_seqno))
@@ -1386,11 +1386,14 @@ static int read_and_merge(unsigned char *buff, int maxbufflen, seq_num read_jnl_
} else
repl_log(gtmsource_log_fp, FALSE, TRUE, "\n");
}
- if (TREF(gtm_environment_init)
- DEBUG_ONLY(&& (WBTEST_CLOSE_JNLFILE != gtm_white_box_test_case_number)))
- gtm_fork_n_core();
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SEQNUMSEARCHTIMEOUT, 2,
- &read_jnl_seqno, &read_jnl_seqno);
+ if (!jnlpool.gtmsource_local->jnlfileonly)
+ {
+ if (TREF(gtm_environment_init)
+ DEBUG_ONLY(&& (WBTEST_CLOSE_JNLFILE != gtm_white_box_test_case_number)))
+ gtm_fork_n_core();
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SEQNUMSEARCHTIMEOUT, 2,
+ &read_jnl_seqno, &read_jnl_seqno);
+ }
}
}
}
@@ -1818,7 +1821,7 @@ int gtmsource_readfiles(unsigned char *buff, int *data_len, int maxbufflen, bool
maxbufflen = gtmsource_msgbufsiz - REPL_MSG_HDRLEN;
}
} while (TRUE);
- if (file2pool)
+ if (file2pool && !gtmsource_local->jnlfileonly)
{
gtmsource_local->read = (uint4)(read_addr % jnlpool_size) ;
gtmsource_local->read_state = read_state = READ_POOL;
diff --git a/sr_unix/gtmsrc.csh b/sr_unix/gtmsrc.csh
index ab571d2..af170ec 100644
--- a/sr_unix/gtmsrc.csh
+++ b/sr_unix/gtmsrc.csh
@@ -1,6 +1,6 @@
#################################################################
# #
-# Copyright 2001 Sanchez Computer Associates, Inc. #
+# Copyright 2001, 2014 Fidelity Information Services, Inc #
# #
# This source code contains the intellectual property #
# of its copyright holder(s), and is made available #
@@ -83,7 +83,7 @@ if ( $?gtmsrc_last_exe == "1" ) then
set path = `echo $path | sed -e "s|$gtmsrc_last_exe|$gtm_exe|"`
# (Note: the use of an intermediate gtmroutines shell variable is necessary for csh; tcsh doesn't require it.)
- set gtmsrc_gtmroutines = `echo $gtmroutines | sed -e "s|$gtmsrc_last_exe|$gtm_exe|"`
+ set gtmsrc_gtmroutines = `echo "$gtmroutines" | sed -e "s|$gtmsrc_last_exe|$gtm_exe|"`
setenv gtmroutines "$gtmsrc_gtmroutines"
endif
setenv gtmsrc_last_exe $gtm_exe
diff --git a/sr_unix/gv_trigger.c b/sr_unix/gv_trigger.c
index ea58a16..031e76c 100644
--- a/sr_unix/gv_trigger.c
+++ b/sr_unix/gv_trigger.c
@@ -88,6 +88,7 @@ error_def(ERR_DBROLLEDBACK);
error_def(ERR_GVKILLFAIL);
error_def(ERR_GVPUTFAIL);
error_def(ERR_GVZTRIGFAIL);
+error_def(ERR_NEEDTRIGUPGRD);
error_def(ERR_INDRMAXLEN);
error_def(ERR_PATMAXLEN);
error_def(ERR_TEXT);
@@ -100,20 +101,15 @@ error_def(ERR_TRIGSUBSCRANGE);
LITREF char ctypetab[NUM_CHARS];
LITREF int4 gvtr_cmd_mask[GVTR_CMDTYPES];
LITREF mval gvtr_cmd_mval[GVTR_CMDTYPES];
-LITREF mval literal_cmd;
-LITREF mval literal_delim;
-LITREF mval literal_gvsubs;
+LITREF mval literal_zero;
LITREF mval literal_hashcount;
LITREF mval literal_hashcycle;
LITREF mval literal_hashlabel;
-LITREF mval literal_hasht;
-LITREF mval literal_options;
-LITREF mval literal_pieces;
-LITREF mval literal_xecute;
-LITREF mval literal_trigname;
-LITREF mval literal_chset;
-LITREF mval literal_zdelim;
-LITREF mval literal_zero;
+LITREF mval literal_null;
+
+#define TRIGGER_SUBSDEF(SUBSTYPE, SUBSNAME, LITMVALNAME, TRIGFILEQUAL, PARTOFHASH) LITREF mval LITMVALNAME;
+#include "trigger_subs_def.h"
+#undef TRIGGER_SUBSDEF
#define GVTR_PARSE_POINT 1
#define GVTR_PARSE_LEFT 2
@@ -248,7 +244,7 @@ LITREF mval literal_zero;
}
/* This error macro is used for all definition errors where the target is ^#t(GVN,<index>,<required subscript>) */
-#define HASHT_GVN_DEFINITION_RETRY_OR_ERROR(INDEX,SUBSCRIPT,CSA) \
+#define GVTR_HASHT_GVN_DEFINITION_RETRY_OR_ERROR(INDEX,SUBSCRIPT,CSA) \
{ \
if (CDB_STAGNATE > t_tries) \
{ \
@@ -370,8 +366,8 @@ STATICFNDEF void gvtr_db_tpwrap_helper(sgmnt_addrs *csa, int err_code, boolean_t
REVERT;
}
-/* Helper function used by "gvtr_db_read_hasht" function */
-STATICFNDEF boolean_t gvtr_get_hasht_gblsubs(mval *subs_mval, mval *ret_mval)
+/* Helper function used by "gvtr_db_read_hasht" and "trigger_upgrade" functions */
+boolean_t gvtr_get_hasht_gblsubs(mval *subs_mval, mval *ret_mval)
{
uint4 curend;
boolean_t was_null = FALSE, is_null = FALSE, is_defined;
@@ -390,26 +386,6 @@ STATICFNDEF boolean_t gvtr_get_hasht_gblsubs(mval *subs_mval, mval *ret_mval)
return is_defined;
}
-STATICFNDEF boolean_t gvtr_get_hasht_gblsubs_and_index(mval *subs_mval, mval *index, mval *ret_mval)
-{
- uint4 curend;
- boolean_t was_null = FALSE, is_null = FALSE, is_defined;
- DCL_THREADGBL_ACCESS;
-
- SETUP_THREADGBL_ACCESS;
- is_defined = FALSE;
- curend = gv_currkey->end; /* note down gv_currkey->end before changing it so we can restore it before function returns */
- assert(KEY_DELIMITER == gv_currkey->base[curend]);
- assert(gv_target->gd_csa == cs_addrs);
- COPY_SUBS_TO_GVCURRKEY(subs_mval, gv_cur_region, gv_currkey, was_null, is_null); /* updates gv_currkey */
- COPY_SUBS_TO_GVCURRKEY(index, gv_cur_region, gv_currkey, was_null, is_null); /* updates gv_currkey */
- is_defined = gvcst_get(ret_mval);
- assert(!is_defined || (MV_STR & ret_mval->mvtype)); /* assert that gvcst_get() sets type of mval to MV_STR */
- gv_currkey->end = curend; /* reset gv_currkey->end to what it was at function entry */
- gv_currkey->base[curend] = KEY_DELIMITER; /* restore terminator for entire key so key is well-formed */
- return is_defined;
-}
-
STATICFNDEF uint4 gvtr_process_range(gv_namehead *gvt, gvtr_subs_t *subsdsc, int type, char *start, char *end)
{
mval tmpmval;
@@ -668,8 +644,16 @@ void gvtr_db_read_hasht(sgmnt_addrs *csa)
{ /* ^#t global does not exist. Return right away. */
DBGTRIGR((stderr, "gvtr_db_read_hasht: no triggers\n"));
GVTR_HASHTGBL_READ_CLEANUP(TRUE);
+ csa->hdr->hasht_upgrade_needed = FALSE; /* Reset now that we know there is no ^#t global in this db.
+ * Note: It is safe to do so even if we dont hold crit.
+ */
return;
}
+ if (csa->hdr->hasht_upgrade_needed)
+ { /* ^#t needs to be upgraded first before reading it. Cannot proceed. */
+ GVTR_HASHTGBL_READ_CLEANUP(TRUE);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_NEEDTRIGUPGRD, 2, DB_LEN_STR(gv_cur_region));
+ }
/* ^#t global exists.
* Initialize gv_target->gvt_trigger from ^#t(<gbl>,...) where <gbl> is the global corresponding to save_gvtarget.
*
@@ -683,7 +667,7 @@ void gvtr_db_read_hasht(sgmnt_addrs *csa)
*
* ^#t global structure created by MUPIP TRIGGER
* ----------------------------------------------
- * ^#t("GBL","#LABEL")="1" # Format of the ^#t global for GBL. Currently set to 1.
+ * ^#t("GBL","#LABEL")="3" # Format of the ^#t global for GBL. Currently set to 3.
* # Will get bumped up in the future when the ^#t global format changes.
* ^#t("GBL","#CYCLE")=<32-bit-decimal-number> # incremented every time any trigger changes happen in ^GBL global
* ^#t("GBL","#COUNT")=1 # indicating there is 1 trigger currently defined for ^GBL global
@@ -701,7 +685,7 @@ void gvtr_db_read_hasht(sgmnt_addrs *csa)
* Read ^#t("GBL","#LABEL")
* -----------------------------------------------------------------------------
*/
- /* Check value of ^#t("GBL","#LABEL"). We expect it to be 1 indicating the format of the ^#t global.
+ /* Check value of ^#t("GBL","#LABEL"). We expect it to indicate the current format of the ^#t global.
* If not, it is an integ error in the ^#t global so issue an appropriate error.
*/
gvt = save_gvtarget; /* use smaller variable name as it is going to be used in lots of places below */
@@ -803,7 +787,7 @@ void gvtr_db_read_hasht(sgmnt_addrs *csa)
/* Read in ^#t("GBL",1,"TRIGNAME")="GBL#1" */
is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_trigname, ret_mval);
if (!is_defined)
- HASHT_GVN_DEFINITION_RETRY_OR_ERROR(trigidx,",\"TRIGNAME\"", csa);
+ GVTR_HASHT_GVN_DEFINITION_RETRY_OR_ERROR(trigidx,",\"TRIGNAME\"", csa);
trigdsc->rtn_desc.rt_name = ret_mval->str; /* Copy trigger name mident */
trigdsc->gvt_trigger = gvt_trigger; /* Save ptr to our main gvt_trigger struct for this trigger. With
* this and given a gv_trigger_t, we can get to the gvt_trigger_t
@@ -821,7 +805,7 @@ void gvtr_db_read_hasht(sgmnt_addrs *csa)
/* Read in ^#t("GBL",1,"CMD")="S,K,ZK,ZTK,ZTR" */
is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_cmd, ret_mval);
if (!is_defined)
- HASHT_GVN_DEFINITION_RETRY_OR_ERROR(trigidx,",\"CMD\"", csa);
+ GVTR_HASHT_GVN_DEFINITION_RETRY_OR_ERROR(trigidx,",\"CMD\"", csa);
/* Initialize trigdsc->cmdmask */
ptr = ret_mval->str.addr;
ptr_top = ptr + ret_mval->str.len;
@@ -1035,14 +1019,13 @@ void gvtr_db_read_hasht(sgmnt_addrs *csa)
{
assert(!delim_defined); /* DELIM and ZDELIM should NOT have been specified at same time */
trigdsc->is_zdelim = TRUE;
- /* Initialize trigdsc->delimiter */
- trigdsc->delimiter = ret_mval->str;
}
}
if (delim_defined || zdelim_defined) /* order of || is important since latter is set only if former is FALSE */
{
- trigdsc->delimiter = ret_mval->str;
- GVTR_POOL2BUDDYLIST(gvt_trigger, &trigdsc->delimiter);
+ /* Initialize trigdsc->delimiter */
+ trigdsc->delimiter = *ret_mval;
+ GVTR_POOL2BUDDYLIST(gvt_trigger, &trigdsc->delimiter.str);
}
/* Read in ^#t("GBL",1,"PIECES")="2:6;8" */
is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_pieces, ret_mval);
@@ -1084,7 +1067,7 @@ void gvtr_db_read_hasht(sgmnt_addrs *csa)
/* Read in ^#t("GBL",1,"CHSET")="UTF-8". If CHSET does not match gtm_chset issue error. */
is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_chset, ret_mval);
if (!is_defined)
- HASHT_GVN_DEFINITION_RETRY_OR_ERROR(trigidx,",\"CHSET\"", csa);
+ GVTR_HASHT_GVN_DEFINITION_RETRY_OR_ERROR(trigidx,",\"CHSET\"", csa);
if ((!gtm_utf8_mode && ((STR_LIT_LEN(CHSET_M_STR) != ret_mval->str.len)
|| memcmp(ret_mval->str.addr, CHSET_M_STR, STR_LIT_LEN(CHSET_M_STR))))
|| (gtm_utf8_mode && ((STR_LIT_LEN(CHSET_UTF8_STR) != ret_mval->str.len)
@@ -1331,7 +1314,6 @@ void gvtr_init(gv_namehead *gvt, uint4 cycle, boolean_t tp_is_implicit, int err_
{
sgmnt_addrs *csa;
sgmnt_data_ptr_t csd;
- gv_namehead *dir_tree;
uint4 lcl_t_tries, save_t_tries, loopcnt;
uint4 cycle_start;
boolean_t root_srch_needed;
@@ -1345,9 +1327,16 @@ void gvtr_init(gv_namehead *gvt, uint4 cycle, boolean_t tp_is_implicit, int err_
save_t_tries = t_tries; /* note down the value of t_tries at the entry to this function */
csa = gvt->gd_csa;
assert(NULL != csa); /* database for this gvt better be opened at this point */
- dir_tree = csa->dir_tree;
- if (gvt == dir_tree)
- return; /* trigger initialization should return for directory tree (e.g. set^%GBLDEF is caller) */
+ /* The directory tree corresponds to a non-existent global which does not have any triggers so in this case
+ * return right away. No trigger initialization needed.
+ */
+ if (gvt == csa->dir_tree)
+ return;
+ /* We know there are no triggers for the ^#t global so return right away in that case too.
+ * In fact it is necessary to do this if "trigger_upgrade" is caller as we dont want a NEEDTRIGUPGRD error there.
+ */
+ if (gvt == csa->hasht_tree)
+ return;
csd = csa->hdr;
assert((gvt->db_trigger_cycle != cycle) || (gvt->db_dztrigger_cycle < csa->db_dztrigger_cycle));
root_srch_needed = FALSE;
@@ -1580,7 +1569,7 @@ int gvtr_match_n_invoke(gtm_trigger_parms *trigparms, gvtr_invoke_parms_t *gvtr_
(NULL != trigdsc) && (trigdsc != trigstop);
--trigmax, trigdsc = *(gv_trigger_t **)((char *)trigdsc + trig_list_offset)) /* Follow the designated list */
{
- DBGTRIGR((stderr, "gvtr_match_n_invoke: top of trigr scan loop\n"));
+ DBGTRIGR((stderr, "gvtr_match_n_invoke: top of trigr scan loop (%d)\n", trigmax));
trigstop = trigstart; /* Stop when we get back to where we started */
assertpro(0 <= trigmax); /* Loop ender "just in case" */
assert(trigdsc >= gvt_trigger->gv_trig_array);
@@ -1623,13 +1612,15 @@ int gvtr_match_n_invoke(gtm_trigger_parms *trigparms, gvtr_invoke_parms_t *gvtr_
* If so, check if any of those pieces are different. If not, trigger should NOT be invoked.
*/
ok_to_invoke_trigger = TRUE;
+ trigparms->ztdelim_new = (mval *)&literal_null;
if (is_set_trigger)
{
assert(0 == ztupd_mval->mvtype);
- if (trigdsc->delimiter.len)
+ if (trigdsc->delimiter.str.len)
{
+ trigparms->ztdelim_new = (mval *)&trigdsc->delimiter;
strpiecediff(&trigparms->ztoldval_new->str, &trigparms->ztvalue_new->str,
- &trigdsc->delimiter, trigdsc->numpieces, trigdsc->piecearray,
+ &trigdsc->delimiter.str, trigdsc->numpieces, trigdsc->piecearray,
!trigdsc->is_zdelim && gtm_utf8_mode, ztupd_mstr);
if (!ztupd_mstr->len)
{ /* No pieces of interest changed. So dont invoke trigger. */
diff --git a/sr_unix/gv_trigger.h b/sr_unix/gv_trigger.h
index 74c30be..527f8fe 100644
--- a/sr_unix/gv_trigger.h
+++ b/sr_unix/gv_trigger.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2013 Fidelity Information Services, Inc *
+ * Copyright 2010, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -128,7 +128,7 @@ typedef struct gv_trigger_struct
* piecearray[1].min=8, piecearray[1].max=8 */
rtn_tabent rtn_desc; /* Compiled routine name/objcode; Inited by gvtr_db_read_hasht() */
boolean_t is_zdelim; /* TRUE if "ZDELIM" was specified; FALSE if "DELIM" was specified */
- mstr delimiter; /* is a copy of ^#t(<GBL>,<index>,"DELIM") or ^#t(..."ZDELIM") whichever is defined */
+ mval delimiter; /* is a copy of ^#t(<GBL>,<index>,"DELIM") or ^#t(..."ZDELIM") whichever is defined */
mstr options; /* is a copy of ^#t(<GBL>,<index>,"OPTIONS") */
mval xecute_str; /* Trigger code to execute */
struct gvt_trigger_struct /* top of gvt_trigger block this trigger belongs to. Used in src lookup when we know */
@@ -201,11 +201,21 @@ typedef struct gvtr_invoke_parms_struct
ztrig_cycle_mismatch = (CSA->db_dztrigger_cycle && (GVT->db_dztrigger_cycle != CSA->db_dztrigger_cycle)); \
db_trigger_cycle_mismatch = (GVT->db_trigger_cycle != cycle); \
cycle_mismatch = (db_trigger_cycle_mismatch || ztrig_cycle_mismatch); \
+ DBGTRIGR((stderr, "GVTR_INIT_AND_TPWRAP_IF_NEEDED: CSA->db_ztrigger_cycle=%d\n", cycle)); \
+ DBGTRIGR((stderr, "GVTR_INIT_AND_TPWRAP_IF_NEEDED: GVT->db_trigger_cycle=%d\n", GVT->db_trigger_cycle)); \
+ DBGTRIGR((stderr, "GVTR_INIT_AND_TPWRAP_IF_NEEDED: CSA->db_dztrigger_cycle=%d\n", CSA->db_dztrigger_cycle)); \
+ DBGTRIGR((stderr, "GVTR_INIT_AND_TPWRAP_IF_NEEDED: GVT->db_dztrigger_cycle=%d\n", GVT->db_dztrigger_cycle)); \
+ DBGTRIGR((stderr, "GVTR_INIT_AND_TPWRAP_IF_NEEDED: local_tn=%d\n", local_tn)); \
+ DBGTRIGR((stderr, "GVTR_INIT_AND_TPWRAP_IF_NEEDED: GVT->trig_local_tn=%d\n", GVT->trig_local_tn)); \
+ DBGTRIGR((stderr, "GVTR_INIT_AND_TPWRAP_IF_NEEDED: ztrig_cycle_mismatch=%d\n", ztrig_cycle_mismatch)); \
+ DBGTRIGR((stderr, "GVTR_INIT_AND_TPWRAP_IF_NEEDED: db_trigger_cycle_mismatch=%d\n", db_trigger_cycle_mismatch)); \
+ DBGTRIGR((stderr, "GVTR_INIT_AND_TPWRAP_IF_NEEDED: cycle_mismatch=%d t_tries=%d\n", cycle_mismatch, t_tries)); \
/* Set up wrapper even if no triggers if this is for ZTRIGGER command */ \
if (cycle_mismatch || (NULL != GVT->gvt_trigger) || (ERR_GVZTRIGFAIL == T_ERR)) \
{ /* Create TP wrap if needed */ \
if (!dollar_tlevel) \
{ /* need to create implicit TP wrap */ \
+ DBGTRIGR((stderr, "GVTR_INIT_AND_TPWRAP_IF_NEEDED: creating TP wrapper\n")); \
DEBUG_ONLY(was_nontp = TRUE;) \
assert(!LCL_TSTART); \
/* Set a debug-only global variable to indicate that from now onwards, until the completion of this \
@@ -415,8 +425,8 @@ typedef struct gvtr_invoke_parms_struct
hasht_tree = CSA->hasht_tree; \
if (NULL == hasht_tree) \
{ /* Allocate gv_target like structure for "^#t" global in this database file */ \
- gvname.var_name.addr = literal_hasht.str.addr; \
- gvname.var_name.len = literal_hasht.str.len; \
+ gvname.var_name.addr = HASHT_GBLNAME; \
+ gvname.var_name.len = HASHT_GBLNAME_LEN; \
gvname.marked = FALSE; \
COMPUTE_HASH_MNAME(&gvname); \
hasht_tree = targ_alloc(CSA->hdr->max_key_size, &gvname, NULL); \
@@ -430,6 +440,10 @@ typedef struct gvtr_invoke_parms_struct
{ \
unsigned char *key; \
\
+ GBLREF gv_key *gv_currkey; \
+ GBLREF gd_region *gv_cur_region; \
+ GBLREF sgmnt_data_ptr_t cs_data; \
+ \
key = &gv_currkey->base[0]; \
memcpy(key, HASHT_GBLNAME, HASHT_GBLNAME_FULL_LEN); /* including terminating '\0' subscript */ \
key += HASHT_GBLNAME_FULL_LEN; \
@@ -445,23 +459,28 @@ typedef struct gvtr_invoke_parms_struct
GVCST_ROOT_SEARCH; \
}
-#define SWITCH_TO_DEFAULT_REGION \
-{ \
- GBLREF uint4 dollar_tlevel; \
- GBLREF gd_addr *gd_header; \
- GBLREF gv_namehead *gv_target; \
- \
- gd_region *default_region; \
- \
- assert(NULL != gd_header); \
- default_region = gd_header->maps->reg.addr; \
- if (!default_region->open) \
- gv_init_reg(default_region); \
- TP_CHANGE_REG_IF_NEEDED(default_region); \
- SET_GVTARGET_TO_HASHT_GBL(cs_addrs); \
- assert(NULL != gv_target); \
- if (dollar_tlevel) \
- tp_set_sgm(); \
+/* Caller has to check for "NULL" value of "cs_addrs" and act accordingly */
+#define GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(reg) \
+{ \
+ GBLREF uint4 dollar_tlevel; \
+ GBLREF gv_namehead *gv_target; \
+ GBLREF gd_region *gv_cur_region; \
+ GBLREF gv_key *gv_currkey; \
+ \
+ if (!reg->open) \
+ gv_init_reg(reg); \
+ gv_cur_region = reg; \
+ change_reg(); /* TP_CHANGE_REG wont work as we need to set sgm_info_ptr */ \
+ if (NULL != cs_addrs) \
+ { \
+ SET_GVTARGET_TO_HASHT_GBL(cs_addrs); /* sets up gv_target */ \
+ assert(NULL != gv_target); \
+ INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED; /* sets up gv_currkey */ \
+ } else \
+ { \
+ DEBUG_ONLY(gv_target = NULL;) /* to keep cs_addrs/gv_target in sync */ \
+ DEBUG_ONLY(gv_currkey->base[0] = '\0';) /* to keep gv_target/gv_currkey in sync */ \
+ } \
}
GBLREF uint4 dollar_tlevel;
@@ -624,4 +643,19 @@ GBLREF int4 tstart_trigger_depth;
assert(MAX_TRIG_UTIL_LEN >= UTIL_LEN); \
}
+/* This error macro is used for all definition errors where the target is ^#t(GVN,<index>,<required subscript>) */
+#define HASHT_GVN_DEFINITION_RETRY_OR_ERROR(INDEX,SUBSCRIPT,CSA) \
+{ \
+ if (CDB_STAGNATE > t_tries) \
+ t_retry(cdb_sc_triggermod); \
+ else \
+ { \
+ assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number); \
+ /* format "INDEX,SUBSCRIPT" of ^#t(GVN,INDEX,SUBSCRIPT) in the error message */ \
+ SET_PARAM_STRING(util_buff, util_len, INDEX, SUBSCRIPT); \
+ rts_error_csa(CSA_ARG(CSA) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn, \
+ trigvn_len, trigvn, util_len, util_buff); \
+ } \
+}
+
#endif
diff --git a/sr_unix/gv_trigger_protos.h b/sr_unix/gv_trigger_protos.h
index 8a1d8e2..5c22775 100644
--- a/sr_unix/gv_trigger_protos.h
+++ b/sr_unix/gv_trigger_protos.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2012 Fidelity Information Services, Inc *
+ * Copyright 2010, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -13,8 +13,6 @@
#define GV_TRIGGER_PROTOS_H_INCLUDED
STATICFNDCL void gvtr_db_tpwrap_helper(sgmnt_addrs *csa, int err_code, boolean_t root_srch_needed);
-STATICFNDCL boolean_t gvtr_get_hasht_gblsubs(mval *subs_mval, mval *ret_mval);
-STATICFNDCL boolean_t gvtr_get_hasht_gblsubs_and_index(mval *subs_mval, mval *index, mval *ret_mval);
STATICFNDCL uint4 gvtr_process_range(gv_namehead *gvt, gvtr_subs_t *subsdsc, int type, char *start, char *end);
STATICFNDCL uint4 gvtr_process_pattern(char *ptr, uint4 len, gvtr_subs_t *subsdsc, gvt_trigger_t *gvt_trigger);
STATICFNDCL uint4 gvtr_process_gvsubs(char *start, char *end, gvtr_subs_t *subsdsc,
@@ -22,8 +20,9 @@ STATICFNDCL uint4 gvtr_process_gvsubs(char *start, char *end, gvtr_subs_t *subs
STATICFNDCL boolean_t gvtr_is_key_a_match(char *keysub_start[], gv_trigger_t *trigdsc, mval *lvvalarray[]);
STATICFNDCL boolean_t gvtr_is_value_a_match(mval *val, gv_trigger_t *trigdsc);
-void gvtr_db_read_hasht(sgmnt_addrs *csa);
-void gvtr_free(gv_namehead *gvt);
-void gvtr_init(gv_namehead *gvt, uint4 cycle, boolean_t tp_is_implicit, int err_code);
-int gvtr_match_n_invoke(gtm_trigger_parms *trigparms, gvtr_invoke_parms_t *gvtr_parms);
+boolean_t gvtr_get_hasht_gblsubs(mval *subs_mval, mval *ret_mval);
+void gvtr_db_read_hasht(sgmnt_addrs *csa);
+void gvtr_free(gv_namehead *gvt);
+void gvtr_init(gv_namehead *gvt, uint4 cycle, boolean_t tp_is_implicit, int err_code);
+int gvtr_match_n_invoke(gtm_trigger_parms *trigparms, gvtr_invoke_parms_t *gvtr_parms);
#endif
diff --git a/sr_unix/gvcst_init_sysops.c b/sr_unix/gvcst_init_sysops.c
index 8aea912..f49d8db 100644
--- a/sr_unix/gvcst_init_sysops.c
+++ b/sr_unix/gvcst_init_sysops.c
@@ -28,9 +28,7 @@
#include "gtm_string.h"
#include "gtm_sem.h"
#include "gtm_statvfs.h"
-#ifdef __linux__
-#include "hugetlbfs_overrides.h"
-#endif
+#include "hugetlbfs_overrides.h" /* for the ADJUST_SHM_SIZE_FOR_HUGEPAGES macro */
#include "gt_timer.h"
#include "gdsroot.h"
@@ -356,7 +354,7 @@ gd_region *dbfilopn (gd_region *reg)
free(seg->file_cntl);
seg->file_cntl = 0;
}
- RTS_ERROR(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), status);
}
assert(((int)pblk.b_esl + 1) <= SIZEOF(seg->fname));
memcpy(seg->fname, pblk.buffer, pblk.b_esl);
@@ -395,7 +393,7 @@ gd_region *dbfilopn (gd_region *reg)
free(seg->file_cntl);
seg->file_cntl = 0;
}
- RTS_ERROR(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), save_errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), save_errno);
}
reg->read_only = TRUE; /* maintain csa->read_write simultaneously */
csa->read_write = FALSE; /* maintain reg->read_only simultaneously */
@@ -408,7 +406,7 @@ gd_region *dbfilopn (gd_region *reg)
if (-1 == stat_res)
{
save_errno = errno;
- RTS_ERROR(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), save_errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), save_errno);
}
set_gdid_from_stat(&udi->fileid, &buf);
if (prev_reg = gv_match(reg))
@@ -446,11 +444,7 @@ void dbsecspc(gd_region *reg, sgmnt_data_ptr_t csd, gtm_uint64_t *sec_size)
assertpro(dba_bg == reg->dyn.addr->acc_meth);
tmp_sec_size += CACHE_CONTROL_SIZE(csd) + (LOCK_BLOCK(csd) * DISK_BLOCK_SIZE);
}
-# ifdef HUGETLB_SUPPORTED
- *sec_size = ROUND_UP(tmp_sec_size, OS_HUGEPAGE_SIZE);
-# else
- *sec_size = ROUND_UP(tmp_sec_size, OS_PAGE_SIZE);
-# endif
+ ADJUST_SHM_SIZE_FOR_HUGEPAGES(tmp_sec_size, *sec_size); /* *sec_size is adjusted size */
return;
}
@@ -1158,7 +1152,7 @@ int db_init(gd_region *reg)
if (-1 == shmctl(csa->nl->jnlpool_shmid, IPC_STAT, &shmstat))
{
save_errno = errno;
- if ((EINVAL == save_errno) || (EIDRM == save_errno)) /* EIDRM is only on Linux */
+ if (SHM_REMOVED(save_errno))
{
replinst_mismatch = FALSE;
csa->nl->jnlpool_shmid = jnlpool.repl_inst_filehdr->jnlpool_shmid;
diff --git a/sr_unix/hugetlbfs_overrides.h b/sr_unix/hugetlbfs_overrides.h
new file mode 100644
index 0000000..b4a2126
--- /dev/null
+++ b/sr_unix/hugetlbfs_overrides.h
@@ -0,0 +1,34 @@
+/****************************************************************
+ * *
+ * Copyright 2014 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef HUGETLBFS_OVERRIDES_H_
+#define HUGETLBFS_OVERRIDES_H_
+
+#if defined(__linux__)
+# if ( defined(__i386__) || defined(__x86_64__) )
+# define HUGETLB_SUPPORTED 1
+# endif
+
+ GBLREF long gtm_os_hugepage_size;
+# define OS_HUGEPAGE_SIZE gtm_os_hugepage_size
+
+ extern int gtm_shmget(key_t __key, size_t __size, int __shmflg);
+ void libhugetlbfs_init(void);
+#endif
+
+#ifdef HUGETLB_SUPPORTED
+# define ADJUST_SHM_SIZE_FOR_HUGEPAGES(SRCSIZE, DSTSIZE) DSTSIZE = ROUND_UP(SRCSIZE, OS_HUGEPAGE_SIZE)
+#else
+ OS_PAGE_SIZE_DECLARE
+# define ADJUST_SHM_SIZE_FOR_HUGEPAGES(SRCSIZE, DSTSIZE) DSTSIZE = ROUND_UP(SRCSIZE, OS_PAGE_SIZE)
+#endif
+
+#endif /* HUGETLBFS_OVERRIDES_H_ */
diff --git a/sr_unix/incr_link.c b/sr_unix/incr_link.c
index f20e4ee..d33a815 100644
--- a/sr_unix/incr_link.c
+++ b/sr_unix/incr_link.c
@@ -12,7 +12,6 @@
#include "mdef.h"
#include <sys/types.h>
-#include <sys/mman.h>
#include <sys/shm.h>
#include <errno.h>
@@ -36,9 +35,12 @@
#include "gtmdbglvl.h"
#include "cmd_qlf.h" /* needed for CQ_UTF8 */
#include "gtm_text_alloc.h"
-#include "zhist.h"
#include "send_msg.h"
#include "cacheflush.h"
+#include "rtnobj.h"
+#include "zbreak.h"
+#include "interlock.h"
+#include "util.h"
/* Define linkage types */
typedef enum
@@ -71,6 +73,7 @@ typedef enum
{ \
free(hdr); \
hdr = NULL; \
+ RELEASE_RECENT_ZHIST; \
return IL_RECOMPILE; /* Signal recompile */ \
} \
}
@@ -115,40 +118,63 @@ error_def(ERR_DLLCHSETUTF8);
error_def(ERR_DLLVERSION);
error_def(ERR_INVOBJFILE);
error_def(ERR_LOADRUNNING);
-error_def(ERR_TEXT);
+error_def(ERR_RLNKRECLATCH);
error_def(ERR_SYSCALL);
+error_def(ERR_TEXT);
+error_def(ERR_ZLINKBYPASS);
error_def(ERR_ZLINKFILE);
STATICFNDCL void res_free(res_list *root);
STATICFNDCL boolean_t addr_fix(int file, unsigned char *shdr, linktype linktyp, urx_rtnref *urx_lcl);
-STATICFNDCL void zl_error(linktype linktyp, int4 file, int4 err, int4 len, char *addr, int4 len2, char *addr2);
-STATICFNDCL void zl_error_hskpng(linktype linktyp, int4 file);
+STATICFNDCL void zl_error(void *recent_zhist, linktype linktyp, int4 file, int4 err, int4 len, char *addr,
+ int4 len2, char *addr2);
+STATICFNDCL void zl_error_hskpng(linktype linktyp, int4 file, void *recent_zhist);
/* incr_link - read and process a mumps object module. Link said module to currently executing image */
-boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *fname)
+#ifdef AUTORELINK_SUPPORTED
+boolean_t incr_link(int file_desc, zro_ent *zro_entry, zro_hist *recent_zhist, uint4 fname_len, char *fname)
+#else
+boolean_t incr_link(int file_desc, zro_ent *zro_entry, uint4 fname_len, char *fname)
+#endif
{
- rhdtyp *old_rhead;
- int sect_ro_rel_size, sect_rw_rel_size, name_buf_len, alloc_len, order, rc, save_errno;
- uint4 lcl_compiler_qlf;
- boolean_t dynlits;
- ssize_t status, sect_rw_nonrel_size, sect_ro_rel_offset;
- size_t offset_correction;
- lab_tabent *lbt_ent, *lbt_bot, *lbt_top, *olbt_ent, *olbt_bot, *olbt_top;
- mident_fixed module_name;
- pre_v5_mident *pre_v5_routine_name;
- urx_rtnref urx_lcl_anchor;
- unsigned char *shdr, *rel_base, *newaddr;
- mval *curlit, *littop;
- lab_tabent *curlbe, *lbetop;
- var_tabent *curvar, *vartop;
- char name_buf[PATH_MAX + 1], marker[SIZEOF(JSB_MARKER) - 1], *rw_rel_start;
- linktype linktyp;
- struct stat obj_stat;
- ZOS_ONLY(ESD symbol;)
+ rhdtyp *old_rhead;
+ rtn_tabent *tabent_ptr;
+ int sect_ro_rel_size, sect_rw_rel_size, name_buf_len, alloc_len, order;
+ uint4 lcl_compiler_qlf;
+ boolean_t dynlits;
+ ssize_t status, sect_rw_nonrel_size, sect_ro_rel_offset;
+ size_t offset_correction, rtnname_off;
+ lab_tabent *lbt_ent, *lbt_bot, *lbt_top, *olbt_ent, *olbt_bot, *olbt_top;
+ mident_fixed module_name;
+ pre_v5_mident *pre_v5_routine_name;
+ urx_rtnref urx_lcl_anchor;
+ unsigned char *shdr, *rel_base, *newaddr;
+ mstr rtnname;
+ mval *curlit, *littop;
+ lab_tabent *curlbe, *lbetop;
+ var_tabent *curvar, *vartop;
+ char name_buf[PATH_MAX + 1], marker[SIZEOF(JSB_MARKER) - 1], *rw_rel_start;
+ char rtnname_buf[MAX_MIDENT_LEN];
+ linktype linktyp;
+ va_list save_last_va_list_ptr;
+ boolean_t util_copy_saved;
+ char *save_util_outptr;
+ int4 save_error_condition;
+ ZOS_ONLY(ESD symbol;)
# ifdef _AIX
- FILHDR hddr;
- unsigned short magic;
+ FILHDR hddr;
+ unsigned short magic;
# endif
+# ifdef AUTORELINK_SUPPORTED
+ relinkrec_t *rec;
+ zro_validation_entry *zhent;
+ open_relinkctl_sgm *linkctl;
+# ifdef DEBUG
+ relinkrec_t *relinkrec;
+ int rtnlen;
+ char save_char, *rtnname2;
+# endif /* DEBUG */
+# endif /* AUTORELINK_SUPPORTED */
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
@@ -161,9 +187,9 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
ZOS_FREE_TEXT_SECTION;
# endif
urx_lcl_anchor.len = 0;
- urx_lcl_anchor.addr = 0;
+ urx_lcl_anchor.addr = NULL;
urx_lcl_anchor.lab = 0;
- urx_lcl_anchor.next = 0;
+ urx_lcl_anchor.next = NULL;
assert(NULL == hdr);
assert(NULL == sect_ro_rel);
assert(NULL == sect_rw_rel);
@@ -172,18 +198,53 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
shdr = NULL;
sect_ro_rel = sect_rw_rel = sect_rw_nonrel = NULL;
if (file_desc)
- { /* This is a disk resident object we mmap and share if autorelink is enabled in that directory, or instead we
+ { /* This is a disk resident object we share if autorelink is enabled in that directory, or instead we
* read/link into process private storage if autorelink is not enabled.
*/
if ((NULL == zro_entry) || (NULL == zro_entry->relinkctl_sgmaddr))
+ {
linktyp = LINK_PPRIVOBJ;
- else
+ /* No history if process private link */
+ ARLINK_ONLY(assert(NULL == recent_zhist));
+ } else
+ {
linktyp = LINK_SHROBJ;
+# if defined(AUTORELINK_SUPPORTED) && defined(DEBUG)
+ /* Need a history if sharing the object */
+ assert(NULL != recent_zhist);
+ /* Later call to rtnobj_shm_malloc will use recent_zhist->end - 1 as the zro_validation_entry
+ * to get at the linkctl and relinkrec so assert that it is indeed linkctl corresponding to zro_entry.
+ */
+ assert((recent_zhist->end - 1)->relinkctl_bkptr
+ == (open_relinkctl_sgm *)zro_entry->relinkctl_sgmaddr);
+ relinkrec = (recent_zhist->end - 1)->relinkrec;
+ rtnlen = STRLEN(relinkrec->rtnname_fixed.c);
+ assert(fname_len >= (STR_LIT_LEN(DOTOBJ) + rtnlen));
+ rtnname2 = fname + fname_len - 1;
+ while (rtnname2 >= fname)
+ {
+ if ('/' == *rtnname2)
+ {
+ rtnname2++;
+ break;
+ }
+ rtnname2--;
+ }
+ save_char = *rtnname2;
+ if ('_' == save_char)
+ *rtnname2 = '%'; /* Temporary adjustment for below assert to not fail */
+ assert(!memcmp(relinkrec->rtnname_fixed.c, rtnname2, rtnlen));
+ if ('_' == save_char)
+ *rtnname2 = save_char; /* restore */
+# endif /* AUTORELINK_SUPPORTED && DEBUG */
+ }
NON_USHBIN_ONLY(assert(LINK_PPRIVOBJ == linktyp)); /* No autorelink in non-ushbin platform */
} else
- { /* With no file descriptor, this can only be linkage from a shared library */
+ {
+ /* With no file descriptor, this can only be linkage from a shared library and shared libraries have no history */
+ ARLINK_ONLY(assert(NULL == recent_zhist));
+ assert(NULL != zro_entry);
linktyp = LINK_SHRLIB;
- NON_USHBIN_ONLY(assert(FALSE /* Shared libraries not supported on this platform */));
}
/* Get the routine header where we can make use of it */
hdr = (rhdtyp *)malloc(SIZEOF(rhdtyp));
@@ -200,35 +261,9 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
memcpy(hdr, shdr, SIZEOF(rhdtyp));
hdr->shlib_handle = zro_entry->shrlib;
break;
- case LINK_SHROBJ:
- FSTAT_FILE(file_desc, &obj_stat, rc);
- if (-1 == rc)
- { /* Need to not use zl_error() here since need compound error to put out errno */
- save_errno = errno;
- ZOS_FREE_TEXT_SECTION;
- zl_error_hskpng(linktyp, file_desc);
- rts_error_csa(NULL, VARLSTCNT(5) ERR_ZLINKFILE, 2, fname_len, fname, save_errno);
- }
- /* Share the object file (in its entirety) via mmap() */
- shdr = (unsigned char *)mmap(NULL, obj_stat.st_size, PROT_EXEC|PROT_READ, MAP_SHARED, file_desc, 0)
- + NATIVE_HDR_LEN; /* shdr->routinehdr (past native object header) */
- if (MAP_FAILED == (void *)shdr)
- { /* If mmap() fails, send error to both process and to syslog. Note we do not use zlerror()
- * here since need to send a compound message about the failure.
- */
- save_errno = errno;
- send_msg_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_ZLINKFILE, 2, fname_len, fname, ERR_SYSCALL,
- 5, LEN_AND_LIT("mmap"), CALLFROM, save_errno);
- ZOS_FREE_TEXT_SECTION;
- zl_error_hskpng(linktyp, file_desc);
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_ZLINKFILE, 2, fname_len, fname, ERR_SYSCALL,
- 5, LEN_AND_LIT("mmap"), CALLFROM, save_errno);
- }
- memcpy(hdr, shdr, SIZEOF(rhdtyp));
- hdr->shared_len = obj_stat.st_size; /* Record length we shared so we can unmap it when done */
- break;
# endif
case LINK_PPRIVOBJ:
+ case LINK_SHROBJ:
/* Seek past native object headers to get GT.M object's routine header */
/* To check if it is not an xcoff64 bit .o */
# ifdef _AIX
@@ -239,11 +274,11 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
if (magic != U64_TOCMAGIC)
{
ZOS_FREE_TEXT_SECTION;
- zl_error_hskpng(linktyp, file_desc);
+ zl_error_hskpng(linktyp, file_desc, RECENT_ZHIST);
return IL_RECOMPILE;
}
} else
- zl_error(linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
+ zl_error(RECENT_ZHIST, linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
# endif
/* In the GOFF .o on zOS, if the symbol name(name of the module) exceeds ESD_NAME_MAX_LENGTH (8),
* then 2 extra extended records are emitted, which causes the start of text section to vary
@@ -252,20 +287,20 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
DOREADRC(file_desc, &symbol, SIZEOF(symbol), status); /* This is HDR record */
if (0 == status)
{
- DOREADRC(file_desc, &symbol, SIZEOF(symbol), status) /* First symbol (ESD record) */
- if (0 == status)
+ DOREADRC(file_desc, &symbol, SIZEOF(symbol), status); /* First symbol (ESD record) */
+ if (0 == status)
+ {
+ if (0x01 == symbol.ptv[1]) /* Means the extended records are there */
+ extended_symbols_present = TRUE;
+ else
{
- if (0x01 == symbol.ptv[1]) /* Means the extended records are there */
- extended_symbols_present = TRUE;
- else
- {
- assert(0x0 == symbol.ptv[1]);
- extended_symbols_present = FALSE;
- }
+ assert(0x0 == symbol.ptv[1]);
+ extended_symbols_present = FALSE;
}
+ }
}
if (0 != status)
- zl_error(linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
+ zl_error(RECENT_ZHIST, linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
# endif
if (-1 != (status = (ssize_t)lseek(file_desc, NATIVE_HDR_LEN, SEEK_SET)))
{
@@ -276,7 +311,7 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
if (0 != status)
{
CHECK_NONUSB_RECOMPILE_RETURN;
- zl_error(linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
+ zl_error(RECENT_ZHIST, linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
}
break;
default:
@@ -290,7 +325,7 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
{
CHECK_NONUSB_RECOMPILE_RETURN;
}
- zl_error(linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
+ zl_error(RECENT_ZHIST, linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
}
/* Binary version check. If no match, shlib gets error, otherwise signal recompile */
if (MAGIC_COOKIE != hdr->objlabel)
@@ -305,7 +340,7 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
pre_v5_routine_name = (pre_v5_mident *)((char*)hdr + PRE_V5_RTNHDR_RTNOFF);
for (len = 0; len < SIZEOF(pre_v5_mident) && pre_v5_routine_name->c[len]; len++)
;
- zl_error(linktyp, 0, ERR_DLLVERSION, len, &(pre_v5_routine_name->c[0]),
+ zl_error(RECENT_ZHIST, linktyp, 0, ERR_DLLVERSION, len, &(pre_v5_routine_name->c[0]),
zro_entry->str.len, zro_entry->str.addr);
}
# if defined(__osf__) || defined(__hppa)
@@ -315,7 +350,7 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
*/
v50v51_mstr *mstr5051; /* declare here so don't have to conditionally add above */
mstr5051 = (v50v51_mstr *)((char *)hdr + V50V51_RTNHDR_RTNMSTR_OFFSET);
- zl_error(linktyp, 0, ERR_DLLVERSION, mstr5051->len,
+ zl_error(RECENT_ZHIST, linktyp, 0, ERR_DLLVERSION, mstr5051->len,
((char *)shdr + *(int4 *)((char *)hdr + V50V51_FTNHDR_LITBASE_OFFSET)
+ (int4)mstr5051->addr), zro_entry->str.len, zro_entry->str.addr);
}
@@ -324,13 +359,13 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
{ /* Note: routine_name field has not been relocated yet, so compute its absolute
* address in the shared library and use it
*/
- zl_error(linktyp, 0, ERR_DLLVERSION, hdr->routine_name.len, (char *)shdr +
- (UINTPTR_T)hdr->literal_text_adr + (UINTPTR_T)hdr->routine_name.addr,
+ zl_error(RECENT_ZHIST, linktyp, 0, ERR_DLLVERSION, hdr->routine_name.len,
+ (char *)shdr + (UINTPTR_T)hdr->literal_text_adr + (UINTPTR_T)hdr->routine_name.addr,
zro_entry->str.len, zro_entry->str.addr);
}
}
ZOS_FREE_TEXT_SECTION;
- zl_error_hskpng(linktyp, file_desc);
+ zl_error_hskpng(linktyp, file_desc, RECENT_ZHIST);
return IL_RECOMPILE;
}
if (((hdr->compiler_qlf & CQ_UTF8) && !gtm_utf8_mode) || (!(hdr->compiler_qlf & CQ_UTF8) && gtm_utf8_mode))
@@ -342,17 +377,17 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
*/
if ((lcl_compiler_qlf & CQ_UTF8) && !gtm_utf8_mode)
{
- zl_error(linktyp, 0, ERR_DLLCHSETUTF8, (int)hdr->routine_name.len, (char *)shdr +
- (UINTPTR_T)hdr->literal_text_adr + (UINTPTR_T)hdr->routine_name.addr,
+ zl_error(NULL, linktyp, 0, ERR_DLLCHSETUTF8, (int)hdr->routine_name.len,
+ (char *)shdr + (UINTPTR_T)hdr->literal_text_adr + (UINTPTR_T)hdr->routine_name.addr,
(int)zro_entry->str.len, zro_entry->str.addr);
} else
{
- zl_error(linktyp, 0, ERR_DLLCHSETM, (int)hdr->routine_name.len, (char *)shdr +
- (UINTPTR_T)hdr->literal_text_adr + (UINTPTR_T)hdr->routine_name.addr,
+ zl_error(NULL, linktyp, 0, ERR_DLLCHSETM, (int)hdr->routine_name.len,
+ (char *)shdr + (UINTPTR_T)hdr->literal_text_adr + (UINTPTR_T)hdr->routine_name.addr,
(int)zro_entry->str.len, zro_entry->str.addr);
}
}
- zl_error_hskpng(linktyp, file_desc);
+ zl_error_hskpng(linktyp, file_desc, RECENT_ZHIST);
if ((lcl_compiler_qlf & CQ_UTF8) && !gtm_utf8_mode)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_INVOBJFILE, 2, fname_len, fname, ERR_TEXT, 2,
LEN_AND_LIT("Object compiled with CHSET=UTF-8 which is different from $ZCHSET"));
@@ -360,6 +395,117 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_INVOBJFILE, 2, fname_len, fname, ERR_TEXT, 2,
LEN_AND_LIT("Object compiled with CHSET=M which is different from $ZCHSET"));
}
+ /* We need to check if this is a relink of an already linked routine. To do that, we need to be able to fetch
+ * the routine name from the object file in question in order to look the routine up.
+ */
+ switch(linktyp)
+ {
+ ARLINK_ONLY(case LINK_SHROBJ:);
+ case LINK_PPRIVOBJ:
+ rtnname = ((rhdtyp *)hdr)->routine_name;
+ rtnname_off = (size_t)hdr->literal_text_adr + (size_t)rtnname.addr; /* Offset into object of rtnname */
+ ZOS_ONLY(assertpro(FALSE /* Read file pointer being reset - recode for ZOS */));
+ /* Read the routine name from the object file */
+ if (-1 != (status = (ssize_t)lseek(file_desc, rtnname_off + NATIVE_HDR_LEN, SEEK_SET)))
+ {
+ DOREADRC_OBJFILE(file_desc, rtnname_buf, rtnname.len, status);
+ } else
+ status = errno;
+ if (0 != status)
+ zl_error(NULL, linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
+ rtnname.addr = rtnname_buf;
+ /* Reset read file-pointer for object file back to what it was */
+ status = (ssize_t)lseek(file_desc, NATIVE_HDR_LEN + SIZEOF(rhdtyp), SEEK_SET);
+ if (-1 == status)
+ zl_error(NULL, linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
+ break;
+ case LINK_SHRLIB:
+ rtnname = ((rhdtyp *)shdr)->routine_name;
+ /* Routine name not yet relocated so effectively do so */
+ rtnname.addr = (char *)shdr + (size_t)((rhdtyp *)shdr)->literal_text_adr + (size_t)rtnname.addr;
+ break;
+ default:
+ assert(FALSE);
+ }
+ /* Now check if we know about this routine and if so, if the (new) object hash is the same as the one we currently
+ * have linked. Note both new and old flavors of the routine must either both not be autorelink-enabled or must
+ * both be autorelink-enabled and if autorelink-enabled, must be loaded from the same directory and thus into the same
+ * set of shared memory structures to be able to bypass the link. This might could be eased in the future for certain
+ * special cases.
+ */
+ if (find_rtn_tabent(&tabent_ptr, &rtnname))
+ {
+ old_rhead = (rhdtyp *)tabent_ptr->rt_adr;
+ assert(NULL != old_rhead);
+# ifdef AUTORELINK_SUPPORTED
+ zhent = (LINK_SHROBJ == linktyp) ? recent_zhist->end - 1 : NULL;
+ if ((old_rhead->objhash == hdr->objhash)
+ && (((NULL == zhent) && (NULL == old_rhead->relinkctl_bkptr)) /* Both non-relink */
+ || (NULL != zhent) && (zhent->relinkctl_bkptr == old_rhead->relinkctl_bkptr))) /* Both same relink */
+# else
+ if (old_rhead->objhash == ((rhdtyp *)hdr)->objhash)
+# endif
+ { /* This is the same routine - abort re-link but if autorelink-enabled, use the new history.
+ * Note even a psueo-relink should cancel all the breakpoints in the module. Note we don't address
+ * issues with whether this would have been a recursive relink or not since when we don't actually do
+ * the relink, there's no way to remove breakpoints when the last use of this routine leaves the stack
+ * so eliminate the breakpoints now since newly linked routines are anyway not expected to have
+ * breakpoints.
+ */
+ zr_remove_zbrks(old_rhead, NOBREAKMSG);
+ /* Info level message that link was bypassed. Since this could pollute the error buffer, save and
+ * restore it across the info message we put out (it is either displayed or it isn't - no need to cache it.
+ */
+# ifdef ZLINK_BYPASS /* #ifdef'd out for now due to issues with ERRWETRAP */
+ SAVE_UTIL_OUT_BUFFER(save_util_outptr, save_last_va_list_ptr, util_copy_saved);
+ save_error_condition = error_condition;
+ error_condition = 0;
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZLINKBYPASS, 2, fname_len, fname); /* Info msg returns */
+ error_condition = save_error_condition;
+ RESTORE_UTIL_OUT_BUFFER(save_util_outptr, save_last_va_list_ptr, util_copy_saved);
+# endif
+ /* Note do these cleanup release/reset after the error message so these values still around if the error
+ * causes an issue in debugging.
+ */
+ free(hdr); /* Don't need this (new) copy of routine header */
+ hdr = NULL;
+# ifdef AUTORELINK_SUPPORTED
+ if (NULL != old_rhead->zhist)
+ free(old_rhead->zhist); /* Free up previously auto-relinked structures */
+ /* Save new history if supplied or NULL */
+ old_rhead->zhist = recent_zhist;
+# endif
+ return IL_DONE; /* Pretend we did the link (which, effectively, we already have) */
+ }
+ }
+# ifdef AUTORELINK_SUPPORTED
+ /* For shared object, time to pull it into shared memory */
+ if (LINK_SHROBJ == linktyp)
+ {
+ /* Currently, rtnobj_hdr_t->objLen is a 4-byte field so we cannot support object file sizes > 4Gb for now */
+ assert(4 == SIZEOF(hdr->object_len)); /* i.e. object file size is guaranteed to be < 4Gb */
+ assert(4 == SIZEOF(((rtnobj_hdr_t *)NULL)->objLen)); /* i.e. object file size is guaranteed to be < 4Gb */
+ /* Allocate buffer for routine object in shared memory. If one already exists, use it */
+ if ((size_t)MAXUINT4 <= ((size_t)hdr->object_len + OFFSETOF(rtnobj_hdr_t, userStorage)))
+ { /* Currently, rtnobj_hdr_t->objLen is a 4-byte field so we cannot support object file
+ * sizes > 4Gb for now.
+ */
+ ZOS_FREE_TEXT_SECTION;
+ zl_error_hskpng(linktyp, file_desc, RECENT_ZHIST);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZLINKFILE, 2, fname_len, fname, ERR_TEXT, 2,
+ LEN_AND_LIT("Object file size > 4Gb cannot be auto-relinked"));
+ }
+ shdr = rtnobj_shm_malloc(recent_zhist, file_desc, hdr->object_len, hdr->objhash);
+ if (NULL == shdr)
+ { /* Most likely lseek or read of object file into shared memory failed. Possible for example
+ * if the object file is truncated. Issue error.
+ */
+ zl_error(RECENT_ZHIST, linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
+ }
+ /* We need this link - continue setup */
+ assert(!memcmp(hdr, shdr, SIZEOF(rhdtyp))); /* we already read rtnhdr from disk, assert that is same as in shm */
+ }
+# endif
/* Read in and/or relocate the pointers to the various sections. To understand the size calculations
* being done note that the contents of the various xxx_adr pointers in the routine header are
* initially the offsets from the start of the object. This is so we can address the various sections
@@ -372,6 +518,12 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
switch(linktyp)
{
case LINK_SHROBJ:
+ hdr->shared_object = TRUE; /* Indicate this is linked as a shared object */
+# ifdef AUTORELINK_SUPPORTED
+ zhent = recent_zhist->end - 1;
+ hdr->relinkctl_bkptr = zhent->relinkctl_bkptr;
+# endif
+ /* Note - fall through */
case LINK_SHRLIB:
rel_base = shdr;
break;
@@ -382,7 +534,7 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
assert((INTPTR_T)sect_ro_rel == ((INTPTR_T)sect_ro_rel & ~(LINKAGE_PSECT_BOUNDARY - 1)));
DOREADRC_OBJFILE(file_desc, sect_ro_rel, sect_ro_rel_size, status);
if (0 != status)
- zl_error(linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
+ zl_error(NULL, linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
/* The offset correction is the amount that needs to be applied to a given storage area that
* is no longer contiguous with the routine header. In this case, the code and other sections
* are no longer contiguous with the routine header but the initial offsets in the routine
@@ -428,6 +580,7 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
}
RELOCATE(hdr->lnrtab_adr, lnr_tabent *, rel_base);
RELOCATE(hdr->literal_text_adr, unsigned char *, rel_base);
+ RELOCATE(hdr->linkage_names, mstr *, rel_base);
if (dynlits)
RELOCATE(hdr->literal_adr, mval *, rel_base);
/* Read-write releasable section */
@@ -442,7 +595,7 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
case LINK_PPRIVOBJ:
DOREADRC_OBJFILE(file_desc, sect_rw_rel, sect_rw_rel_size, status);
if (0 != status)
- zl_error(linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
+ zl_error(NULL, linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
break;
default:
assert(FALSE /* Invalid link type */);
@@ -512,7 +665,7 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
case LINK_PPRIVOBJ:
DOREADRC_OBJFILE(file_desc, sect_rw_nonrel, sect_rw_nonrel_size, status);
if (0 != status)
- zl_error(linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
+ zl_error(NULL, linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
break;
default:
assert(FALSE /* Invalid link type */);
@@ -525,7 +678,9 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
RELOCATE(curlbe->lnr_adr, lnr_tabent *, hdr->lnrtab_adr);
}
/* Remaining initialization */
- hdr->zhist = TREF(recent_zhist); /* TODO: Document what this is or change to different mechanism */
+ ARLINK_ONLY(assert(((NULL == recent_zhist) && (LINK_SHROBJ != linktyp))
+ || ((NULL != recent_zhist) && (LINK_SHROBJ == linktyp))));
+ ARLINK_ONLY(hdr->zhist = recent_zhist);
hdr->current_rhead_adr = hdr;
assert(hdr->routine_name.len < SIZEOF(zlink_mname.c));
memcpy(&zlink_mname.c[0], hdr->routine_name.addr, hdr->routine_name.len);
@@ -537,7 +692,9 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
if (!addr_fix(file_desc, shdr, linktyp, &urx_lcl_anchor))
{
urx_free(&urx_lcl_anchor);
- zl_error(linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
+ /* Decrement "refcnt" bump done by "rtnobj_shm_malloc" above */
+ ARLINK_ONLY(if (LINK_SHROBJ == linktyp) rtnobj_shm_free(hdr, LATCH_GRABBED_FALSE));
+ zl_error(RECENT_ZHIST, linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
}
/* Register new routine in routine name vector displacing old one and performing any necessary cleanup */
if (!zlput_rname(hdr))
@@ -545,8 +702,14 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
urx_free(&urx_lcl_anchor);
/* Copy routine name to local variable because zl_error frees it. */
memcpy(&module_name.c[0], hdr->routine_name.addr, hdr->routine_name.len);
- zl_error(linktyp, file_desc, ERR_LOADRUNNING, (int)hdr->routine_name.len, &module_name.c[0], 0, NULL);
+ /* Decrement "refcnt" bump done by "rtnobj_shm_malloc" above */
+ ARLINK_ONLY(if (LINK_SHROBJ == linktyp) rtnobj_shm_free(hdr, LATCH_GRABBED_FALSE));
+ zl_error(RECENT_ZHIST, linktyp, file_desc, ERR_LOADRUNNING, (int)hdr->routine_name.len, &module_name.c[0],
+ 0, NULL);
}
+ /* Now that new routine is registered, no longer need to do rtnobj_shm_free.
+ * That will be done by relinkctl_rundown as part of scanning the rtn_names[] array.
+ */
/* Fix up of routine headers for old versions of routine so they point to the newest version */
old_rhead = hdr->old_rhead_adr;
lbt_bot = hdr->labtab_adr;
@@ -578,6 +741,7 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
old_rhead->routine_name = hdr->routine_name;
old_rhead->vartab_len = hdr->vartab_len;
old_rhead->vartab_adr = hdr->vartab_adr;
+ old_rhead->shared_ptext_adr = hdr->shared_ptext_adr;
old_rhead->ptext_adr = hdr->ptext_adr;
old_rhead->ptext_end_adr = hdr->ptext_end_adr;
old_rhead->lnrtab_adr = hdr->lnrtab_adr;
@@ -589,7 +753,7 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
old_rhead->literal_adr = hdr->literal_adr;
old_rhead->literal_text_adr = hdr->literal_text_adr;
old_rhead->literal_len = hdr->literal_len;
- old_rhead->zhist = hdr->zhist;
+ ARLINK_ONLY(old_rhead->zhist = hdr->zhist);
old_rhead = (rhdtyp *)old_rhead->old_rhead_adr;
}
/* Add local unresolves to global chain freeing elements that already existed in the global chain */
@@ -598,6 +762,7 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
urx_resolve(hdr, (lab_tabent *)lbt_bot, (lab_tabent *)lbt_top);
if (LINK_PPRIVOBJ == linktyp)
cacheflush(hdr->ptext_adr, (hdr->ptext_end_adr - hdr->ptext_adr), BCACHE);
+ /* zOS cleanups */
ZOS_FREE_TEXT_SECTION;
/* Don't leave global pointers around to active blocks */
hdr = NULL;
@@ -891,12 +1056,12 @@ STATICFNDEF void res_free(res_list *root)
* len/addr - length/address of 1st substitution string.
* len2/addr2 - length/address of 2nd substitution string.
*/
-STATICFNDEF void zl_error(linktype linktyp, int4 file, int4 err, int4 len, char *addr, int4 len2, char *addr2)
+STATICFNDEF void zl_error(void *recent_zhist, linktype linktyp, int4 file, int4 err, int4 len, char *addr, int4 len2, char *addr2)
{
int rc;
ZOS_FREE_TEXT_SECTION;
- zl_error_hskpng(linktyp, file);
+ zl_error_hskpng(linktyp, file, recent_zhist);
if (LINK_PPRIVOBJ == linktyp)
{ /* Only private process links have this area to free */
CLOSEFILE_RESET(file, rc); /* resets "file" to FD_INVALID */
@@ -914,7 +1079,7 @@ STATICFNDEF void zl_error(linktype linktyp, int4 file, int4 err, int4 len, char
* linktyp - type of linkage performed (enum linktype).
* file - file descriptor of open file.
*/
-STATICFNDEF void zl_error_hskpng(linktype linktyp, int4 file)
+STATICFNDEF void zl_error_hskpng(linktype linktyp, int4 file, void *recent_zhist)
{
if (NULL != hdr)
{
@@ -936,4 +1101,5 @@ STATICFNDEF void zl_error_hskpng(linktype linktyp, int4 file)
GTM_TEXT_FREE(sect_ro_rel);
sect_ro_rel = NULL;
}
+ RELEASE_RECENT_ZHIST;
}
diff --git a/sr_unix/incr_link.h b/sr_unix/incr_link.h
index e78a59a..282deb7 100644
--- a/sr_unix/incr_link.h
+++ b/sr_unix/incr_link.h
@@ -17,10 +17,34 @@
#ifdef USHBIN_SUPPORTED
#include <incr_link_sp.h>
+#endif
+#include "zroutinessp.h" /* need zro_ent typedef */
+
+/* If autorelink is supported, the additional recent_zhist parameter (if non-NULL) points to a malloc'd search history buffer
+ * which should be* released for any error. This macro provides the release capability.
+ */
+#ifdef AUTORELINK_SUPPORTED
+# define RECENT_ZHIST recent_zhist
+# define RELEASE_RECENT_ZHIST \
+{ \
+ if (NULL != recent_zhist) \
+ { \
+ free(recent_zhist); \
+ recent_zhist = NULL; \
+ } \
+}
#else
-#include "zroutinessp.h" /* need zro_ent typedef for i386 dummy argument */
+# define RECENT_ZHIST NULL
+# define RELEASE_RECENT_ZHIST
#endif
+
+#ifdef AUTORELINK_SUPPORTED
+# define INCR_LINK(FD, ZRO_ENT, ZRO_HIST, FNLEN, FNAME) incr_link(FD, ZRO_ENT, ZRO_HIST, FNLEN, FNAME)
+boolean_t incr_link(int file_desc, zro_ent *zro_entry, zro_hist *recent_zhist_ptr, uint4 fname_len, char *fname);
+#else
+# define INCR_LINK(FD, ZRO_ENT, ZRO_HIST, FNLEN, FNAME) incr_link(FD, ZRO_ENT, FNLEN, FNAME)
boolean_t incr_link(int file_desc, zro_ent *zro_entry, uint4 fname_len, char *fname);
+#endif
#ifdef __MVS__
#define ZOS_FREE_TEXT_SECTION \
diff --git a/sr_unix/init_gtm.c b/sr_unix/init_gtm.c
index 3a114ef..a76791c 100644
--- a/sr_unix/init_gtm.c
+++ b/sr_unix/init_gtm.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -51,8 +51,6 @@ GBLREF void (*tp_timeout_action_ptr)(void);
GBLREF void (*tp_timeout_clear_ptr)(void);
GBLREF void (*tp_timeout_start_timer_ptr)(int4 tmout_sec);
GBLREF int (*op_open_ptr)(mval *v, mval *p, int t, mval *mspace);
-GBLREF void (*op_write_ptr)(mval *v);
-GBLREF void (*op_wteol_ptr)(int4 n);
GBLREF void (*unw_prof_frame_ptr)(void);
GBLREF void (*stx_error_fptr)(int in_error, ...); /* Function pointer for stx_error() so gtm_utf8.c can avoid pulling
* stx_error() into gtmsecshr, and thus just about everything else
@@ -113,8 +111,6 @@ void init_gtm(void)
ctrlc_handler_ptr = ctrlc_handler;
if (MUMPS_UTILTRIGR != invocation_mode)
op_open_ptr = op_open;
- op_write_ptr = op_write;
- op_wteol_ptr = op_wteol;
unw_prof_frame_ptr = unw_prof_frame;
stx_error_fptr = stx_error;
show_source_line_fptr = show_source_line;
diff --git a/sr_unix/interlock.h b/sr_unix/interlock.h
index 3125629..e1af33a 100644
--- a/sr_unix/interlock.h
+++ b/sr_unix/interlock.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -102,9 +102,13 @@
#endif /* __ia64, __x86_64__, and __sparc */
/* Use COMPSWAP_UNLOCK to release the lock because of the memory barrier and other-processor notification it implies. Also
* the usage of COMPSWAP_UNLOCK allows us to check (with low cost) that we have/had the lock we are trying to release.
- * If we don't have the lock and are trying to release it, a GTMASSERT seems the logical choice as the logic is very broken
- * at that point. If this macro is used in part of an expression, the GTMASSERT path must also return a value (to keep
- * the compiler happy) thus the construct (GTMASSERT, 0) which returns a zero (see usage with assert() on UNIX).
+ * If we don't have the lock and are trying to release it, an assertpro seems the logical choice as the logic is very broken
+ * at that point. If this macro is used in part of an expression, the assertpro path must also return a value (to keep
+ * the compiler happy) thus the construct (assertpro, 0) which returns a zero (see usage with assert() on UNIX).
*/
-#define RELEASE_SWAPLOCK(X) (COMPSWAP_UNLOCK((X), process_id, 0, LOCK_AVAILABLE, 0) ? 1 : (GTMASSERT, 0))
+#define RELEASE_SWAPLOCK(X) (COMPSWAP_UNLOCK((X), process_id, 0, LOCK_AVAILABLE, 0) ? 1 : (assertpro(FALSE), 0))
+
+/* Function prototypes */
+boolean_t grab_latch(sm_global_latch_ptr_t latch, int max_timeout_in_secs);
+void rel_latch(sm_global_latch_ptr_t latch);
diff --git a/sr_unix/iopi_open.c b/sr_unix/iopi_open.c
index 4b37616..265121e 100644
--- a/sr_unix/iopi_open.c
+++ b/sr_unix/iopi_open.c
@@ -38,6 +38,8 @@
#include "gtm_zos_io.h"
#include "gtm_zos_chset.h"
#endif
+#include "send_msg.h"
+#include "wbox_test_init.h"
LITREF unsigned char io_params_size[];
ZOS_ONLY(GBLREF boolean_t gtm_tag_utf8_as_ascii;)
@@ -50,6 +52,13 @@ error_def(ERR_SYSCALL);
error_def(ERR_TEXT);
ZOS_ONLY(error_def(ERR_BADTAG);)
+enum
+{
+ PARSE_OK = 1, /* the parse passed */
+ PARSE_FAIL, /* the parse failed but $PATH is defined in the environment */
+ PARSE_FAIL_NOPATH /* the parse failed and $PATH is undefined in the environment */
+};
+
#define FREE_ALL { if (NULL != copy_cmd_string) free(copy_cmd_string); if (NULL != temp) free(temp);\
if (NULL != buf) free(buf); if (NULL != dir_in_path) free(dir_in_path);if (NULL != command2) free(command2); }
@@ -109,11 +118,11 @@ int parse_pipe(char *cmd_string, char *ret_token)
int env_inc;
struct stat sb;
char *path, path_buff[GTM_PATH_MAX];
- char *temp;
- char *buf;
- char *dir_in_path;
- char *command2;
- char *copy_cmd_string;
+ char *temp = NULL;
+ char *buf = NULL;
+ char *dir_in_path = NULL;
+ char *command2 = NULL;
+ char *copy_cmd_string = NULL;
char *token1;
char *token2;
char *token3;
@@ -123,17 +132,20 @@ int parse_pipe(char *cmd_string, char *ret_token)
int cmd_string_size;
path = GETENV("PATH");
- path_len = STRLEN(path);
- if (GTM_PATH_MAX <= path_len)
- path_len = GTM_PATH_MAX - 1;
- memcpy(path_buff, path, path_len + 1); /* + 1 for null */
- path = path_buff;
+ if (NULL != path)
+ {
+ path_len = STRLEN(path);
+ if (GTM_PATH_MAX <= path_len)
+ path_len = GTM_PATH_MAX - 1;
+ memcpy(path_buff, path, path_len + 1); /* + 1 for null */
+ path = path_buff;
+ dir_in_path = (char *)malloc(GTM_PATH_MAX);
+ }
cmd_string_size = STRLEN(cmd_string) + 1;
pathsize = GTM_PATH_MAX + cmd_string_size;
buf = (char *)malloc(pathsize);
copy_cmd_string = (char *)malloc(cmd_string_size);
- dir_in_path = (char *)malloc(GTM_PATH_MAX);
command2 = (char *)malloc(cmd_string_size);
temp = (char *)malloc(pathsize);
memcpy(copy_cmd_string, cmd_string, cmd_string_size);
@@ -148,7 +160,7 @@ int parse_pipe(char *cmd_string, char *ret_token)
break;
/* separate into tokens using space as delimiter */
- /* if the first token is a non-alpha-numeric or if it is nohup the skip it */
+ /* if the first token is a non-alpha-numeric or if it is nohup then skip it */
/* and use the next one as a command to find */
memcpy(command2, token1, STRLEN(token1) + 1);
@@ -176,18 +188,19 @@ int parse_pipe(char *cmd_string, char *ret_token)
/* if the first character is a $ sign then assume it is an environment variable used
like $gtm_dist/mupip. Get the environment variable and substitute it. */
notfound = TRUE;
+ temp[0] = '\0';
if ('$' == *token2)
{
for (env_inc = 1; '/' != *(token2 + env_inc); env_inc++)
{
temp[env_inc - 1] = *(token2 + env_inc);
}
- temp[env_inc] = '\0';
+ temp[env_inc - 1] = '\0';
env_var = GETENV(temp);
if (NULL != env_var)
{
/* build a translated path to command */
- assert(cmd_string_size > (STRLEN(token2 + env_inc) + STRLEN(env_var)));
+ assert(pathsize > (STRLEN(token2 + env_inc) + STRLEN(env_var)));
SPRINTF(temp, "%s%s", env_var, token2 + env_inc);
/* The command must be a regular file and executable */
@@ -215,21 +228,24 @@ int parse_pipe(char *cmd_string, char *ret_token)
notfound = TRUE;
}
- /* search all the directories in the $PATH */
- memcpy(dir_in_path, path, path_len + 1);
- for (str3= dir_in_path; TRUE == notfound; str3 = NULL)
+ /* search all the directories in the $PATH if defined */
+ if (NULL != path)
{
- token3 = strtok_r(str3, ":", &saveptr3);
- if (NULL == token3)
- break;
- SPRINTF(buf, "%s/%s", token3, token2);
- notfound = TRUE;
- /* The command must be a regular file and executable */
- STAT_FILE(buf, &sb, ret_stat);
- if (0 == ret_stat && (S_ISREG(sb.st_mode)) && (sb.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)))
+ memcpy(dir_in_path, path, path_len + 1);
+ for (str3 = dir_in_path; TRUE == notfound; str3 = NULL)
{
- notfound = FALSE;
- break;
+ token3 = strtok_r(str3, ":", &saveptr3);
+ if (NULL == token3)
+ break;
+ SPRINTF(buf, "%s/%s", token3, token2);
+ notfound = TRUE;
+ /* The command must be a regular file and executable */
+ STAT_FILE(buf, &sb, ret_stat);
+ if (0 == ret_stat && (S_ISREG(sb.st_mode)) && (sb.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)))
+ {
+ notfound = FALSE;
+ break;
+ }
}
}
}
@@ -238,11 +254,14 @@ int parse_pipe(char *cmd_string, char *ret_token)
assert(GTM_PATH_MAX > (STRLEN(token2) + 1));
memcpy(ret_token, token2, STRLEN(token2) + 1);
FREE_ALL;
- return(FALSE);
+ if (NULL != path)
+ return(PARSE_FAIL);
+ else
+ return(PARSE_FAIL_NOPATH);
}
}
FREE_ALL;
- return(TRUE);
+ return(PARSE_OK);
}
/* When we are in this routine dev_name is same as naml in io_open_try() */
@@ -256,6 +275,7 @@ int parse_pipe(char *cmd_string, char *ret_token)
}
#define INVALID_CMD "Invalid command string: "
+#define INVALID_CMD2 "$PATH undefined, Invalid command string: "
short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 timeout)
{
@@ -286,11 +306,12 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
char *sh;
int independent = FALSE;
int parse = FALSE;
+ int parse_result;
int status_read;
int return_stdout = TRUE;
int return_stderr = FALSE;
char ret_token[GTM_MAX_DIR_LEN];
- char error_str[MAXDEVPARLEN + STR_LIT_LEN(INVALID_CMD)];
+ char error_str[MAXDEVPARLEN + STR_LIT_LEN(INVALID_CMD2)];
int save_errno;
int flags;
int fcntl_res, rc;
@@ -302,7 +323,11 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
boolean_t textflag;
int ccsid, status, realfiletag;
#endif
+# ifdef DEBUG
+ DCL_THREADGBL_ACCESS;
+ SETUP_THREADGBL_ACCESS;
+# endif
iod = dev_name->iod;
while (iop_eol != *(pp->str.addr + p_offset))
@@ -365,10 +390,13 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
pcommand[slen[PCOMMAND]] = '\0';
if (TRUE == parse)
{
- if (FALSE == parse_pipe(pcommand, ret_token))
+ if (PARSE_OK != (parse_result = parse_pipe(pcommand, ret_token)))
{
PIPE_ERROR_INIT();
- SPRINTF(error_str, "%s%s", INVALID_CMD, ret_token);
+ if (PARSE_FAIL == parse_result)
+ SPRINTF(error_str, "%s%s", INVALID_CMD, ret_token);
+ else
+ SPRINTF(error_str, "%s%s", INVALID_CMD2, ret_token);
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
ERR_TEXT, 2, LEN_AND_STR(error_str));
}
@@ -515,49 +543,52 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
CLOSEFILE(0, rc);
/* stdin becomes pfd_write[0] */
- if (-1 == dup2(pfd_write[0], 0))
+ if (DEBUG_ONLY(WBTEST_ENABLED(WBTEST_BADDUP_PIPE_STDIN) ||) (-1 == dup2(pfd_write[0], 0)))
{
save_errno = errno;
PIPE_ERROR_INIT();
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
- ERR_TEXT, 2, LEN_AND_LIT("PIPE - dup2(pfd_write[0]) failed in child"), save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
+ ERR_TEXT, 2, LEN_AND_LIT("PIPE - dup2(pfd_write[0]) failed in child"));
+ _exit(ERR_DEVOPENFAIL);
}
if (return_stdout)
{
/* stdout becomes pfd_read[1] */
CLOSEFILE(1, rc);
- if (-1 == dup2(pfd_read[1], 1))
+ if (DEBUG_ONLY(WBTEST_ENABLED(WBTEST_BADDUP_PIPE_STDOUT) ||) (-1 == dup2(pfd_read[1], 1)))
{
save_errno = errno;
PIPE_ERROR_INIT();
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
- ERR_TEXT, 2, LEN_AND_LIT("PIPE - dup2(pfd_read[1],1) failed in child"), save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
+ ERR_TEXT, 2, LEN_AND_LIT("PIPE - dup2(pfd_read[1],1) failed in child"));
+ _exit(ERR_DEVOPENFAIL);
}
/* stderr also becomes pfd_read[1] if return_stderr is false*/
if (FALSE == return_stderr)
{
CLOSEFILE(2, rc);
- if (-1 == dup2(pfd_read[1], 2))
+ if (DEBUG_ONLY(WBTEST_ENABLED(WBTEST_BADDUP_PIPE_STDERR1) ||) (-1 == dup2(pfd_read[1], 2)))
{
save_errno = errno;
PIPE_ERROR_INIT();
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2,
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2,
dev_name->len, dev_name->dollar_io, ERR_TEXT, 2,
- LEN_AND_LIT("PIPE - dup2(pfd_read[1],2) failed in child"), save_errno);
+ LEN_AND_LIT("PIPE - dup2(pfd_read[1],2) failed in child"));
+ _exit(ERR_DEVOPENFAIL);
}
}
}
if (return_stderr)
{
CLOSEFILE(2, rc);
- if (-1 == dup2(pfd_read_stderr[1], 2))
+ if (DEBUG_ONLY(WBTEST_ENABLED(WBTEST_BADDUP_PIPE_STDERR2) ||) (-1 == dup2(pfd_read_stderr[1], 2)))
{
save_errno = errno;
PIPE_ERROR_INIT();
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2,
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2,
dev_name->len, dev_name->dollar_io, ERR_TEXT, 2,
- LEN_AND_LIT("PIPE - dup2(pfd_read_stderr[1],2) failed in child"),
- save_errno);
+ LEN_AND_LIT("PIPE - dup2(pfd_read_stderr[1],2) failed in child"));
+ _exit(ERR_DEVOPENFAIL);
}
}
if (0 == slen[PSHELL])
@@ -569,18 +600,23 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
{
ret = EXECL("/bin/sh", "sh", "-c", pcommand, (char *)NULL);
} else
- ret = EXECL(sh, basename(sh), "-c", pcommand, (char *)NULL);
+ if (!WBTEST_ENABLED(WBTEST_BADEXEC_PIPE_PROCESS))
+ ret = EXECL(sh, basename(sh), "-c", pcommand, (char *)NULL);
+ else
+ ret = -1;
} else
ret = EXECL(pshell, pshell_name, "-c", pcommand, (char *)NULL);
if (-1 == ret)
{
save_errno = errno;
PIPE_ERROR_INIT();
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
- ERR_TEXT, 2, LEN_AND_LIT("PIPE - execl() failed in child"), save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
+ ERR_TEXT, 2, LEN_AND_LIT("PIPE - execl() failed in child"));
+ _exit(-1);
}
} else
{ /* in parent */
+ DEBUG_ONLY(TREF(fork_without_child_wait) = TRUE); /* set variable to help assert in "relinkctl_rundown()" */
CLOSEFILE_RESET(pfd_write[0], rc); /* Close unused read end; Resets "pfd_write[0]" to FD_INVALID */
ZOS_ONLY(if (-1 == gtm_zos_setcvtmode(pfd_write[1], write_cvt[PARENTCVT]))
TAG_POLICY_SEND_MSG("PIPE - conversion mode(pfd_write) failed", errno, realfiletag, ccsid));
diff --git a/sr_unix/iosocket_tls.c b/sr_unix/iosocket_tls.c
new file mode 100644
index 0000000..8fadbf8
--- /dev/null
+++ b/sr_unix/iosocket_tls.c
@@ -0,0 +1,357 @@
+/****************************************************************
+ * *
+ * Copyright 2014 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#ifdef GTM_TLS
+
+#include <errno.h>
+#ifdef USE_POLL
+#include <poll.h>
+#else
+#include "gtm_select.h"
+#endif
+#include "gtm_socket.h"
+#include "gtm_inet.h"
+#include "gtm_stdio.h"
+#include "gtm_string.h"
+#include "eintr_wrappers.h"
+
+#include "io.h"
+#include "gt_timer.h"
+#include "iosocketdef.h"
+#include "gtm_conv.h"
+#include "gtm_utf8.h"
+#include "rel_quant.h"
+#include "send_msg.h"
+#include "error.h"
+#include "min_max.h"
+#include "gtm_caseconv.h"
+#include "fgncalsp.h"
+#include "iotimer.h"
+#include "gtm_tls.h"
+
+GBLREF io_pair io_curr_device;
+GBLREF char dl_err[MAX_ERRSTR_LEN];
+GBLREF int dollar_truth;
+
+GBLREF gtm_tls_ctx_t *tls_ctx;
+
+error_def(ERR_CURRSOCKOFR);
+error_def(ERR_TLSCONVSOCK);
+error_def(ERR_TLSDLLNOOPEN);
+error_def(ERR_TLSHANDSHAKE);
+error_def(ERR_TLSINIT);
+error_def(ERR_TLSPARAM);
+error_def(ERR_TLSRENEGOTIATE);
+error_def(ERR_NOSOCKETINDEV);
+error_def(ERR_SOCKPASSDATAMIX);
+error_def(ERR_TEXT);
+error_def(ERR_ZINTRECURSEIO);
+
+#define MAX_TLSOPTION 12
+
+typedef enum
+{
+ tlsopt_invalid,
+ tlsopt_client,
+ tlsopt_server,
+ tlsopt_renegotiate
+} tls_option;
+
+void iosocket_tls(mval *optionmval, int4 timeoutarg, mval *tlsid, mval *password, mval *extraarg)
+{ /* note extraarg is not currently used */
+ int4 length, flags, timeout, msec_timeout, status, status2, len, errlen, devlen, tls_errno, save_errno;
+ io_desc *iod;
+ d_socket_struct *dsocketptr;
+ socket_struct *socketptr;
+ char optionstr[MAX_TLSOPTION], idstr[MAX_TLSID_LEN], passwordstr[GTM_PASSPHRASE_MAX_ASCII + 1];
+ const char *errp;
+ tls_option option;
+ gtm_tls_socket_t *tlssocket;
+ ABS_TIME cur_time, end_time;
+# ifdef USE_POLL
+ struct pollfd fds;
+# else
+ fd_set fds, *readfds, *writefds;
+ struct timeval timeout_spec, *timeout_ptr;
+# endif
+
+ iod = io_curr_device.out;
+ assert(gtmsocket == iod->type);
+ dsocketptr = (d_socket_struct *)iod->dev_sp;
+ if (0 >= dsocketptr->n_socket)
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOSOCKETINDEV);
+ return;
+ }
+ if (dsocketptr->n_socket <= dsocketptr->current_socket)
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CURRSOCKOFR, 2, dsocketptr->current_socket, dsocketptr->n_socket);
+ return;
+ }
+ if (dsocketptr->mupintr)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO);
+ socketptr = dsocketptr->socket[dsocketptr->current_socket];
+ ENSURE_DATA_SOCKET(socketptr);
+ if (socket_tcpip != socketptr->protocol)
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, RTS_ERROR_MVAL(optionmval),
+ LEN_AND_LIT("but socket is not TCP"));
+ return;
+ }
+ if (socket_connected != socketptr->state)
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_LIT("/TLS"),
+ LEN_AND_LIT("but socket not connected"));
+ return;
+ }
+ if (NULL != tlsid)
+ {
+ length = tlsid->str.len;
+ if (MAX_TLSID_LEN < (length + 1)) /* for null */
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_LIT("TLSID"), LEN_AND_LIT("too long"));
+ return;
+ }
+ STRNCPY_STR(idstr, tlsid->str.addr, length);
+ idstr[length] = '\0';
+ } else
+ idstr[0] = '\0';
+ if (NULL != password)
+ {
+ length = password->str.len;
+ if (GTM_PASSPHRASE_MAX_ASCII < length)
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_LIT("passphrase"),
+ LEN_AND_LIT("too long"));
+ return;
+ }
+ STRNCPY_STR(passwordstr, password->str.addr, length);
+ passwordstr[length] = '\0';
+ } else
+ passwordstr[0] = '\0';
+ length = MIN(MAX_TLSOPTION, optionmval->str.len);
+ lower_to_upper((uchar_ptr_t)optionstr, (uchar_ptr_t)optionmval->str.addr, length);
+ if (0 == memcmp(optionstr, "CLIENT", length))
+ option = tlsopt_client;
+ else if (0 == memcmp(optionstr, "SERVER", length))
+ option = tlsopt_server;
+ else if (0 == memcmp(optionstr, "RENEGOTIATE", length))
+ option = tlsopt_renegotiate;
+ else
+ option = tlsopt_invalid;
+ memcpy(iod->dollar.device, "0", SIZEOF("0"));
+ if (NO_M_TIMEOUT != timeoutarg)
+ {
+ msec_timeout = timeout2msec(timeoutarg);
+ sys_get_curr_time(&cur_time);
+ add_int_to_abs_time(&cur_time, msec_timeout, &end_time);
+ } else
+ msec_timeout = -1;
+ if ((tlsopt_client == option) || (tlsopt_server == option))
+ { /* most of the setup is common */
+ if (socketptr->tlsenabled)
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_STR(optionstr),
+ LEN_AND_LIT("but TLS already enabled"));
+ return;
+ }
+ assertpro((0 >= socketptr->buffered_length) && (0 >= socketptr->obuffer_length));
+ if (NULL == tls_ctx)
+ { /* first use of TLS */
+ if (-1 == gtm_tls_loadlibrary())
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSDLLNOOPEN, 0, ERR_TEXT, 2, LEN_AND_STR(dl_err));
+ return;
+ }
+ if (NULL == (tls_ctx = (gtm_tls_init(GTM_TLS_API_VERSION, GTMTLS_OP_INTERACTIVE_MODE))))
+ {
+ errp = gtm_tls_get_error();
+ len = SIZEOF(ONE_COMMA) - 1;
+ memcpy(iod->dollar.device, ONE_COMMA, len);
+ errlen = STRLEN(errp);
+ devlen = MIN((SIZEOF(iod->dollar.device) - len - 1), errlen);
+ memcpy(&iod->dollar.device[len], errp, devlen + 1);
+ if (devlen < errlen)
+ iod->dollar.device[SIZEOF(iod->dollar.device) - 1] = '\0';
+ if (socketptr->ioerror)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSINIT, 0, ERR_TEXT, 2, errlen, errp);
+ if (NO_M_TIMEOUT != timeoutarg)
+ dollar_truth = FALSE;
+ return;
+ }
+ }
+ socketptr->tlsenabled = TRUE;
+ flags = GTMTLS_OP_SOCKET_DEV | ((tlsopt_client == option) ? GTMTLS_OP_CLIENT_MODE : 0);
+ socketptr->tlssocket = gtm_tls_socket(tls_ctx, NULL, socketptr->sd, idstr, flags);
+ if (NULL == socketptr->tlssocket)
+ {
+ socketptr->tlsenabled = FALSE;
+ errp = gtm_tls_get_error();
+ len = SIZEOF(ONE_COMMA) - 1;
+ memcpy(iod->dollar.device, ONE_COMMA, len);
+ errlen = STRLEN(errp);
+ devlen = MIN((SIZEOF(iod->dollar.device) - len - 1), errlen);
+ memcpy(&iod->dollar.device[len], errp, devlen + 1);
+ if (devlen < errlen)
+ iod->dollar.device[SIZEOF(iod->dollar.device) - 1] = '\0';
+ if (socketptr->ioerror)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSCONVSOCK, 0, ERR_TEXT, 2, errlen, errp);
+ if (NO_M_TIMEOUT != timeoutarg)
+ dollar_truth = FALSE;
+ return;
+ }
+ status = 0;
+# ifndef USE_POLL
+ if (NO_M_TIMEOUT == timeoutarg)
+ timeout_ptr = NULL;
+ else
+ {
+ timeout_spec.tv_sec = msec_timeout / 1000;
+ timeout_spec.tv_usec = (msec_timeout % 1000) * 1000; /* remainder in millsecs to microsecs */
+ timeout_ptr = &timeout_spec;
+ }
+# endif
+ do
+ {
+ status2 = 0;
+ if (0 != status)
+ {
+# ifdef USE_POLL
+ fds.fd = socketptr->sd;
+ fds.events = (GTMTLS_WANT_READ == status) ? POLLIN : POLLOUT;
+# else
+ readfds = writefds = NULL;
+ assertpro(FD_SETSIZE > socketptr->sd);
+ FD_ZERO(&fds);
+ FD_SET(socketptr->sd, &fds);
+ writefds = (GTMTLS_WANT_WRITE == status) ? &fds : NULL;
+ readfds = (GTMTLS_WANT_READ == status) ? &fds : NULL;
+# endif
+ POLL_ONLY(if (-1 == (status2 = poll(&fds, 1, msec_timeout))))
+ SELECT_ONLY(if (-1 == (status2 = select(socketptr->sd + 1, readfds, writefds, NULL, timeout_ptr))))
+ {
+ save_errno = errno;
+ if (EAGAIN == save_errno)
+ {
+ rel_quant(); /* allow resources to become available */
+ status2 = 0; /* treat as timeout */
+ } else if (EINTR == save_errno)
+ status2 = 0;
+ }
+ } else
+ status2 = 1; /* do accept/connect first time */
+ if (0 < status2)
+ {
+ if (tlsopt_server == option)
+ status = gtm_tls_accept((gtm_tls_socket_t *)socketptr->tlssocket);
+ else
+ status = gtm_tls_connect((gtm_tls_socket_t *)socketptr->tlssocket);
+ }
+ if ((0 > status2) || ((status != 0) && ((GTMTLS_WANT_READ != status) && (GTMTLS_WANT_WRITE != status))))
+ {
+ if (0 != status)
+ {
+ tls_errno = gtm_tls_errno();
+ if (0 > tls_errno)
+ errp = gtm_tls_get_error();
+ else
+ errp = STRERROR(tls_errno);
+ } else
+ errp = STRERROR(save_errno);
+ socketptr->tlsenabled = FALSE;
+ len = SIZEOF(ONE_COMMA) - 1;
+ memcpy(iod->dollar.device, ONE_COMMA, len);
+ errlen = STRLEN(errp);
+ devlen = MIN((SIZEOF(iod->dollar.device) - len - 1), errlen);
+ memcpy(&iod->dollar.device[len], errp, devlen + 1);
+ if (devlen < errlen)
+ iod->dollar.device[SIZEOF(iod->dollar.device) - 1] = '\0';
+ if (socketptr->ioerror)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSHANDSHAKE, 0,
+ ERR_TEXT, 2, errlen, errp);
+ return;
+ }
+ if ((0 != status) && (0 <= status2)) /* not accepted/connected and not error */
+ { /* check for timeout if not error or want read or write */
+ if ((0 != timeoutarg) && (NO_M_TIMEOUT != timeoutarg))
+ {
+ sys_get_curr_time(&cur_time);
+ cur_time = sub_abs_time(&end_time, &cur_time);
+ if (0 >= cur_time.at_sec)
+ { /* no more time */
+ gtm_tls_session_close((gtm_tls_socket_t **)&socketptr->tlssocket);
+ socketptr->tlsenabled = FALSE;
+ dollar_truth = FALSE;
+ return;
+ } else
+ { /* adjust msec_timeout for poll/select */
+# ifdef USE_POLL
+ msec_timeout = (cur_time.at_sec * 1000) + (cur_time.at_usec / 1000);
+# else
+ timeout_spec.tv_sec = cur_time.at_sec;
+ timeout_spec.tv_usec = (gtm_tv_usec_t)cur_time.at_usec;
+# endif
+ }
+ } else if (0 == timeoutarg)
+ { /* only one chance */
+ gtm_tls_session_close((gtm_tls_socket_t **)&socketptr->tlssocket);
+ socketptr->tlsenabled = FALSE;
+ dollar_truth = FALSE;
+ return;
+ }
+ continue;
+ }
+ } while ((GTMTLS_WANT_READ == status) || (GTMTLS_WANT_WRITE == status));
+ /* turn on output buffering */
+ if (0 == socketptr->obuffer_size)
+ socketptr->obuffer_size = socketptr->buffer_size;
+ socketptr->obuffer_length = socketptr->obuffer_offset = 0;
+ socketptr->obuffer_wait_time = DEFAULT_WRITE_WAIT;
+ socketptr->obuffer_flush_time = DEFAULT_WRITE_WAIT * 2; /* until add device parameter */
+ socketptr->obuffer = malloc(socketptr->obuffer_size);
+ } else if (tlsopt_renegotiate == option)
+ {
+ if (!socketptr->tlsenabled)
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_STR(optionstr),
+ LEN_AND_LIT("but TLS not enabled"));
+ return; /* make compiler and analyzers happy */
+ }
+ /* TODO: allow verify-mode options in idstr */
+ status = gtm_tls_renegotiate((gtm_tls_socket_t *)socketptr->tlssocket);
+ if (0 != status)
+ {
+ tls_errno = gtm_tls_errno();
+ if (0 > tls_errno)
+ errp = gtm_tls_get_error();
+ else
+ errp = STRERROR(tls_errno);
+ len = SIZEOF(ONE_COMMA) - 1;
+ memcpy(iod->dollar.device, ONE_COMMA, len);
+ errlen = STRLEN(errp);
+ devlen = MIN((SIZEOF(iod->dollar.device) - len - 1), errlen);
+ memcpy(&iod->dollar.device[len], errp, devlen + 1);
+ if (devlen < errlen)
+ iod->dollar.device[SIZEOF(iod->dollar.device) - 1] = '\0';
+ if (socketptr->ioerror)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSRENEGOTIATE, 0,
+ ERR_TEXT, 2, errlen, errp);
+ return;
+ }
+ } else
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_STR(optionstr),
+ LEN_AND_LIT("not a valid option"));
+ if (NO_M_TIMEOUT != timeoutarg)
+ dollar_truth = TRUE;
+ return;
+}
+#endif
diff --git a/sr_unix/jnlpool_init.c b/sr_unix/jnlpool_init.c
index 2acb5ae..cf2f7cb 100644
--- a/sr_unix/jnlpool_init.c
+++ b/sr_unix/jnlpool_init.c
@@ -959,7 +959,7 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
assert(NULL != gtmsourcelocal_ptr);
QWASSIGNDW(gtmsourcelocal_ptr->read_addr, 0);
gtmsourcelocal_ptr->read = 0;
- gtmsourcelocal_ptr->read_state = READ_POOL;
+ gtmsourcelocal_ptr->read_state = gtmsourcelocal_ptr->jnlfileonly ? READ_FILE : READ_POOL;
gtmsourcelocal_ptr->mode = gtmsource_options.mode;
gtmsourcelocal_ptr->statslog = FALSE;
gtmsourcelocal_ptr->shutdown = NO_SHUTDOWN;
diff --git a/sr_unix/jobchild_init.c b/sr_unix/jobchild_init.c
index 91c8647..eece2b0 100644
--- a/sr_unix/jobchild_init.c
+++ b/sr_unix/jobchild_init.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -61,7 +61,7 @@ CONDITION_HANDLER(job_init_ch)
/* Child process test and initialization. If this copy of GTM is a child process, then initialize the child. */
void jobchild_init(void)
{
- unsigned int status;
+ boolean_t need_rtnobj_shm_free;
job_params_type jparms;
unsigned char *transfer_addr; /* Transfer data */
rhdtyp *base_addr;
@@ -71,7 +71,7 @@ void jobchild_init(void)
mval job_args[MAX_ACTUALS];
mstr routine, label;
int offset;
- int rc;
+ int status;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
@@ -84,7 +84,8 @@ void jobchild_init(void)
/* read parameters into parameter structure - references CHILD_FLAG_ENV */
ojchildparms(&jparms, &job_arglist, job_args);
/* Clear the environment variable so that subsequent child mumps processes can start normal initialization. */
- if (PUTENV(CLEAR_CHILD_FLAG_ENV))
+ PUTENV(status, CLEAR_CHILD_FLAG_ENV);
+ if (status)
{
util_out_print("Unable to clear gtmj0 process !UL exiting.", TRUE, process_id);
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno);
@@ -92,14 +93,17 @@ void jobchild_init(void)
/* Execute the command to be run before executing the actual M routine */
if (jparms.startup.len)
{
- rc = SYSTEM(jparms.startup.addr);
- if (-1 == rc)
+ status = SYSTEM(jparms.startup.addr);
+ if (-1 == status)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_JOBSTARTCMDFAIL, 0, errno);
- else if (0 != rc)
+ else if (0 != status)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(2) ERR_JOBSTARTCMDFAIL, 0);
}
- if(!job_addr(&jparms.routine, &jparms.label, jparms.offset,
- (char **)&base_addr, (char **)&transfer_addr))
+ /* See comment in ojstartchild.c about "need_rtnobj_shm_free". It is not used here because we will
+ * decrement rtnobj reference counts at exit time in relinkctl_rundown (called by gtm_exit_handler).
+ */
+ if (!job_addr(&jparms.routine, &jparms.label, jparms.offset,
+ (char **)&base_addr, (char **)&transfer_addr, &need_rtnobj_shm_free))
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBLABOFF);
/* Set process priority */
if (jparms.baspri)
@@ -136,7 +140,11 @@ void jobchild_init(void)
if (!cli_get_str("INFILE", run_file_name, &arg_len))
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_RUNPARAMERR);
lref_parse((uchar_ptr_t)run_file_name, &routine, &label, &offset);
- if(!job_addr(&routine, &label, offset, (char **)&base_addr, (char **)&transfer_addr))
+ /* See comment in ojstartchild.c about "need_rtnobj_shm_free". It is not used here because we will
+ * decrement rtnobj reference counts at exit time in relinkctl_rundown (called by gtm_exit_handler).
+ */
+ if (!job_addr(&routine, &label, offset, (char **)&base_addr,
+ (char **)&transfer_addr, &need_rtnobj_shm_free))
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBLABOFF);
} else if (MUMPS_CALLIN & invocation_mode) /* call-in mode */
{
diff --git a/sr_unix/jobsp.h b/sr_unix/jobsp.h
index 71a50a2..928785d 100644
--- a/sr_unix/jobsp.h
+++ b/sr_unix/jobsp.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -19,6 +19,7 @@
#define MAX_PRCNAM_LEN 15
#define MAX_STDIOE_LEN 1024
#define MAX_JOBPARM_LEN 1024
+
#define TIMEOUT_ERROR (MAX_SYSERR + 1) /* a special value to differentiate it from the rest of errno's */
#define CHILD_FLAG_ENV "gtmj0"
@@ -106,6 +107,7 @@ typedef struct
job_parm *parms;
size_t input_prebuffer_size;
char *input_prebuffer;
+ boolean_t passcurlvn;
} job_params_type;
typedef enum
@@ -126,7 +128,9 @@ typedef enum
job_done, /* last message */
job_set_params, /* followed by a job_params_msg message */
job_set_parm_list, /* followed by a job_arg_count_msg and "arg_count" job_arg_msg messages */
- job_set_input_buffer /* followed by a job_buffer_size_msg and a data message of "buffer_size" */
+ job_set_input_buffer, /* followed by a job_buffer_size_msg and a data message of "buffer_size" */
+ job_set_locals, /* followed by local_variable */
+ local_trans_done /* Indicates all of the locals have been sent to the grandchild */
} job_setup_op;
typedef struct
@@ -166,5 +170,5 @@ int ojstartchild(job_params_type *jparms, int argcnt, boolean_t *non_exit_return
void ojparams(char *p, job_params_type *job_params);
void ojgetch_env(job_params_type *jparms);
void ojchildioclean(void);
-
+void ojmidchild_send_var(void);
#endif
diff --git a/sr_unix/kitstart.csh b/sr_unix/kitstart.csh
index cb63b62..614c394 100644
--- a/sr_unix/kitstart.csh
+++ b/sr_unix/kitstart.csh
@@ -194,7 +194,7 @@ chmod 444 $readme_txt
# be copied as a part of open source distribution (down the script)
set open_source = 0
set GNU_COPYING_license = "${gtm_com}/COPYING"
-if (("$osname" == "linux" && ( "$arch" == "i686" || "x8664" == "$arch" )) || ("$osname" == "osf1" && "$arch" == "alpha")) then
+if (("$osname" == "linux" && ( "$arch" == "i586" || "x8664" == "$arch" )) || ("$osname" == "osf1" && "$arch" == "alpha")) then
set open_source = 1
/bin/cp -pf $cms_tools/opensource_COPYING $GNU_COPYING_license
chmod 444 $GNU_COPYING_license
@@ -323,7 +323,7 @@ foreach image ($imagetype)
# no directories to be writeable for group or world if aix or 32-bit linux, otherwise for all
chmod a+x configure
chmod a+x gtminstall
- if ((aix == ${osname}) || ((linux == ${osname}) && (i686 == "$arch"))) then
+ if ((aix == ${osname}) || ((linux == ${osname}) && ("i586" == "$arch"))) then
find . -type d -exec chmod go-w {} \;
else
find . -type d -exec chmod a-w {} \;
@@ -388,9 +388,9 @@ if ($testinstall) then
# blank line for default group
# V54003 now asks whether or not to retain .o files if libgtmutil.so is created
# We answer "y" to this question
- # If libgtmutil.so is not created(on i686) this question is not asked
+ # If libgtmutil.so is not created(on i586) this question is not asked
if ("$osname" != "osf1") then
- if ("$osname" == "linux" && "$arch" == "i686") then
+ if ("$osname" == "linux" && "$arch" == "i586") then
sh ./configure << CONFIGURE_EOF
@@ -438,9 +438,9 @@ CONFIGURE_EOF
# reversed from V54000
# V54003 now asks whether or not to retain .o files if libgtmutil.so is created
# We answer "y" to this question
- # If libgtmutil.so is not created(on i686) this question is not asked
+ # If libgtmutil.so is not created(on i586) this question is not asked
if("$osname" != "osf1") then
- if ("$osname" == "linux" && "$arch" == "i686") then
+ if ("$osname" == "linux" && "$arch" == "i586") then
sh ./configure << CONFIGURE_EOF
$rootgroup
@@ -528,7 +528,7 @@ CONFIGURE_EOF
set comp="$gtm_tools/gtm_compare_dir.csh ${install} ${tmp_dist}/$defgroup $gtm_tools/bdelete.txt"
set adddir=$gtm_tools/badd.txt
set deldir=$gtm_tools/bdeldir.txt
- if (("linux" == ${osname}) && ("i686" == ${arch})) then
+ if (("linux" == ${osname}) && ("i586" == ${arch})) then
set adddir=$gtm_tools/linuxi686_badd.txt
else if (("hpux" == ${osname}) && ("parisc" == ${arch})) then
set adddir=$gtm_tools/hpuxparisc_badd.txt
diff --git a/sr_unix/libmupip.list b/sr_unix/libmupip.list
index 1b5b823..1d501d9 100644
--- a/sr_unix/libmupip.list
+++ b/sr_unix/libmupip.list
@@ -89,6 +89,7 @@ mu_replpool_grab_sem
mu_replpool_release_sem
mu_rndwn_all
mu_rndwn_file
+mu_rndwn_rlnkctl
mu_rndwn_repl_instance
mu_rndwn_replpool
mu_signal_process
@@ -128,6 +129,7 @@ mupip_help
mupip_integ
mupip_intrpt
mupip_quit
+mupip_rctldump
mupip_recover
mupip_reorg
mupip_restore
@@ -204,6 +206,7 @@ ss_anal_shdw_file
ss_get_block
ss_initiate
ss_read_block
+trigger_upgrade
upd_log_init
updhelper_end
updhelper_init
diff --git a/sr_unix/load.h b/sr_unix/load.h
index bc34fb7..fb8bd14 100644
--- a/sr_unix/load.h
+++ b/sr_unix/load.h
@@ -33,8 +33,8 @@
continue; /* continue, when (onerror = ONERROR_PROCEED) or when user selects Yes in ONERROR_INTERACTIVE */ \
}
-void bin_load(uint4 begin, uint4 end);
-void go_load(uint4 begin, uint4 end);
+void bin_load(uint4 begin, uint4 end, char *line1_ptr, int line1_len);
+void go_load(uint4 begin, uint4 end, char *line1_ptr, int line1_len, char *line2_ptr, int line2_len);
void goq_load(void);
#endif /* LOAD_INCLUDED */
diff --git a/sr_unix/m_zrupdate.c b/sr_unix/m_zrupdate.c
index d65f7ec..6d1d5e8 100644
--- a/sr_unix/m_zrupdate.c
+++ b/sr_unix/m_zrupdate.c
@@ -19,7 +19,7 @@
#include "advancewindow.h"
#include "cmd.h"
-#ifdef USHBIN_SUPPORTED
+#ifdef AUTORELINK_SUPPORTED
/* Routine to compile ZRUPDATE command
*
* Current syntax:
diff --git a/sr_unix/maskpass.c b/sr_unix/maskpass.c
index 33e5817..c125765 100644
--- a/sr_unix/maskpass.c
+++ b/sr_unix/maskpass.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2009, 2013 Fidelity Information Services, Inc *
+ * Copyright 2009, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -17,16 +17,24 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
+#include <signal.h>
+#include <termios.h>
#include "gtmxc_types.h"
#include "gtmcrypt_util.h"
+static struct termios *tty = NULL;
+
+void maskpass_signal_handler(int sig);
+
int main()
{
- char passwd[GTM_PASSPHRASE_MAX], hex_out[GTM_PASSPHRASE_MAX * 2], mumps_exe[GTM_PATH_MAX], *env_ptr;
- struct stat stat_info;
- gtm_string_t passwd_str;
+ char passwd[GTM_PASSPHRASE_MAX], hex_out[GTM_PASSPHRASE_MAX * 2], mumps_exe[GTM_PATH_MAX], *env_ptr;
+ struct stat stat_info;
+ gtm_string_t passwd_str;
+ struct sigaction reset_term_handler, ignore_handler;
+ int sig;
/* Since the obfuscated password depends on $USER and the inode of $gtm_dist/mumps, make sure all the pre-requisites are
* available to this process.
@@ -47,8 +55,38 @@ int main()
printf("Cannot stat %s\n", mumps_exe);
exit(EXIT_FAILURE);
}
+ /* We want the process to restore the terminal settings (if they already changed by the time a signal is caught) on the more
+ * conventional terminal signals, such as SIGINT and SIGTERM, and ignore the non-critical other ones. We also do not want to
+ * allow putting the process in the background because the terminal settings may be unsuitable for user interaction at that
+ * point, and the user may decide to "sanitize" them, which might render the entered password visible upon resumption.
+ */
+ reset_term_handler.sa_handler = maskpass_signal_handler;
+ reset_term_handler.sa_flags = 0;
+ sigfillset(&reset_term_handler.sa_mask);
+ ignore_handler.sa_handler = SIG_IGN;
+ ignore_handler.sa_flags = 0;
+ sigemptyset(&ignore_handler.sa_mask);
+ for (sig = 1; sig <= NSIG; sig++)
+ {
+ switch (sig)
+ {
+ case SIGINT:
+ case SIGTERM:
+ sigaction(sig, &reset_term_handler, NULL);
+ break;
+ case SIGSEGV:
+ case SIGABRT:
+ case SIGBUS:
+ case SIGFPE:
+ case SIGTRAP:
+ case SIGKILL:
+ break;
+ default:
+ sigaction(sig, &ignore_handler, NULL);
+ }
+ }
/* Read the password (with terminal echo turned off). */
- if (-1 == gc_read_passwd(GTMCRYPT_DEFAULT_PASSWD_PROMPT, passwd, GTM_PASSPHRASE_MAX))
+ if (-1 == gc_read_passwd(GTMCRYPT_DEFAULT_PASSWD_PROMPT, passwd, GTM_PASSPHRASE_MAX, &tty))
{
printf("%s\n", gtmcrypt_err_string);
exit(EXIT_FAILURE);
@@ -66,3 +104,12 @@ int main()
printf("%s\n", hex_out);
return 0;
}
+
+void maskpass_signal_handler(int sig)
+{ /* If gc_read_passwd() changed the terminal settings before we got hit by an interrupt, the original terminal state should
+ * have been saved in tty, so we will only restore the terminal settings when the pointer is non-NULL.
+ */
+ if (NULL != tty)
+ tcsetattr(fileno(stdin), TCSAFLUSH, tty);
+ exit(-1);
+}
diff --git a/sr_unix/mdefsp.h b/sr_unix/mdefsp.h
index 4311150..27e30f9 100644
--- a/sr_unix/mdefsp.h
+++ b/sr_unix/mdefsp.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -14,13 +14,14 @@
#include <sys/types.h>
-#ifdef GTM64
-typedef long int8; /* 8-byte signed integer */
-typedef unsigned long uint8; /* 8-byte unsigned integer */
-typedef unsigned long gtm_uint8; /*these two datatypes are defined because */
-typedef long gtm_int8; /*int8 and uint8 are system defined in AIX_64*/
-#define INT8_NATIVE
+/* All current Unix platforms support {u,}int64_t, so set these up regardless of GTM64 setting. */
+#ifndef int8
+typedef int64_t int8; /* 8-byte signed integer */
+typedef uint64_t uint8; /* 8-byte unsigned integer */
#endif
+typedef uint64_t gtm_uint8; /* these two datatypes are defined because */
+typedef int64_t gtm_int8; /* int8 and uint8 are system defined in AIX_64 */
+#define INT8_NATIVE
#ifdef __s390__
typedef short int2; /* 2-byte signed integer */
@@ -42,6 +43,7 @@ typedef uint2 mach_inst;
#ifdef __sparc
#define CACHELINE_SIZE 256
#define USHBIN_SUPPORTED
+#define AUTORELINK_SUPPORTED
#define LINKAGE_PSECT_BOUNDARY 8
#define OFF_T_LONG
#define INO_T_LONG
@@ -71,6 +73,9 @@ typedef uint4 mach_inst;
#define MUTEX_MSEM_WAKE
#define POSIX_MSEM
#define USHBIN_SUPPORTED
+/* #define AUTORELINK_SUPPORTED -- not yet due to issues with replacing mapped object files - revisit if/when support objects in
+ * shared memory.
+ */
#define OFF_T_LONG
/* Make sure linkage Psect is aligned on appropriate boundary. */
#ifdef __ia64
@@ -126,7 +131,8 @@ typedef unsigned short in_port_t;
# ifdef __linux__
# undef BIGENDIAN
# define USHBIN_SUPPORTED
- /* Make sure linkage Psect is aligned on appropriate boundary. */
+# define AUTORELINK_SUPPORTED /* If this ever comes back */
+ /* Make sure linkage Psect is aligned on appropriate boundary */
# define LINKAGE_PSECT_BOUNDARY 8
typedef uint4 mach_inst; /* machine instruction */
# elif defined(__hpux)
@@ -146,6 +152,7 @@ typedef char mach_inst; /* machine instruction */
#ifdef __x86_64__
#define CACHELINE_SIZE 64
#define USHBIN_SUPPORTED
+#define AUTORELINK_SUPPORTED
#define INO_T_LONG
/*
#define MUTEX_MSEM_WAKE
diff --git a/sr_unix/mmrhash.c b/sr_unix/mmrhash.c
index 5894cf5..5dd991d 100644
--- a/sr_unix/mmrhash.c
+++ b/sr_unix/mmrhash.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2011 Fidelity Information Services, Inc *
+ * Copyright 2011, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -22,6 +22,9 @@
*-----------------------------------------------------------------------------*/
#include "mdef.h"
+
+#include "gtm_string.h"
+
#include "mmrhash.h"
/*
@@ -44,35 +47,34 @@
#endif
-static uint4 rotl32 ( uint4 x, char r );
static uint4 fmix ( uint4 h );
-#ifdef GTM64
-static gtm_uint8 rotl64 ( gtm_uint8 x, char r );
static gtm_uint8 fmix64 ( gtm_uint8 k );
-#endif
-
-static uint4 rotl32 ( uint4 x, char r )
-{
- return (x << r) | (x >> (32 - r));
-}
-#ifdef GTM64
-static gtm_uint8 rotl64 ( gtm_uint8 x, char r )
-{
- return (x << r) | (x >> (64 - r));
-}
-#endif
-
-#define ROTL32(x,y) rotl32(x,y)
-#define ROTL64(x,y) rotl64(x,y)
+#define ROTL32(X,Y) (((X) << (Y)) | ((X) >> (32 - (Y))))
+#define ROTL64(X,Y) (((X) << (Y)) | ((X) >> (64 - (Y))))
#define BIG_CONSTANT(x) (x##LLU)
#define GETBLOCK(p,i) (((const uint4 *)p)[(int)i])
-#ifdef GTM64
#define GETBLOCK64(p,i) (((const gtm_uint8 *)p)[(int)i])
+
+#ifdef BIGENDIAN
+# if defined(__GNUC__) && (__GNUC__>4 || (__GNUC__==4 && __GNUC_MINOR__>=3))
+# define UI64_TO_LE(X) (__builtin_bswap64(*((uint64_t*)&(X))))
+# else
+# define UI64_TO_LE(X) (X) = ((((X) & BIG_CONSTANT(0xff)) << 56) \
+ | (((X) & BIG_CONSTANT(0xff00)) << 40) \
+ | (((X) & BIG_CONSTANT(0xff0000)) << 24) \
+ | (((X) & BIG_CONSTANT(0xff000000)) << 8) \
+ | (((X) & BIG_CONSTANT(0xff00000000)) >> 8) \
+ | (((X) & BIG_CONSTANT(0xff0000000000)) >> 24) \
+ | (((X) & BIG_CONSTANT(0xff000000000000)) >> 40) \
+ | (((X) & BIG_CONSTANT(0xff00000000000000)) >> 56))
+# endif
+#else
+#define UI64_TO_LE(X) /* nothing */
#endif
/*-----------------------------------------------------------------------------
@@ -91,7 +93,6 @@ static FORCE_INLINE uint4 fmix ( uint4 h )
/*----------*/
-#ifdef GTM64
static FORCE_INLINE gtm_uint8 fmix64 ( gtm_uint8 k )
{
k ^= k >> 33;
@@ -102,7 +103,6 @@ static FORCE_INLINE gtm_uint8 fmix64 ( gtm_uint8 k )
return k;
}
-#endif
/*-----------------------------------------------------------------------------*/
@@ -110,10 +110,11 @@ void MurmurHash3_x86_32 ( const void * key, int len,
uint4 seed, void * out )
{
int i;
- const unsigned char * data = (const unsigned char*)key;
const unsigned char * tail;
const uint4 * blocks;
const int nblocks = len / 4;
+ static char *buff;
+ static int bufflen;
uint4 h1 = seed;
@@ -123,9 +124,28 @@ void MurmurHash3_x86_32 ( const void * key, int len,
/*----------
* body */
-
- blocks = (const uint4 *)(data + nblocks*4);
-
+# ifndef UNALIGNED_ACCESS_SUPPORTED
+ /* Murmur3 hash works only on 4-byte aligned keys so align key to avoid unaligned access error
+ * messages from an architecture that does not support it.
+ */
+ if (len && (0 != ((UINTPTR_T)key % 4)))
+ { /* make buffer 4-byte aligned */
+ if (bufflen < len)
+ {
+ if (NULL != buff)
+ {
+ assert(bufflen);
+ free(buff);
+ }
+ bufflen = len * 2;
+ buff = malloc(bufflen);
+ }
+ assert(bufflen >= len);
+ memcpy(buff, key, len);
+ key = (const unsigned char*)buff;
+ }
+# endif
+ blocks = (const uint4 *)((char *)key + nblocks*4);
for(i = -nblocks; i; i++)
{
k1 = GETBLOCK(blocks,i);
@@ -142,10 +162,14 @@ void MurmurHash3_x86_32 ( const void * key, int len,
/*----------
* tail */
- tail = (const unsigned char*)(data + nblocks*4);
+ tail = (const unsigned char*)blocks;
k1 = 0;
+ /* The shifts below assume little endian, so the handling of the tail block is inconsistent with normal blocks
+ * on big endian systems. However, we are already using this version and we don't want to change the resulting
+ * hashes, so leave it alone.
+ */
switch(len & 3)
{
case 3: k1 ^= tail[2] << 16;
@@ -173,6 +197,8 @@ void MurmurHash3_x86_128 ( const void * key, const int len,
const unsigned char * data = (const unsigned char*)key;
const unsigned char * tail;
const int nblocks = len / 16;
+ static char *buff;
+ static int bufflen;
uint4 h1 = seed;
uint4 h2 = seed;
@@ -191,6 +217,27 @@ void MurmurHash3_x86_128 ( const void * key, const int len,
/*----------
* body */
+# ifndef UNALIGNED_ACCESS_SUPPORTED
+ /* Murmur3 hash works only on 4-byte aligned keys so align key to avoid unaligned access error
+ * messages from an architecture that does not support it.
+ */
+ if (len && (0 != ((UINTPTR_T)key % 4)))
+ { /* make buffer 4-byte aligned */
+ if (bufflen < len)
+ {
+ if (NULL != buff)
+ {
+ assert(bufflen);
+ free(buff);
+ }
+ bufflen = len * 2;
+ buff = malloc(bufflen);
+ }
+ assert(bufflen >= len);
+ memcpy(buff, key, len);
+ data = (const unsigned char*)buff;
+ }
+# endif
const uint4 * blocks = (const uint4 *)(data + nblocks*16);
@@ -228,6 +275,9 @@ void MurmurHash3_x86_128 ( const void * key, const int len,
k3 = 0;
k4 = 0;
+ /* The shifts below assume little endian, so the handling of the tail block is inconsistent with normal blocks
+ * on big endian systems. If we start using this routine, we should decide whether to fix it or not.
+ */
switch(len & 15)
{
case 15: k4 ^= tail[14] << 16;
@@ -278,7 +328,6 @@ void MurmurHash3_x86_128 ( const void * key, const int len,
/*-----------------------------------------------------------------------------*/
-#ifdef GTM64
void MurmurHash3_x64_128 ( const void * key, const int len,
const uint4 seed, void * out )
{
@@ -286,6 +335,8 @@ void MurmurHash3_x64_128 ( const void * key, const int len,
const unsigned char * data = (const unsigned char*)key;
const unsigned char * tail;
const int nblocks = len / 16;
+ static char *buff;
+ static int bufflen;
gtm_uint8 h1 = seed;
gtm_uint8 h2 = seed;
@@ -298,6 +349,27 @@ void MurmurHash3_x64_128 ( const void * key, const int len,
/*----------
* body */
+# ifndef UNALIGNED_ACCESS_SUPPORTED
+ /* Murmur3 hash works only on 4-byte aligned keys so align key to avoid unaligned access error
+ * messages from an architecture that does not support it.
+ */
+ if (len && (0 != ((UINTPTR_T)key % 8)))
+ { /* make buffer 4-byte aligned */
+ if (bufflen < len)
+ {
+ if (NULL != buff)
+ {
+ assert(bufflen);
+ free(buff);
+ }
+ bufflen = len * 2;
+ buff = malloc(bufflen);
+ }
+ assert(bufflen >= len);
+ memcpy(buff, key, len);
+ data = (const unsigned char*)buff;
+ }
+# endif
const gtm_uint8 * blocks = (const gtm_uint8 *)(data);
@@ -306,6 +378,9 @@ void MurmurHash3_x64_128 ( const void * key, const int len,
k1 = GETBLOCK64(blocks,i*2+0);
k2 = GETBLOCK64(blocks,i*2+1);
+ UI64_TO_LE(k1);
+ UI64_TO_LE(k2);
+
k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
@@ -323,6 +398,10 @@ void MurmurHash3_x64_128 ( const void * key, const int len,
k1 = 0;
k2 = 0;
+ /* The shifts below originally assumed little endian, so the handling of the tail block was inconsistent with normal blocks
+ * on big endian systems. Since we haven't used this routine previously, fix it here instead of making the progressive
+ * version consistent with the broken implementation.
+ */
switch(len & 15)
{
case 15: k2 ^= ((gtm_uint8)tail[14]) << 48;
@@ -362,7 +441,372 @@ void MurmurHash3_x64_128 ( const void * key, const int len,
((gtm_uint8*)out)[0] = h1;
((gtm_uint8*)out)[1] = h2;
}
+
+/*******************************************************************************
+ * Progressive 128-bit MurmurHash3
+ *******************************************************************************/
+
+#define C1 BIG_CONSTANT(0x87c37b91114253d5)
+#define C2 BIG_CONSTANT(0x4cf5ad432745937f)
+#define M1 0x52dce729
+#define M2 0x38495ab5
+
+#define LSHIFT_BYTES_SAFE(LHS, RHS) ((LHS) << ((RHS) * 8))
+#define RSHIFT_BYTES_SAFE(LHS, RHS) ((LHS) >> ((RHS) * 8))
+#define LSHIFT_BYTES(LHS, RHS) ((RHS < SIZEOF(LHS)) ? LSHIFT_BYTES_SAFE(LHS, RHS) : 0)
+#define RSHIFT_BYTES(LHS, RHS) ((RHS < SIZEOF(LHS)) ? RSHIFT_BYTES_SAFE(LHS, RHS) : 0)
+
+#if !defined(BIGENDIAN)
+
+/* Little Endian */
+
+#define ADD_BYTES(STATEPTR, KEY, COUNT) \
+MBSTART { \
+ int ab_count, ab_offset, ab_carry_bytes; \
+ const unsigned char *ab_key, *ab_ptr; \
+ gtm_uint8 c1, c2; \
+ \
+ assert((STATEPTR)->carry_bytes + (COUNT) >= 0); \
+ assert((STATEPTR)->carry_bytes + (COUNT) <= 16); \
+ ab_count = (COUNT); \
+ ab_carry_bytes = (STATEPTR)->carry_bytes; \
+ ab_offset = ab_carry_bytes + ab_count; \
+ ab_key = (KEY); \
+ ab_ptr = ab_key + ab_count - 1; \
+ c1 = (STATEPTR)->c.one; \
+ c2 = (STATEPTR)->c.two; \
+ assert((ab_carry_bytes != 0) || ((c1 == 0) && (c2 == 0))); \
+ for (; (ab_offset > 8) && (ab_ptr >= ab_key); ab_ptr--, ab_offset--) \
+ c2 |= LSHIFT_BYTES_SAFE((gtm_uint8)*ab_ptr, (ab_offset - 9)); \
+ for (; ab_ptr >= ab_key; ab_ptr--, ab_offset--) \
+ c1 |= LSHIFT_BYTES_SAFE((gtm_uint8)*ab_ptr, (ab_offset - 1)); \
+ assert(((ab_carry_bytes + ab_count) != 0) || ((c1 == 0) && (c2 == 0))); \
+ assert((ab_count != 0) || (((STATEPTR)->c.one == c1) && ((STATEPTR)->c.two == c2))); \
+ (STATEPTR)->c.one = c1; \
+ (STATEPTR)->c.two = c2; \
+ (STATEPTR)->carry_bytes = ab_carry_bytes + ab_count; \
+} MBEND
+
+#define GET_BLOCK(STATEPTR, KEY, K1, K2) \
+MBSTART { \
+ int gb_carry_bytes; \
+ gtm_uint8 gb_m1, gb_m2, gb_k1, gb_k2, gb_c1, gb_c2; \
+ \
+ assert(((STATEPTR)->carry_bytes != 0) || (((STATEPTR)->c.one == 0) && ((STATEPTR)->c.two == 0))); \
+ assert((STATEPTR)->carry_bytes < 16); \
+ gb_carry_bytes = (STATEPTR)->carry_bytes; \
+ gb_m1 = ((gtm_uint8 *)(KEY))[0]; \
+ gb_m2 = ((gtm_uint8 *)(KEY))[1]; \
+ if (0 == gb_carry_bytes) \
+ { \
+ (K1) = gb_m1; \
+ (K2) = gb_m2; \
+ } \
+ else if (8 == gb_carry_bytes) \
+ { \
+ gb_k1 = (STATEPTR)->c.one; \
+ gb_k2 = gb_m1; \
+ gb_c1 = gb_m2; \
+ /* gb_c2 = 0; */ \
+ (K1) = gb_k1; \
+ (K2) = gb_k2; \
+ (STATEPTR)->c.one = gb_c1; \
+ assert(0 == (STATEPTR)->c.two); \
+ } \
+ else if (gb_carry_bytes < 8) \
+ { \
+ gb_k1 = (STATEPTR)->c.one | LSHIFT_BYTES_SAFE(gb_m1, gb_carry_bytes); \
+ gb_k2 = RSHIFT_BYTES_SAFE(gb_m1, (8 - gb_carry_bytes)) \
+ | LSHIFT_BYTES_SAFE(gb_m2, gb_carry_bytes); \
+ gb_c1 = RSHIFT_BYTES_SAFE(gb_m2, (8 - gb_carry_bytes)); \
+ /* gb_c2 = 0; */ \
+ (K1) = gb_k1; \
+ (K2) = gb_k2; \
+ (STATEPTR)->c.one = gb_c1; \
+ assert(0 == (STATEPTR)->c.two); \
+ } \
+ else { \
+ gb_k1 = (STATEPTR)->c.one; \
+ gb_k2 = (STATEPTR)->c.two \
+ | LSHIFT_BYTES_SAFE(gb_m1, (gb_carry_bytes - 8)); \
+ gb_c1 = RSHIFT_BYTES_SAFE(gb_m1, (16 - gb_carry_bytes)) \
+ | LSHIFT_BYTES_SAFE(gb_m2, (gb_carry_bytes - 8)); \
+ gb_c2 = RSHIFT_BYTES_SAFE(gb_m2, (16 - gb_carry_bytes)); \
+ (K1) = gb_k1; \
+ (K2) = gb_k2; \
+ (STATEPTR)->c.one = gb_c1; \
+ (STATEPTR)->c.two = gb_c2; \
+ } \
+} MBEND
+
+#else
+
+/* Big Endian */
+
+#define ADD_BYTES(STATEPTR, KEY, COUNT) \
+MBSTART { \
+ int ab_count, ab_offset, ab_carry_bytes; \
+ const unsigned char *ab_key, *ab_ptr; \
+ gtm_uint8 c1, c2; \
+ \
+ assert((STATEPTR)->carry_bytes + (COUNT) >= 0); \
+ assert((STATEPTR)->carry_bytes + (COUNT) <= 16); \
+ ab_count = (COUNT); \
+ ab_carry_bytes = (STATEPTR)->carry_bytes; \
+ ab_offset = ab_carry_bytes + ab_count; \
+ ab_key = (KEY); \
+ ab_ptr = ab_key + ab_count - 1; \
+ c1 = (STATEPTR)->c.one; \
+ c2 = (STATEPTR)->c.two; \
+ assert((ab_carry_bytes != 0) || ((c1 == 0) && (c2 == 0))); \
+ for (; (ab_offset > 8) && (ab_ptr >= ab_key); ab_ptr--, ab_offset--) \
+ c2 |= LSHIFT_BYTES_SAFE((gtm_uint8)*ab_ptr, (16 - ab_offset)); \
+ for (; ab_ptr >= ab_key; ab_ptr--, ab_offset--) \
+ c1 |= LSHIFT_BYTES_SAFE((gtm_uint8)*ab_ptr, (8 - ab_offset)); \
+ assert(((ab_carry_bytes + ab_count) != 0) || ((c1 == 0) && (c2 == 0))); \
+ assert((ab_count != 0) || (((STATEPTR)->c.one == c1) && ((STATEPTR)->c.two == c2))); \
+ (STATEPTR)->c.one = c1; \
+ (STATEPTR)->c.two = c2; \
+ (STATEPTR)->carry_bytes = ab_carry_bytes + ab_count; \
+} MBEND
+
+#define GET_BLOCK(STATEPTR, KEY, K1, K2) \
+MBSTART { \
+ int gb_carry_bytes; \
+ gtm_uint8 gb_m1, gb_m2, gb_k1, gb_k2, gb_c1, gb_c2; \
+ \
+ assert(((STATEPTR)->carry_bytes != 0) || (((STATEPTR)->c.one == 0) && ((STATEPTR)->c.two == 0))); \
+ gb_carry_bytes = (STATEPTR)->carry_bytes; \
+ gb_m1 = ((gtm_uint8 *)(KEY))[0]; \
+ gb_m2 = ((gtm_uint8 *)(KEY))[1]; \
+ if (0 == gb_carry_bytes) \
+ { \
+ (K1) = gb_m1; \
+ (K2) = gb_m2; \
+ } \
+ else if (8 == gb_carry_bytes) \
+ { \
+ gb_k1 = (STATEPTR)->c.one; \
+ gb_k2 = gb_m1; \
+ gb_c1 = gb_m2; \
+ /* gb_c2 = 0; */ \
+ (K1) = gb_k1; \
+ (K2) = gb_k2; \
+ (STATEPTR)->c.one = gb_c1; \
+ assert(0 == (STATEPTR)->c.two); \
+ } \
+ else if ( gb_carry_bytes < 8) \
+ { \
+ gb_k1 = (STATEPTR)->c.one | RSHIFT_BYTES_SAFE(gb_m1, gb_carry_bytes); \
+ gb_k2 = LSHIFT_BYTES_SAFE(gb_m1, (8 - gb_carry_bytes)) \
+ | RSHIFT_BYTES_SAFE(gb_m2, gb_carry_bytes); \
+ gb_c1 = LSHIFT_BYTES_SAFE(gb_m2, (8 - gb_carry_bytes)); \
+ /* gb_c2 = 0; */ \
+ (K1) = gb_k1; \
+ (K2) = gb_k2; \
+ (STATEPTR)->c.one = gb_c1; \
+ assert(0 == (STATEPTR)->c.two); \
+ } \
+ else { \
+ gb_k1 = (STATEPTR)->c.one; \
+ gb_k2 = (STATEPTR)->c.two \
+ | RSHIFT_BYTES_SAFE(gb_m1, (gb_carry_bytes - 8)); \
+ gb_c1 = LSHIFT_BYTES_SAFE(gb_m1, (16 - gb_carry_bytes)) \
+ | RSHIFT_BYTES_SAFE(gb_m2, (gb_carry_bytes - 8)); \
+ gb_c2 = LSHIFT_BYTES_SAFE(gb_m2, (16 - gb_carry_bytes)); \
+ (K1) = gb_k1; \
+ (K2) = gb_k2; \
+ (STATEPTR)->c.one = gb_c1; \
+ (STATEPTR)->c.two = gb_c2; \
+ } \
+} MBEND
+
#endif
+#define INTEGRATE_K1(K1, H1) \
+MBSTART { \
+ (K1) *= C1; \
+ (K1) = ROTL64((K1), 31); \
+ (K1) *= C2; \
+ (H1) ^= (K1); \
+} MBEND
+
+#define INTEGRATE_K2(K2, H2) \
+MBSTART { \
+ (K2) *= C2; \
+ (K2) = ROTL64((K2), 33); \
+ (K2) *= C1; \
+ (H2) ^= (K2); \
+} MBEND
+
+#define PROCESS_BLOCK(K1, K2, H1, H2) \
+MBSTART { \
+ UI64_TO_LE(K1); \
+ UI64_TO_LE(K2); \
+ INTEGRATE_K1(K1, H1); \
+ (H1) = ROTL64((H1), 27); \
+ (H1) += (H2); \
+ (H1) = (H1) * 5 + M1; \
+ INTEGRATE_K2(K2, H2); \
+ (H2) = ROTL64((H2), 31); \
+ (H2) += (H1); \
+ (H2) = (H2) * 5 + M2; \
+} MBEND
+
+#define PROCESS_BYTES(STATEPTR, KEY, LEN) \
+MBSTART { \
+ int pb_carry_fill = 0; \
+ \
+ assert((LEN) < 16); \
+ if ((STATEPTR)->carry_bytes + (LEN) >= 16) \
+ { \
+ /* fill the carry field, process it as a block, then clear it */ \
+ pb_carry_fill = 16 - (STATEPTR)->carry_bytes; \
+ ADD_BYTES((STATEPTR), (KEY), pb_carry_fill); \
+ assert((STATEPTR)->carry_bytes == 16); \
+ PROCESS_BLOCK((STATEPTR)->c.one, (STATEPTR)->c.two, (STATEPTR)->h.one, (STATEPTR)->h.two); \
+ (STATEPTR)->c.one = (STATEPTR)->c.two = 0; \
+ (STATEPTR)->carry_bytes = 0; \
+ } \
+ ADD_BYTES((STATEPTR), (KEY) + pb_carry_fill, (LEN) - pb_carry_fill); \
+} MBEND
+
+#define UNALIGNED_SAFE (defined(__i386) || defined(__x86_64__) || defined(_AIX))
+
+/* This is an endian-independent 16-byte murmur hash function */
+void gtmmrhash_128(const void *key, int len, uint4 seed, gtm_uint16 *out)
+{
+ hash128_state_t state;
+
+ HASH128_STATE_INIT(state, seed);
+ assert((state.carry_bytes == 0) && (state.c.one == 0) && (state.c.two == 0));
+ gtmmrhash_128_ingest(&state, key, len);
+ gtmmrhash_128_result(&state, len, out);
+}
+
+/* This is the same as gtmmrhash_128 (i.e. is endian independent) except that it generates a 4-byte hash
+ * (needed e.g. by STR_HASH macro). To avoid the overhead of an extra function call, we duplicate the
+ * code of "gtmmmrhash_128" here.
+ */
+void gtmmrhash_32(const void *key, int len, uint4 seed, uint4 *out4)
+{
+ hash128_state_t state;
+ gtm_uint16 out16;
+
+ HASH128_STATE_INIT(state, seed);
+ assert((state.carry_bytes == 0) && (state.c.one == 0) && (state.c.two == 0));
+ gtmmrhash_128_ingest(&state, key, len);
+ gtmmrhash_128_result(&state, len, &out16);
+ *out4 = (uint4)out16.one;
+}
+
+void gtmmrhash_128_ingest(hash128_state_t *state, const void *key, int len)
+{
+ int i;
+ gtm_uint8 k1, k2;
+ const unsigned char *keyptr;
+
+ if (0 == len)
+ return;
+
+ keyptr = key;
+# if !UNALIGNED_SAFE
+ /* determine the number of bytes to consume to reach 64-bit (8 byte) alignment */
+ i = (0x8 - ((UINTPTR_T)keyptr & 0x7)) & 0x7;
+ if (i > len)
+ i = len;
+ if (i > 0)
+ {
+ PROCESS_BYTES(state, keyptr, i);
+ keyptr += i;
+ len -= i;
+ }
+# endif
+ for (; len >= 16; len -= 16, keyptr += 16)
+ {
+ GET_BLOCK(state, keyptr, k1, k2);
+ PROCESS_BLOCK(k1, k2, state->h.one, state->h.two);
+ }
+ if (len > 0)
+ PROCESS_BYTES(state, keyptr, len);
+}
+
+void gtmmrhash_128_result(hash128_state_t *state, uint4 total_len, gtm_uint16 *out)
+{
+ gtm_uint8 k1, k2, h1, h2;
+
+ k1 = state->c.one;
+ k2 = state->c.two;
+ h1 = state->h.one;
+ h2 = state->h.two;
+
+ UI64_TO_LE(k1);
+ UI64_TO_LE(k2);
+ if (state->carry_bytes != 0)
+ {
+ if (state->carry_bytes > 8)
+ {
+ INTEGRATE_K2(k2, h2);
+ }
+ INTEGRATE_K1(k1, h1);
+ }
+
+ h1 ^= total_len;
+ h2 ^= total_len;
+ h1 += h2;
+ h2 += h1;
+ h1 = fmix64(h1);
+ h2 = fmix64(h2);
+ h1 += h2;
+ h2 += h1;
+
+ out->one = h1;
+ out->two = h2;
+}
+
+void gtmmrhash_128_bytes(const gtm_uint16 *hash, unsigned char *out)
+{
+# ifdef BIGENDIAN
+# define EXTRACT_BYTE(X, N) (((uint64_t)(X) & ((uint64_t)0xff << (N) * 8)) >> (N) * 8)
+ out[0] = EXTRACT_BYTE(hash->one, 0);
+ out[1] = EXTRACT_BYTE(hash->one, 1);
+ out[2] = EXTRACT_BYTE(hash->one, 2);
+ out[3] = EXTRACT_BYTE(hash->one, 3);
+ out[4] = EXTRACT_BYTE(hash->one, 4);
+ out[5] = EXTRACT_BYTE(hash->one, 5);
+ out[6] = EXTRACT_BYTE(hash->one, 6);
+ out[7] = EXTRACT_BYTE(hash->one, 7);
+ out[8] = EXTRACT_BYTE(hash->two, 0);
+ out[9] = EXTRACT_BYTE(hash->two, 1);
+ out[10] = EXTRACT_BYTE(hash->two, 2);
+ out[11] = EXTRACT_BYTE(hash->two, 3);
+ out[12] = EXTRACT_BYTE(hash->two, 4);
+ out[13] = EXTRACT_BYTE(hash->two, 5);
+ out[14] = EXTRACT_BYTE(hash->two, 6);
+ out[15] = EXTRACT_BYTE(hash->two, 7);
+# else
+ ((gtm_uint8 *)out)[0] = hash->one;
+ ((gtm_uint8 *)out)[1] = hash->two;
+# endif
+}
+
+void gtmmrhash_128_hex(const gtm_uint16 *hash, unsigned char *out)
+{
+ int i;
+ unsigned char bytes[16], n;
+
+ gtmmrhash_128_bytes(hash, bytes);
+ for (i = 0; i < 16; i++)
+ {
+ n = bytes[i] & 0xf;
+ out[i * 2 + 1] = (n < 10) ? (n + '0') : (n - 10 + 'a');
+ n = (bytes[i] >> 4) & 0xf;
+ out[i * 2] = (n < 10) ? (n + '0') : (n - 10 + 'a');
+ }
+}
+
+
+/*******************************************************************************/
+
/*-----------------------------------------------------------------------------*/
diff --git a/sr_unix/mmrhash.h b/sr_unix/mmrhash.h
index ed193da..052a4f5 100644
--- a/sr_unix/mmrhash.h
+++ b/sr_unix/mmrhash.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2011 Fidelity Information Services, Inc *
+ * Copyright 2011, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -26,9 +26,33 @@ void MurmurHash3_x86_32 ( const void * key, int len, uint4 seed, void * out );
void MurmurHash3_x86_128 ( const void * key, int len, uint4 seed, void * out );
-#ifdef GTM64
void MurmurHash3_x64_128 ( const void * key, int len, uint4 seed, void * out );
-#endif
+
+typedef struct
+{
+ gtm_uint8 one, two;
+} gtm_uint16;
+
+typedef struct
+{
+ gtm_uint16 h, c;
+ int carry_bytes;
+} hash128_state_t;
+
+#define HASH128_STATE_INIT(STATE, SEED) \
+MBSTART { \
+ (STATE).h.one = (STATE).h.two = (SEED); \
+ (STATE).c.one = (STATE).c.two = 0; \
+ (STATE).carry_bytes = 0; \
+} MBEND
+
+void gtmmrhash_128(const void *key, int len, uint4 seed, gtm_uint16 *out);
+void gtmmrhash_32(const void *key, int len, uint4 seed, uint4 *out4);
+void gtmmrhash_128_ingest(hash128_state_t *state, const void *key, int len);
+void gtmmrhash_128_result(hash128_state_t *state, uint4 total_len, gtm_uint16 *out);
+
+void gtmmrhash_128_hex(const gtm_uint16 *hash, unsigned char *out);
+void gtmmrhash_128_bytes(const gtm_uint16 *hash, unsigned char *out);
#endif
diff --git a/sr_unix/mu_all_version_standalone.c b/sr_unix/mu_all_version_standalone.c
index 6af0afa..511fe28 100644
--- a/sr_unix/mu_all_version_standalone.c
+++ b/sr_unix/mu_all_version_standalone.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2005, 2013 Fidelity Information Services, Inc *
+ * Copyright 2005, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -92,7 +92,7 @@ void mu_all_version_get_standalone(char_ptr_t db_fn, sem_info *sem_inf)
{
save_errno = errno;
mu_all_version_release_standalone(sem_inf);
- rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("ftok()"), CALLFROM, save_errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("ftok()"), CALLFROM, save_errno);
}
sem_inf[i].sem_id = semget(sem_inf[i].ftok_key, 3, RWDALL | IPC_CREAT | IPC_EXCL);
if (-1 == sem_inf[i].sem_id)
@@ -107,11 +107,13 @@ void mu_all_version_get_standalone(char_ptr_t db_fn, sem_info *sem_inf)
*/
if (EEXIST == save_errno || EAGAIN == save_errno || EINVAL == save_errno)
/* Semaphore already exists and/or is locked-- likely rundown needed */
- rts_error(VARLSTCNT(9) MAKE_MSG_TYPE(ERR_MUSTANDALONE, ERROR), 2, RTS_ERROR_TEXT(db_fn),
- save_errno, 0, ERR_FTOKKEY, 1, sem_inf[i].ftok_key);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9)
+ MAKE_MSG_TYPE(ERR_MUSTANDALONE, ERROR), 2, RTS_ERROR_TEXT(db_fn),
+ save_errno, 0, ERR_FTOKKEY, 1, sem_inf[i].ftok_key);
else
- rts_error(VARLSTCNT(12) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semget()"), CALLFROM, save_errno, 0,
- ERR_FTOKKEY, 1, sem_inf[i].ftok_key);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(12)
+ ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semget()"), CALLFROM, save_errno, 0,
+ ERR_FTOKKEY, 1, sem_inf[i].ftok_key);
}
SEMOP(sem_inf[i].sem_id, sop, 4, rc, NO_WAIT);
if (-1 == rc)
@@ -119,15 +121,16 @@ void mu_all_version_get_standalone(char_ptr_t db_fn, sem_info *sem_inf)
save_errno = errno;
mu_all_version_release_standalone(sem_inf);
if (EAGAIN == save_errno)
- rts_error(VARLSTCNT(12) MAKE_MSG_TYPE(ERR_MUSTANDALONE, ERROR), 2, RTS_ERROR_TEXT(db_fn),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(12)
+ MAKE_MSG_TYPE(ERR_MUSTANDALONE, ERROR), 2, RTS_ERROR_TEXT(db_fn),
save_errno, 0, ERR_FTOKKEY, 1, sem_inf[i].ftok_key,
- ERR_SEMID, 1, sem_inf[i].sem_id);
+ ERR_SEMID, 1, sem_inf[i].sem_id);
else
- rts_error(VARLSTCNT(15) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semop()"), CALLFROM, save_errno, 0,
- ERR_FTOKKEY, 1, sem_inf[i].ftok_key, ERR_SEMID, 1, sem_inf[i].sem_id);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(15)
+ ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semop()"), CALLFROM, save_errno, 0,
+ ERR_FTOKKEY, 1, sem_inf[i].ftok_key, ERR_SEMID, 1, sem_inf[i].sem_id);
}
}
-
/* First try to access shared memory based on the database FTOK id. Only need to do the ftok returned by the first
FTOK done above as it was the only method where the shared memory and semaphore had the same key.
@@ -147,7 +150,7 @@ void mu_all_version_get_standalone(char_ptr_t db_fn, sem_info *sem_inf)
{
save_errno = errno;
mu_all_version_release_standalone(sem_inf);
- rts_error(VARLSTCNT(5) ERR_DBOPNERR, 2, RTS_ERROR_TEXT(db_fn), save_errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_DBOPNERR, 2, RTS_ERROR_TEXT(db_fn), save_errno);
}
# ifdef __MVS__
if (-1 == gtm_zos_tag_to_policy(fd, TAG_BINARY, &realfiletag))
@@ -157,7 +160,7 @@ void mu_all_version_get_standalone(char_ptr_t db_fn, sem_info *sem_inf)
if (0 != rc)
{
mu_all_version_release_standalone(sem_inf);
- rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("LSEEKREAD()"), CALLFROM, rc);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("LSEEKREAD()"), CALLFROM, rc);
}
CLOSEFILE_RESET(fd, rc); /* resets "fd" to FD_INVALID */
if (0 != v15_csd.shmid && INVALID_SHMID != v15_csd.shmid)
@@ -166,7 +169,7 @@ void mu_all_version_get_standalone(char_ptr_t db_fn, sem_info *sem_inf)
if (-1 != shmid)
{
mu_all_version_release_standalone(sem_inf);
- rts_error(VARLSTCNT(9) MAKE_MSG_TYPE(ERR_MUSTANDALONE, ERROR), 2, RTS_ERROR_TEXT(db_fn),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) MAKE_MSG_TYPE(ERR_MUSTANDALONE, ERROR), 2, RTS_ERROR_TEXT(db_fn),
save_errno, 0, ERR_FTOKKEY, 1, sem_inf[i].ftok_key);
}
}
@@ -179,17 +182,21 @@ void mu_all_version_release_standalone(sem_info *sem_inf)
int i, rc, save_errno;
/* Note that we ignore most errors in this routine as we may get called with the alleged semaphores in
- just about any state.
- */
+ * just about any state.
+ */
for (i = 0; FTOK_ID_CNT > i; ++i)
{ /* release/delete any held semaphores in this set */
if (sem_inf[i].sem_id && -1 != sem_inf[i].sem_id)
{
rc = semctl(sem_inf[i].sem_id, 0, IPC_RMID);
- if (-1 == rc && EIDRM != errno)
- { /* Don't care if semaphore already removed */
+ if (-1 == rc)
+ {
save_errno = errno;
- send_msg(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semctl(remid)"), CALLFROM, save_errno);
+ if (!SEM_REMOVED(save_errno))
+ { /* Don't care if semaphore already removed (probably by a concurrent mupip rundown) */
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8)
+ ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semctl(remid)"), CALLFROM, save_errno);
+ }
}
sem_inf[i].sem_id = 0; /* Clear so we don't repeat if redriven */
}
diff --git a/sr_unix/mu_rndwn_file.c b/sr_unix/mu_rndwn_file.c
index 3a225cf..420d8ba 100644
--- a/sr_unix/mu_rndwn_file.c
+++ b/sr_unix/mu_rndwn_file.c
@@ -993,7 +993,7 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
if (0 != shm_rmid(udi->shmid))
{
save_errno = errno;
- if ((EINVAL != save_errno) && (EIDRM != save_errno))
+ if (!SHM_REMOVED(save_errno))
{
assert(FALSE);
RNDWN_ERR("!AD -> Error removing shared memory.", reg);
diff --git a/sr_unix/mu_rndwn_rlnkctl.c b/sr_unix/mu_rndwn_rlnkctl.c
new file mode 100644
index 0000000..6aea790
--- /dev/null
+++ b/sr_unix/mu_rndwn_rlnkctl.c
@@ -0,0 +1,65 @@
+/****************************************************************
+ * *
+ * Copyright 2014 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#ifdef AUTORELINK_SUPPORTED
+
+#include "gtm_string.h"
+
+#include "relinkctl.h"
+#include "util.h"
+#include <rtnhdr.h> /* needed for zroutines.h */
+#include "zroutines.h"
+#include "cli.h"
+#include "cliif.h"
+#include "cli_parse.h"
+#endif
+#include "mu_rndwn_rlnkctl.h" /* for mupip_rctldump prototype */
+
+#ifdef AUTORELINK_SUPPORTED
+error_def(ERR_MUPCLIERR);
+#endif
+
+void mu_rndwn_rlnkctl(void)
+{
+# ifdef AUTORELINK_SUPPORTED
+ open_relinkctl_sgm *linkctl;
+ relinkshm_hdr_t *shm_hdr;
+ relinkrec_t *linkrec;
+ relinkctl_data *hdr;
+ rtnobjshm_hdr_t *rtnobj_shm_hdr;
+ char objdir[GTM_PATH_MAX];
+ int i, j, recnum, n_records, shmid, shm_stat, save_errno;
+ unsigned short max_len;
+ mstr dir;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ TREF(is_mu_rndwn_rlnkctl) = TRUE; /* relinkctl_open and relinkctl_rundown check this flag to act differently */
+ if (TREF(parms_cnt))
+ {
+ assert(1 == TREF(parms_cnt));
+ max_len = SIZEOF(objdir);
+ if (!cli_get_str("WHAT", objdir, &max_len))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUPCLIERR);
+ dir.addr = objdir;
+ dir.len = max_len;
+ linkctl = relinkctl_attach(&dir);
+ assert(linkctl == TREF(open_relinkctl_list));
+ assert((NULL == linkctl) || (NULL == linkctl->next));
+ } else
+ zro_init();
+ relinkctl_rundown(TRUE, FALSE); /* will rundown one or more linkctl files opened above */
+ TREF(is_mu_rndwn_rlnkctl) = FALSE;
+# endif /* AUTORELINK_SUPPORTED */
+}
+
diff --git a/sr_unix/do_shmat.h b/sr_unix/mu_rndwn_rlnkctl.h
similarity index 67%
copy from sr_unix/do_shmat.h
copy to sr_unix/mu_rndwn_rlnkctl.h
index c4143a7..81aaf1d 100644
--- a/sr_unix/do_shmat.h
+++ b/sr_unix/mu_rndwn_rlnkctl.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * Copyright 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -9,9 +9,9 @@
* *
****************************************************************/
-#ifndef __DO_SHMAT_H__
-#define __DO_SHMAT_H__
+#ifndef MU_RNDWN_RLNKCTL_INCLUDED
+#define MU_RNDWN_RLNKCTL_INCLUDED
-void *do_shmat(int4 shmid, const void *shmaddr, int4 shmflg);
+void mu_rndwn_rlnkctl(void);
-#endif
+#endif /* MU_RNDWN_RLNKCTL_INCLUDED */
diff --git a/sr_unix/mupip_cmd.c b/sr_unix/mupip_cmd.c
index a4b03b0..9ee21d9 100644
--- a/sr_unix/mupip_cmd.c
+++ b/sr_unix/mupip_cmd.c
@@ -53,6 +53,7 @@
#include "mupip_ftok.h"
#include "mupip_endiancvt.h"
#include "mupip_crypt.h"
+#include "mupip_hash.h"
#include "gtmsource.h"
#include "gtmrecv.h"
#include "read_db_files_from_gld.h" /* Needed for updproc.h */
@@ -61,6 +62,8 @@
#ifdef GTM_SNAPSHOT
#include "db_snapshot.h"
#endif
+#include "mupip_rctldump.h"
+#include "mu_rndwn_rlnkctl.h"
static CLI_ENTRY mup_set_journal_qual[] = {
{ "ALIGNSIZE", 0, 0, 0, 0, 0, 0, VAL_REQ, 1, NON_NEG, VAL_NUM, 0 },
@@ -497,6 +500,7 @@ static CLI_ENTRY gtmsource_qual[] = {
{"FILTER", 0, 0, 0, 0, 0, 0, VAL_REQ, 0, NON_NEG, VAL_STR, 0 },
{"FREEZE", 0, inst_freeze_qual, 0, 0, 0, 0, VAL_NOT_REQ, 0, NON_NEG, VAL_STR, 0 },
{"INSTSECONDARY", 0, 0, 0, 0, 0, 0, VAL_REQ, 0, NON_NEG, VAL_STR, 0 },
+ {"JNLFILEONLY", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 1, NEG, VAL_N_A, 0 },
{"JNLPOOL", 0, inst_edit_qual, 0, 0, cli_disallow_mupip_replic_editinst, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 },
{"LOG", 0, 0, 0, 0, 0, 0, VAL_REQ, 0, NON_NEG, VAL_STR, 0 },
{"LOG_INTERVAL", 0, 0, 0, 0, 0, 0, VAL_REQ, 0, NON_NEG, VAL_NUM, 0 },
@@ -613,10 +617,15 @@ static CLI_PARM mup_rundown_parm[] = {
{ "", "", PARM_REQ}
};
+/* Note: "R" is a duplicate of "REGION". It is there so -R usages continue to be treated as -REGION and not have an
+ * ambiguity with "RELINKCTL".
+ */
static CLI_ENTRY mup_rundown_qual[] = {
- { "FILE", mupip_rundown, 0, 0, 0, 0, 0, VAL_DISALLOWED, 1, NON_NEG, VAL_N_A, 0 },
- { "OVERRIDE", mupip_rundown, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 },
- { "REGION", mupip_rundown, 0, 0, 0, 0, 0, VAL_DISALLOWED, 1, NON_NEG, VAL_N_A, 0 },
+ { "FILE", mupip_rundown, 0, 0, 0, 0, 0, VAL_DISALLOWED, 1, NON_NEG, VAL_N_A, 0 },
+ { "OVERRIDE", mupip_rundown, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 },
+ { "R", mupip_rundown, 0, 0, 0, 0, 0, VAL_DISALLOWED, 1, NON_NEG, VAL_N_A, 0 },
+ { "REGION", mupip_rundown, 0, 0, 0, 0, 0, VAL_DISALLOWED, 1, NON_NEG, VAL_N_A, 0 },
+ { "RELINKCTL", mu_rndwn_rlnkctl, 0, 0, 0, 0, 0, VAL_DISALLOWED, 1, 0, 0, 0 },
{ 0 }
};
@@ -677,9 +686,10 @@ static readonly CLI_PARM mup_trig_sel_parm[] = {
};
static CLI_ENTRY mup_trigger_qual[] = {
-{ "NOPROMPT", mupip_trigger, 0, 0, 0, 0, 0, VAL_NOT_REQ, 0, NON_NEG, VAL_STR, 0 },
-{ "SELECT", mupip_trigger, 0, mup_trig_sel_parm, 0, 0, 0, VAL_NOT_REQ, 1, NON_NEG, VAL_STR, 0 },
-{ "TRIGGERFILE", mupip_trigger, 0, 0, 0, 0, 0, VAL_REQ, 0, NON_NEG, VAL_STR, 0 },
+{ "NOPROMPT", mupip_trigger, 0, 0, 0, 0, 0, VAL_NOT_REQ, 0, NON_NEG, VAL_STR, 0 },
+{ "SELECT", mupip_trigger, 0, mup_trig_sel_parm, 0, 0, 0, VAL_NOT_REQ, 1, NON_NEG, VAL_STR, 0 },
+{ "TRIGGERFILE", mupip_trigger, 0, 0, 0, 0, 0, VAL_REQ, 0, NON_NEG, VAL_STR, 0 },
+{ "UPGRADE", mupip_trigger, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 },
{ 0 }
};
#endif
@@ -704,6 +714,11 @@ static CLI_ENTRY mup_downgrade_qual[] = {
{ 0 }
};
+static CLI_PARM mup_rctldump_parm[] = {
+ { "DIRECTORY", "Directory: ", PARM_REQ},
+ { "", "", PARM_REQ}
+};
+
GBLDEF CLI_ENTRY mupip_cmd_ary[] = {
{ "BACKUP", mupip_backup, mup_backup_qual, mup_backup_parm, 0, cli_disallow_mupip_backup, 0, VAL_DISALLOWED, 2, 0, 0, 0 },
{ "CONVERT", mupip_cvtpgm, mup_convert_qual, mup_convert_parm, 0, 0, 0, VAL_DISALLOWED, 2, 0, 0, 0 },
@@ -716,12 +731,14 @@ GBLDEF CLI_ENTRY mupip_cmd_ary[] = {
{ "EXTRACT", mu_extract, mup_extract_qual, mup_extract_parm, 0, 0, 0, VAL_DISALLOWED, 1, 0, 0, 0 },
{ "FREEZE", mupip_freeze, mup_freeze_qual, mup_freeze_parm, 0, cli_disallow_mupip_freeze, 0, VAL_DISALLOWED, 1, 0, 0, 0 },
{ "FTOK", mupip_ftok, mup_ftok_qual, mup_ftok_parm, 0, 0, 0, VAL_DISALLOWED, 1, 0, 0, 0 },
+{ "HASH", mupip_hash, 0, 0, 0, 0, 0, VAL_DISALLOWED, MAX_PARMS, 0, 0, 0 },
{ "HELP", util_help, 0, 0, 0, 0, 0, VAL_DISALLOWED, 1, 0, 0, 0 },
{ "INTEG", mupip_integ, mup_integ_qual, mup_integ_parm, 0, cli_disallow_mupip_integ, 0, VAL_DISALLOWED, 1, 0, 0, 0 },
{ "INTRPT", mupip_intrpt, 0, mup_intrpt_parm, 0, 0, 0, VAL_DISALLOWED, 1, 0, 0, 0 },
{ "JOURNAL", mupip_recover, mup_journal_qual, mup_journal_parm, 0, cli_disallow_mupip_journal, 0, VAL_DISALLOWED, 1, 0, 0, 0 },
{ "LOAD", mupip_cvtgbl, mup_load_qual, mup_load_parm, 0, 0, 0, VAL_DISALLOWED, 1, 0, 0, 0 },
{ "QUIT", mupip_quit, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, 0, 0, 0 },
+{ "RCTLDUMP", mupip_rctldump, 0, mup_rctldump_parm, 0, 0, 0, VAL_DISALLOWED, 1, 0, 0, 0 },
{ "REORG", mupip_reorg, mup_reorg_qual, mup_reorg_parm, 0, cli_disallow_mupip_reorg, 0, VAL_DISALLOWED, 1, 0, 0, 0 },
{ "REPLICATE", 0, mup_replicate_qual, mup_replicate_parm, 0, cli_disallow_mupip_replicate,0, VAL_DISALLOWED, 1, 0, 0, 0 },
{ "RESTORE", mupip_restore, mup_restore_qual, mup_restore_parm, 0, 0, 0, VAL_DISALLOWED, 2, 0, 0, 0 },
diff --git a/sr_unix/mupip_cmd_disallow.c b/sr_unix/mupip_cmd_disallow.c
index fe32ba0..94d3ffc 100644
--- a/sr_unix/mupip_cmd_disallow.c
+++ b/sr_unix/mupip_cmd_disallow.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2002, 2013 Fidelity Information Services, Inc.*
+ * Copyright 2002, 2014 Fidelity Information Services, Inc.*
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -512,8 +512,8 @@ boolean_t cli_disallow_mupip_trigger(void)
*cli_err_str_ptr = 0;
- /* any MUPIP TRIGGER command has to have either SELECT or TRIGGERFILE */
- disallow_return_value = !(d_c_cli_present("SELECT") || d_c_cli_present("TRIGGERFILE"));
+ /* any MUPIP TRIGGER command has to have either SELECT or TRIGGERFILE or UPGRADE */
+ disallow_return_value = !(d_c_cli_present("SELECT") || d_c_cli_present("TRIGGERFILE") || d_c_cli_present("UPGRADE"));
CLI_DIS_CHECK_N_RESET;
return FALSE;
}
diff --git a/sr_unix/mupip_cvtgbl.c b/sr_unix/mupip_cvtgbl.c
index d3a8a3b..9fe7736 100644
--- a/sr_unix/mupip_cvtgbl.c
+++ b/sr_unix/mupip_cvtgbl.c
@@ -31,6 +31,8 @@
#include "mu_outofband_setup.h"
#include <gtm_fcntl.h>
#include <errno.h>
+#include "muextr.h"
+#include <regex.h>
GBLREF int gv_fillfactor;
GBLREF bool mupip_error_occurred;
@@ -46,9 +48,13 @@ error_def(ERR_LOADBGSZ);
error_def(ERR_LOADBGSZ2);
error_def(ERR_LOADEDSZ);
error_def(ERR_LOADEDSZ2);
+error_def(ERR_LDBINFMT);
-#define MAX_ONERROR_VALUE_LEN 11 /* PROCEED, STOP, INTERACTIVE are the choices with INTERACTIVE being the maximum */
-#define MAX_FORMAT_VALUE_LEN 6 /* ZWR, BINARY, GO, GOQ are the choices with BINARY being the longest */
+#define CHAR_TO_READ_LINE1_BIN STR_LIT_LEN("d0GDS BINARY") /* read first 12 characters to check file is binary [d\0GDS BINARY] */
+#define CHAR_TO_READ_LINE1 1030 + 1 - CHAR_TO_READ_LINE1_BIN /* line 1 after 12 chars if not BINARY max[Label^%GO]=1030+\n */
+#define CHAR_TO_READ_LINE2 STR_LIT_LEN("GT.M 11-11-2090 12:12:12 ZWR") + 1 /* GT.M 11-11-2090 12:12:12 ZWR + newline*/
+#define MAX_ONERROR_VALUE_LEN STR_LIT_LEN("INTERACTIVE") /* PROCEED, STOP, INTERACTIVE are the choices with INTERACTIVE as max */
+#define MAX_FORMAT_VALUE_LEN STR_LIT_LEN("BINARY") /* ZWR, BINARY, GO, GOQ are the choices with BINARY being the longest */
void mupip_cvtgbl(void)
{
@@ -56,11 +62,13 @@ void mupip_cvtgbl(void)
char fn[MAX_FN_LEN + 1];
unsigned char buff[MAX_ONERROR_VALUE_LEN];
uint4 begin, end;
- int i, format;
+ int i, file_format;
uint4 cli_status;
gtm_int64_t begin_i8, end_i8;
- DCL_THREADGBL_ACCESS;
+ char *line1_ptr, *line2_ptr;
+ int line1_len, line2_len;
+ DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
assert(MAX_ONERROR_VALUE_LEN > MAX_FORMAT_VALUE_LEN); /* so the buff[] definition above is good for FORMAT and ONERROR */
/* If an online rollback occurs when we are loading up the database with new globals and takes us back to a prior logical
@@ -85,7 +93,7 @@ void mupip_cvtgbl(void)
mupip_exit(ERR_MUPCLIERR);
} else if (!cli_get_str("FILE", fn, &fn_len)) /* User wants to read from a file. */
mupip_exit(ERR_MUPCLIERR); /* Neither -STDIN nor file name specified. */
- file_input_init(fn, fn_len);
+ file_input_init(fn, fn_len, IOP_EOL);
if (mupip_error_occurred)
exit(-1);
mu_outofband_setup();
@@ -127,7 +135,6 @@ void mupip_cvtgbl(void)
gv_fillfactor = MAX_FILLFACTOR;
} else
gv_fillfactor = MAX_FILLFACTOR;
-
if (cli_present("ONERROR") == CLI_PRESENT)
{
len = SIZEOF(buff);
@@ -156,30 +163,119 @@ void mupip_cvtgbl(void)
}
} else
onerror = ONERROR_PROCEED; /* Default: Proceed on error */
-
+ file_format = get_file_format(&line1_ptr, &line2_ptr, &line1_len, &line2_len); /* Get file's format reading it's header */
if (cli_present("FORMAT") == CLI_PRESENT)
{
len = SIZEOF(buff);
if (!cli_get_str("FORMAT", (char *)buff, &len))
- go_load(begin, end);
+ go_load(begin, end, line1_ptr, line1_len, line2_ptr, line2_len);
else
{
lower_to_upper(buff, buff, len);
if (!memcmp(buff, "ZWR", len))
- go_load(begin, end);
+ {
+ if (MU_FMT_ZWR == file_format)
+ go_load(begin, end, line1_ptr, line1_len, line2_ptr, line2_len);
+ else
+ mupip_exit(ERR_LDBINFMT);
+ }
else if (!memcmp(buff, "BINARY", len))
- bin_load(begin, end);
+ {
+ if (MU_FMT_BINARY == file_format)
+ bin_load(begin, end, line1_ptr, line1_len);
+ else
+ mupip_exit(ERR_LDBINFMT);
+ }
else if (!memcmp(buff, "GO", len))
- go_load(begin, end);
+ {
+ if (MU_FMT_GO == file_format)
+ go_load(begin, end, line1_ptr, line1_len, line2_ptr, line2_len);
+ else
+ mupip_exit(ERR_LDBINFMT);
+ }
else if (!memcmp(buff, "GOQ", len))
- goq_load();
- else
{
- util_out_print("Illegal format for load",TRUE);
- mupip_exit(ERR_MUPCLIERR);
+ if (MU_FMT_GOQ == file_format)
+ goq_load();
+ else
+ mupip_exit(ERR_LDBINFMT);
+ } else
+ {
+ util_out_print("Illegal file format for load",TRUE);
+ mupip_exit(ERR_MUPCLIERR);
}
}
} else
- go_load(begin, end);
+ {
+ if (MU_FMT_BINARY == file_format)
+ bin_load(begin, end, line1_ptr, line1_len);
+ else if (MU_FMT_ZWR == file_format || MU_FMT_GO == file_format)
+ go_load(begin, end, line1_ptr, line1_len, line2_ptr, line2_len);
+ else if (MU_FMT_UNRECOG == file_format)
+ mupip_exit(ERR_LDBINFMT);
+ }
mupip_exit(mupip_error_occurred ? ERR_MUNOFINISH : SS_NORMAL);
}
+
+int get_file_format(char **line1_ptr, char **line2_ptr, int *line1_len, int *line2_len)
+{
+ char *c, *ctop;
+ char *line1, *line2;
+ int tmp_len;
+ regex_t regexGO, regexZWR;
+ int count, newlinepos;
+
+ line1 = (char *)malloc(CHAR_TO_READ_LINE1_BIN + CHAR_TO_READ_LINE1 + CHAR_TO_READ_LINE2); /* Allocate max space needed */
+ *line1_len = file_input_read_xchar(line1, CHAR_TO_READ_LINE1_BIN);
+ if (0 < *line1_len)
+ {
+ *line1_ptr = line1;
+ if (0 == memcmp(line1 + 6, "BINARY", STR_LIT_LEN("BINARY"))) /* If file is binary do not look further */
+ return MU_FMT_BINARY;
+ for (newlinepos = -1, count = 0, c = line1, ctop = c + *line1_len; c < ctop; c++, count++)
+ {
+ if ('\n' == *c)
+ {
+ newlinepos = count + 1;
+ break;
+ }
+ }
+ if (0 < newlinepos) /* If the line 1 length is less than 12 chars, line1 has characters from line 2 as well */
+ {
+ *line2_len = *line1_len - newlinepos;
+ *line1_len = newlinepos - 1;
+ line2 = line1 + newlinepos;
+ tmp_len = file_input_get_xchar(line2 + *line2_len, CHAR_TO_READ_LINE2);
+ *line2_len += tmp_len;
+ } else
+ {
+ tmp_len = file_input_get_xchar(line1 + *line1_len, CHAR_TO_READ_LINE1);
+ *line1_len += tmp_len;
+ line2 = line1 + *line1_len + 1;
+ *line2_len = file_input_get_xchar(line2, CHAR_TO_READ_LINE2);
+ }
+ *line2_ptr = line2;
+ if (0 < *line2_len)
+ {
+ /* Compile regular expression "GT.M DD-MON-YEAR 24:60:SS ZWR"*/
+ regcomp(®exZWR, "(GT.M )?[0-9]{2}[-]([A-Z]{3})[-][0-9]{4}[ ]{1,2}[0-9]{2}[:][0-9]{2}[:][0-9]{2} ZWR"
+ , REG_EXTENDED);
+ if (!regexec(®exZWR, line2, 0, NULL, 0) || (0 == memcmp(line2, "; ZWR", STR_LIT_LEN("; ZWR"))))
+ {
+ regfree(®exZWR);
+ return MU_FMT_ZWR;
+ }
+ regfree(®exZWR);
+ /* Compile regular expression "GT.M DD-MON-YEAR 24:60:SS"*/
+ regcomp(®exGO, "(GT.M )?[0-9]{2}[-]([A-Z]{3})[-][0-9]{4}[ ]{1,2}[0-9]{2}[:][0-9]{2}[:][0-9]{2}"
+ , REG_EXTENDED);
+ if (!regexec(®exGO, line2, 0, NULL, 0) || (0 == memcmp(line2, "; GLO", STR_LIT_LEN("; GLO"))))
+ {
+ regfree(®exGO);
+ return MU_FMT_GO;
+ }
+ regfree(®exGO);
+ }
+ }
+ return MU_FMT_UNRECOG;
+}
diff --git a/sr_unix/mupip_exit_handler.c b/sr_unix/mupip_exit_handler.c
index dd79f22..8d9631d 100644
--- a/sr_unix/mupip_exit_handler.c
+++ b/sr_unix/mupip_exit_handler.c
@@ -124,7 +124,7 @@ void mupip_exit_handler(void)
recvpool.recvpool_ctl = NULL;
}
gv_rundown(); /* also takes care of detaching from the journal pool */
- relinkctl_rundown(TRUE);
+ relinkctl_rundown(TRUE, TRUE); /* decrement relinkctl-attach & rtnobj-reference counts */
/* Log the exit of replication servers. In case they are exiting abnormally, their log file pointers
* might not be set up. In that case, use "stderr" for logging.
*/
diff --git a/sr_unix/mupip_hash.c b/sr_unix/mupip_hash.c
new file mode 100644
index 0000000..7edeeff
--- /dev/null
+++ b/sr_unix/mupip_hash.c
@@ -0,0 +1,65 @@
+/****************************************************************
+ * *
+ * Copyright 2014 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "util.h"
+/* #include "cli.h" */
+#include "gtmio.h"
+#include "gtm_threadgbl.h"
+#include "mmrhash.h"
+#include "mupip_hash.h"
+
+/* Display the 128-bit MurmurHash3 value(s) for the file(s) given on the command line.
+ * For example,
+ * % mupip hash foo.m bar.m
+ * foo.m: 77c5e66fcaedebf32199d87b0f6b6d80
+ * bar.m: 4b2a2ddc6803a30f4a769d4f6d9c8bd5
+ */
+
+void mupip_hash(void)
+{
+ int i, fd, status, size;
+ hash128_state_t hash_state;
+ gtm_uint16 hash;
+ unsigned char hash_hex[32], readbuf[4096];
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ for (i = 0; i < TREF(parms_cnt); i++)
+ {
+ OPENFILE(TAREF1(parm_ary, i), O_RDONLY, fd);
+ if (fd < 0)
+ {
+ util_out_print("Error opening !AZ for read", TRUE, TAREF1(parm_ary, i));
+ continue;
+ }
+ size = 0;
+ HASH128_STATE_INIT(hash_state, 0);
+ while (1)
+ {
+ DOREADRL(fd, readbuf, SIZEOF(readbuf), status);
+ if (-1 == status)
+ {
+ util_out_print("Error reading from !AZ", TRUE, TAREF1(parm_ary, i));
+ goto skipfile;
+ }
+ if (0 == status)
+ break;
+ gtmmrhash_128_ingest(&hash_state, readbuf, status);
+ size += status;
+ }
+ gtmmrhash_128_result(&hash_state, size, &hash);
+ gtmmrhash_128_hex(&hash, hash_hex);
+ util_out_print("!AZ: !AD", TRUE, TAREF1(parm_ary, i), SIZEOF(hash_hex), hash_hex);
+ skipfile:
+ CLOSEFILE_RESET(fd, status);
+ }
+}
diff --git a/sr_avms/release_name.h b/sr_unix/mupip_hash.h
similarity index 71%
copy from sr_avms/release_name.h
copy to sr_unix/mupip_hash.h
index 632b116..0cc2069 100644
--- a/sr_avms/release_name.h
+++ b/sr_unix/mupip_hash.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * Copyright 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -9,6 +9,4 @@
* *
****************************************************************/
-#define GTM_RELEASE_NAME "GT.M V6.2-000 VMS AXP"
-#define GTM_PRODUCT "GT.M"
-#define GTM_VERSION "V6.2"
+void mupip_hash(void);
diff --git a/sr_unix/mupip_rctldump.c b/sr_unix/mupip_rctldump.c
new file mode 100644
index 0000000..236b753
--- /dev/null
+++ b/sr_unix/mupip_rctldump.c
@@ -0,0 +1,60 @@
+/****************************************************************
+ * *
+ * Copyright 2014 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#ifdef AUTORELINK_SUPPORTED
+
+#include "gtm_string.h"
+
+#include "relinkctl.h"
+#include "util.h"
+#include <rtnhdr.h> /* needed for zroutines.h */
+#include "zroutines.h"
+#include "cli.h"
+#include "cliif.h"
+#include "cli_parse.h"
+#include "zshow.h"
+#endif
+#include "mupip_rctldump.h" /* for mupip_rctldump prototype */
+
+#ifdef AUTORELINK_SUPPORTED
+error_def(ERR_MUPCLIERR);
+#endif
+
+void mupip_rctldump(void)
+{
+# ifdef AUTORELINK_SUPPORTED
+ unsigned short max_len;
+ mstr dir;
+ char objdir[GTM_PATH_MAX];
+ open_relinkctl_sgm *linkctl;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ if (TREF(parms_cnt))
+ {
+ assert(1 == TREF(parms_cnt));
+ max_len = SIZEOF(objdir);
+ if (!cli_get_str("DIRECTORY", objdir, &max_len))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUPCLIERR);
+ dir.addr = objdir;
+ dir.len = max_len;
+ linkctl = relinkctl_attach(&dir);
+ assert(linkctl == TREF(open_relinkctl_list));
+ assert((NULL == linkctl) || (NULL == linkctl->next));
+ } else
+ zro_init();
+ util_out_print("", RESET); /* Reset output buffer */
+ zshow_rctldump(NULL); /* callee knows caller is mupip_rctldump type based on the NULL parameter */
+# endif /* AUTORELINK_SUPPORTED */
+}
+
diff --git a/sr_unix/do_shmat.h b/sr_unix/mupip_rctldump.h
similarity index 68%
copy from sr_unix/do_shmat.h
copy to sr_unix/mupip_rctldump.h
index c4143a7..d2de5f0 100644
--- a/sr_unix/do_shmat.h
+++ b/sr_unix/mupip_rctldump.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * Copyright 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -9,9 +9,9 @@
* *
****************************************************************/
-#ifndef __DO_SHMAT_H__
-#define __DO_SHMAT_H__
+#ifndef MUPIP_RCTLDUMP_INCLUDED
+#define MUPIP_RCTLDUMP_INCLUDED
-void *do_shmat(int4 shmid, const void *shmaddr, int4 shmflg);
+void mupip_rctldump(void);
-#endif
+#endif /* MUPIP_RCTLDUMP_INCLUDED */
diff --git a/sr_unix/mupip_rundown.c b/sr_unix/mupip_rundown.c
index d6e7769..178984b 100644
--- a/sr_unix/mupip_rundown.c
+++ b/sr_unix/mupip_rundown.c
@@ -99,7 +99,7 @@ void mupip_rundown(void)
SETUP_THREADGBL_ACCESS;
exit_status = SS_NORMAL;
file = (CLI_PRESENT == cli_present("FILE"));
- region = (CLI_PRESENT == cli_present("REGION"));
+ region = (CLI_PRESENT == cli_present("REGION")) || (CLI_PRESENT == cli_present("R"));
TREF(skip_file_corrupt_check) = TRUE; /* rundown the database even if csd->file_corrupt is TRUE */
arg_present = (0 != TREF(parms_cnt));
if ((file == region) && (TRUE == file))
diff --git a/sr_unix/mupip_trigger.c b/sr_unix/mupip_trigger.c
index 3579268..0503005 100644
--- a/sr_unix/mupip_trigger.c
+++ b/sr_unix/mupip_trigger.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2013 Fidelity Information Services, Inc *
+ * Copyright 2010, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -11,6 +11,8 @@
#include "mdef.h"
+#ifdef GTM_TRIGGER
+
#include <errno.h>
#include "gtm_stdlib.h" /* for exit() */
#include "gtm_limits.h"
@@ -20,6 +22,7 @@
#include "gdsroot.h"
#include "gdsbt.h"
#include "gdsfhead.h"
+#include "filestruct.h"
#include <rtnhdr.h>
#include "gv_trigger.h"
#include "mupip_trigger.h"
@@ -27,11 +30,21 @@
#include "trigger_select_protos.h"
#include "util.h"
#include "mupip_exit.h"
+#include "change_reg.h"
+#include "targ_alloc.h"
+#include "gvcst_protos.h"
+#include "trigger_upgrade_protos.h"
+
+GBLREF gd_addr *gd_header;
+#ifdef DEBUG
+GBLREF boolean_t is_replicator;
+#endif
+error_def(ERR_INVSTRLEN);
+error_def(ERR_MUNOACTION);
error_def(ERR_MUPCLIERR);
error_def(ERR_NOSELECT);
-error_def(ERR_MUNOACTION);
-error_def(ERR_INVSTRLEN);
+error_def(ERR_TRIGMODREGNOTRW);
void mupip_trigger(void)
{
@@ -41,8 +54,14 @@ void mupip_trigger(void)
unsigned short sf_name_len;
int local_errno;
struct stat statbuf;
- boolean_t noprompt;
+ boolean_t noprompt, trigger_error;
+ gd_region *reg, *reg_top;
+ sgmnt_addrs *csa;
+# ifdef DEBUG
+ DCL_THREADGBL_ACCESS;
+ SETUP_THREADGBL_ACCESS;
+# endif
if (CLI_PRESENT == cli_present("TRIGGERFILE"))
{
noprompt = (CLI_PRESENT == cli_present("NOPROMPT"));
@@ -82,6 +101,42 @@ void mupip_trigger(void)
util_out_print("Error opening output file: !AD -- File exists", TRUE, sf_name_len, select_file_name);
mupip_exit(ERR_MUNOACTION);
}
- (void)trigger_select(select_list, (uint4)select_list_len, select_file_name, (uint4)sf_name_len);
+ trigger_error = trigger_select_tpwrap(select_list, (uint4)select_list_len, select_file_name, (uint4)sf_name_len);
+ if (trigger_error)
+ mupip_exit(ERR_MUNOACTION);
+ }
+ if (CLI_PRESENT == cli_present("UPGRADE"))
+ { /* Invoke MUPIP TRIGGER -UPGRADE */
+ gvinit();
+ DEBUG_ONLY(TREF(in_trigger_upgrade) = TRUE;)
+ for (reg = gd_header->regions, reg_top = reg + gd_header->n_regions; reg < reg_top; reg++)
+ {
+ GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(reg);
+ csa = cs_addrs;
+ if (NULL == csa) /* not BG or MM access method */
+ continue;
+ if (!csa->hdr->hasht_upgrade_needed)
+ {
+ util_out_print("Triggers in region !AD have already been upgraded", TRUE, REG_LEN_STR(reg));
+ continue; /* ^#t already upgraded */
+ }
+ if (reg->read_only)
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(reg));
+ if (0 == gv_target->root)
+ {
+ util_out_print("No triggers found in region !AD and so no upgrade needed", TRUE, REG_LEN_STR(reg));
+ csa->hdr->hasht_upgrade_needed = FALSE; /* Reset now that we know there is no ^#t global in this db.
+ * Note: It is safe to do so even if we dont hold crit.
+ */
+ continue; /* no ^#t records exist in this region */
+ }
+ assert(!dollar_tlevel);
+ assert(!is_replicator);
+ trigger_upgrade(reg);
+ assert(!csa->hdr->hasht_upgrade_needed); /* should have been cleared inside trigger_upgrade */
+ util_out_print("Triggers in region !AD have been upgraded", TRUE, REG_LEN_STR(reg));
+ }
+ DEBUG_ONLY(TREF(in_trigger_upgrade) = FALSE;)
}
}
+#endif
diff --git a/sr_unix/mutex.c b/sr_unix/mutex.c
index 0735558..9acb9a9 100644
--- a/sr_unix/mutex.c
+++ b/sr_unix/mutex.c
@@ -54,6 +54,8 @@
#include "gt_timer.h"
#include "gtmio.h"
#include "gtm_c_stack_trace.h"
+#include "sleep.h"
+#include "anticipatory_freeze.h"
#ifdef DEBUG
#include "wbox_test_init.h"
#include "repl_msg.h" /* needed by gtmsource.h */
@@ -94,9 +96,11 @@
BG_TRACE_PRO_ANY(CSA, EVENT); \
}
-GBLREF pid_t process_id;
-GBLREF uint4 image_count;
GBLREF int num_additional_processors;
+GBLREF jnl_gbls_t jgbl;
+GBLREF jnlpool_addrs jnlpool;
+GBLREF pid_t process_id;
+GBLREF uint4 image_count, mutex_per_process_init_pid;
#ifdef MUTEX_MSEM_WAKE
GBLREF volatile uint4 heartbeat_counter;
# ifdef POSIX_MSEM
@@ -106,18 +110,14 @@ static msemaphore *mutex_wake_msem_ptr = NULL;
# endif
static mutex_que_entry_ptr_t msem_slot;
#else
-GBLREF int mutex_sock_fd;
GBLREF fd_set mutex_wait_on_descs;
+GBLREF int mutex_sock_fd;
#endif
-GBLREF uint4 mutex_per_process_init_pid;
#ifdef DEBUG
-GBLREF jnlpool_addrs jnlpool;
-GBLREF boolean_t in_mu_rndwn_file;
+GBLREF boolean_t in_mu_rndwn_file;
#endif
-GBLREF jnl_gbls_t jgbl;
DECLARE_MUTEX_TRACE_CNTRS
-
DECLARE_MUTEX_TEST_SIGNAL_FLAG
static boolean_t woke_self;
@@ -491,7 +491,7 @@ static enum cdb_sc mutex_sleep(sgmnt_addrs *csa, mutex_lock_t mutex_lock_type)
mutex_que_entry_ptr_t free_slot;
int redo_cntr;
int queue_retry_counter_remq,
- quant_retry_counter_remq,
+ quant_retry_counter_remq,
queue_retry_counter_insq,
quant_retry_counter_insq;
# ifdef MUTEX_MSEM_WAKE
@@ -590,6 +590,7 @@ static enum cdb_sc mutex_sleep(sgmnt_addrs *csa, mutex_lock_t mutex_lock_type)
* PROBE_BG_TRACE_PRO_ANY macro.
*/
PROBE_BG_TRACE_PRO_ANY(csa, mutex_queue_full);
+ csa->probecrit_rec.p_crit_que_full++;
MUTEX_DPRINT2("%d: Free Queue full\n", process_id);
/* When I can't find a free slot in the queue repeatedly, it means that there is no progress
* in the system. A recovery attempt might be warranted in this scenario. The trick is to
@@ -598,7 +599,7 @@ static enum cdb_sc mutex_sleep(sgmnt_addrs *csa, mutex_lock_t mutex_lock_type)
* done, though queueing isn't.
*/
}
- MICROSEC_SLEEP(ONE_MILLION - 1); /* Wait a second, then try again */
+ SLEEP_USEC(ONE_MILLION - 1, FALSE); /* Wait a second, then try again */
mutex_deadlock_check(addr, csa);
if (++redo_cntr < MUTEX_MAX_WAIT_FOR_PROGRESS_CNTR)
break;
@@ -718,14 +719,16 @@ void gtm_mutex_init(gd_region *reg, int n, bool crash)
}
static enum cdb_sc write_lock_spin(gd_region *reg,
- mutex_spin_parms_ptr_t mutex_spin_parms,
- int crash_count,
- int attempt_recovery,
- mutex_lock_t mutex_lock_type)
+ mutex_spin_parms_ptr_t mutex_spin_parms,
+ int crash_count,
+ int attempt_recovery,
+ mutex_lock_t mutex_lock_type,
+ gtm_uint64_t *spins,
+ gtm_uint64_t *yields)
{
int write_sleep_spin_count, write_hard_spin_count;
- sgmnt_addrs *csa;
mutex_struct_ptr_t addr;
+ sgmnt_addrs *csa;
# ifdef MUTEX_REAL_SLEEP
int micro_sleep_time;
# endif
@@ -749,6 +752,10 @@ static enum cdb_sc write_lock_spin(gd_region *reg,
MUTEX_TEST_SIGNAL_HERE("WRTLCK NOW CRIT\n", FALSE);
csa->now_crit = TRUE;
MUTEX_TEST_SIGNAL_HERE("WRTLCK SUCCESS\n", FALSE);
+ assert(write_hard_spin_count <= *spins);
+ *spins -= write_hard_spin_count; /* reduce by the number of unused */
+ assert(write_sleep_spin_count <= *yields);
+ *yields -= write_sleep_spin_count; /* reduce by the number of unused */
return (cdb_sc_normal);
} else if (attempt_recovery)
{
@@ -756,7 +763,10 @@ static enum cdb_sc write_lock_spin(gd_region *reg,
attempt_recovery = FALSE;
}
if (!write_hard_spin_count) /* save memory reference on fast path */
+ {
write_hard_spin_count = num_additional_processors ? mutex_spin_parms->mutex_hard_spin_count : 1;
+ *spins += write_hard_spin_count; /* start with max */
+ }
} while (--write_hard_spin_count);
/* Sleep for a very short duration */
# ifdef MUTEX_TRACE
@@ -769,12 +779,15 @@ static enum cdb_sc write_lock_spin(gd_region *reg,
micro_sleep_time = (nrand48(next_rand) & mutex_spin_parms->mutex_spin_sleep_mask) + 1;
assert(micro_sleep_time < ONE_MILLION);
assert(FALSE == csa->now_crit);
- MICROSEC_SLEEP(micro_sleep_time);
+ SLEEP_USEC(micro_sleep_time, FALSE);
# else
rel_quant();
# endif
if (!write_sleep_spin_count) /* save memory reference on fast path */
+ {
write_sleep_spin_count = mutex_spin_parms->mutex_sleep_spin_count;
+ *yields += write_sleep_spin_count; /* start with max */
+ }
} while (--write_sleep_spin_count);
MUTEX_DPRINT4("%d: Could not acquire WRITE %sLOCK, held by %d\n", process_id,
(MUTEX_LOCK_WRITE == mutex_lock_type) ? "" : "IMMEDIATE ", addr->semaphore.u.parts.latch_pid);
@@ -786,60 +799,101 @@ static enum cdb_sc mutex_lock(gd_region *reg,
int crash_count,
mutex_lock_t mutex_lock_type)
{
- boolean_t try_recovery;
+ boolean_t epoch_count, try_recovery;
enum cdb_sc status;
- int lock_attempts;
+ int n_queslots;
latch_t local_crit_cycle;
+ mutex_struct_ptr_t addr;
+ node_local *cnl;
pid_t in_crit_pid;
sgmnt_addrs *csa;
time_t curr_time;
uint4 curr_time_uint4, next_alert_uint4;
+ gtm_uint64_t failed_lock_attempts, queue_sleeps, spins, yields;
+ ABS_TIME atstart, atend;
csa = &FILE_INFO(reg)->s_addrs;
+ cnl = csa->nl;
/* Check that "mutex_per_process_init" has happened before we try to grab crit and that it was done with our current
* pid (i.e. ensure that even in the case where parent did the mutex init with its pid and did a fork, the child process
* has done a reinitialization with its pid). The only exception is if we are in "mu_rndwn_file" in which case we
* know for sure there is no other pid accessing the database shared memory.
*/
assert((MUTEX_LOCK_WRITE_IMMEDIATE == mutex_lock_type) || (MUTEX_LOCK_WRITE == mutex_lock_type));
- assert(mutex_per_process_init_pid == process_id || (0 == mutex_per_process_init_pid) && in_mu_rndwn_file);
+ assert((mutex_per_process_init_pid == process_id) || (0 == mutex_per_process_init_pid) && in_mu_rndwn_file);
MUTEX_TRACE_CNTR((MUTEX_LOCK_WRITE == mutex_lock_type) ? mutex_trc_lockw : mutex_trc_lockwim);
optimistic_attempts = 0;
- lock_attempts = 0;
+ queue_sleeps = spins = yields = csa->probecrit_rec.p_crit_que_full = 0;
local_crit_cycle = 0; /* this keeps us from doing a MUTEXLCKALERT on the first cycle in case the time latch is stale */
try_recovery = jgbl.onlnrlbk; /* salvage lock the first time if we are online rollback thereby reducing unnecessary waits */
+ epoch_count = cnl->doing_epoch;
+ if (csa->crit_probe)
+ { /* run the active queue to find how many slots are left */
+ addr = csa->critical;
+ csa->probecrit_rec.p_crit_que_slots = (gtm_uint64_t)addr->queslots; /* free = total number of slots */
+ csa->probecrit_rec.p_crit_que_slots -= verify_queue_lock((que_head_ptr_t)&addr->prochead); /* less used slots */
+ sys_get_curr_time(&atstart); /* start time for the probecrit */
+ }
do
{
- in_crit_pid = csa->nl->in_crit;
- lock_attempts++;
+ in_crit_pid = cnl->in_crit;
MUTEX_TRACE_CNTR(mutex_trc_w_atmpts);
- status = write_lock_spin(reg, mutex_spin_parms, crash_count, try_recovery, mutex_lock_type);
+ status = write_lock_spin(reg, mutex_spin_parms, crash_count, try_recovery, mutex_lock_type, &spins, &yields);
if ((cdb_sc_normal == status) || (MUTEX_LOCK_WRITE_IMMEDIATE == mutex_lock_type) || (cdb_sc_critreset == status))
+ {
+ failed_lock_attempts = spins + yields + queue_sleeps;
+ INCR_GVSTATS_COUNTER(csa, cnl, n_crit_success, 1);
+ if (epoch_count)
+ INCR_GVSTATS_COUNTER(csa, cnl, n_crits_in_epch, failed_lock_attempts);
+ INCR_GVSTATS_COUNTER(csa, cnl, n_crit_failed, failed_lock_attempts);
+ INCR_GVSTATS_COUNTER(csa, cnl, sq_crit_failed, failed_lock_attempts * failed_lock_attempts);
+ if (yields)
+ {
+ INCR_GVSTATS_COUNTER(csa, cnl, n_crit_yields, yields);
+ INCR_GVSTATS_COUNTER(csa, cnl, sq_crit_yields, yields * yields);
+ }
+ if (queue_sleeps)
+ {
+ INCR_GVSTATS_COUNTER(csa, cnl, n_crit_que_slps, queue_sleeps);
+ INCR_GVSTATS_COUNTER(csa, cnl, sq_crit_que_slps, queue_sleeps * queue_sleeps);
+ }
+ if (csa->crit_probe)
+ {
+ sys_get_curr_time(&atend); /* end time for the probcrit */
+ atend = sub_abs_time(&atend, &atstart); /* the times currently use usec but might someday use */
+ csa->probecrit_rec.t_get_crit = ((atend.at_sec * 1000000) + atend.at_usec) * 1000; /* nanosecs? */
+ csa->probecrit_rec.p_crit_failed = failed_lock_attempts;
+ csa->probecrit_rec.p_crit_yields = yields;
+ csa->probecrit_rec.p_crit_que_slps = queue_sleeps;
+ }
return (status);
+ }
try_recovery = FALSE; /* only try recovery once per MUTEXLCKALERT */
assert(cdb_sc_nolock == status);
time(&curr_time);
assert(MAXUINT4 > curr_time);
curr_time_uint4 = (uint4)curr_time;
next_alert_uint4 = csa->critical->stuckexec.cas_time;
- if (curr_time_uint4 > next_alert_uint4)
- { /* We've waited long enough */
+ if ((curr_time_uint4 > next_alert_uint4) && !IS_REPL_INST_FROZEN)
+ { /* We've waited long enough and the Instance is not frozen */
if (COMPSWAP_LOCK(&csa->critical->stuckexec.time_latch, next_alert_uint4, 0,
(curr_time_uint4 + MUTEXLCKALERT_INTERVAL), 0))
{ /* and no one else beat us to it */
MUTEX_DPRINT3("%d: Acquired STUCKEXEC time lock, to trace %d\n", process_id, in_crit_pid);
if (process_id == in_crit_pid)
- { /* This is just a precaution - shouldn't ever happen */
+ { /* This is just a precaution - shouldn't ever happen and has no code to maintain gvstats */
assert(FALSE);
csa->now_crit = TRUE;
return (cdb_sc_normal);
}
- if (in_crit_pid && (in_crit_pid == csa->nl->in_crit) && is_proc_alive(in_crit_pid, 0))
+ if (in_crit_pid && (in_crit_pid == cnl->in_crit) && is_proc_alive(in_crit_pid, 0))
{ /* and we're waiting on some living process */
if (local_crit_cycle == csa->critical->crit_cycle)
{ /* and things aren't moving */
assert(local_crit_cycle);
- if (0 == csa->nl->onln_rlbk_pid)
+ if (IS_REPL_INST_FROZEN) /* recheck to minimize spurious reports */
+ continue;
+ if (0 == cnl->onln_rlbk_pid)
{ /* not rollback - send_msg after trace less likely to lose process */
GET_C_STACK_FROM_SCRIPT("MUTEXLCKALERT", process_id, in_crit_pid,
csa->critical->crit_cycle);
@@ -852,8 +906,8 @@ static enum cdb_sc mutex_lock(gd_region *reg,
* journal pool for its entire duration, use a different message
*/
send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_ORLBKINPROG, 3,
- csa->nl->onln_rlbk_pid, DB_LEN_STR(reg));
- assert(csa->nl->in_crit == csa->nl->onln_rlbk_pid);
+ cnl->onln_rlbk_pid, DB_LEN_STR(reg));
+ assert(cnl->in_crit == cnl->onln_rlbk_pid);
}
} else
{ /* nobody home */
@@ -868,6 +922,7 @@ static enum cdb_sc mutex_lock(gd_region *reg,
}
if (0 == local_crit_cycle)
local_crit_cycle = csa->critical->crit_cycle; /* sync first time waiter */
+ queue_sleeps++;
if (cdb_sc_dbccerr == mutex_sleep(csa, mutex_lock_type))
return (cdb_sc_dbccerr);
} while (TRUE);
diff --git a/sr_unix/mutexsp.h b/sr_unix/mutexsp.h
index 7e3dbe8..7d2e111 100644
--- a/sr_unix/mutexsp.h
+++ b/sr_unix/mutexsp.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -43,8 +43,6 @@
#define ONE_MILLION 1000000
-#define MICROSEC_SLEEP(x) m_usleep(x)
-
typedef struct
{
uint4 pid;
diff --git a/sr_unix/obj_code.c b/sr_unix/obj_code.c
index 935386b..75b05fb 100644
--- a/sr_unix/obj_code.c
+++ b/sr_unix/obj_code.c
@@ -37,6 +37,9 @@
#include "stringpool.h"
#include "min_max.h"
#include "rtn_src_chksum.h"
+#include "mmrhash.h"
+#include "arlinkdbg.h"
+#include "incr_link.h"
GBLDEF uint4 lits_text_size, lits_mval_size;
@@ -61,7 +64,9 @@ GBLREF int4 sym_table_size;
GBLREF int4 linkage_size;
GBLREF uint4 lnkrel_cnt; /* number of entries in linkage Psect to relocate */
GBLREF spdesc stringpool;
+GBLREF short object_name_len;
GBLREF char object_file_name[];
+GBLREF int object_file_des;
#define PTEXT_OFFSET SIZEOF(rhdtyp)
@@ -79,8 +84,10 @@ GBLREF char object_file_name[];
* | code | \ \
* + - - - - - - - + | |
* | line num tbl | |- R/O releasable |
- * + - - - - - - - + / |- R/O releasable
- * | lit text pool | / |
+ * + - - - - - - - + | |- R/O releasable
+ * | lit text pool | | |
+ * +---------------+ / |
+ * | lkg name tbl | / |
* +---------------+ /
* | lit mval tbl | \ /
* +---------------+ |- R/W releasable
@@ -94,25 +101,30 @@ GBLREF char object_file_name[];
* +---------------+
*
* Note in addition to the above layout, a "linkage section" is allocated at run time and is
- * also releasable.
+ * also releasable. The linkage table and the linkage name table are co-indexed and provide the
+ * routine or label names for the given entry. The linkage name table consists of unrelocated mstrs
+ * as they are only ever used once so need not be resolved.
*
* If GTM_DYNAMIC_LITERALS is enabled, the literal mval table becomes part of the R/O-release section.
* In the case of shared libraries, this spares each process from having to take a malloced copy the lit mval table
* at link time (sr_unix/incr_link.c). This memory saving optimization is only available on USHBIN-supported platforms
*/
+error_def(ERR_OBJFILERR);
+error_def(ERR_SYSCALL);
error_def(ERR_TEXT);
-void cg_lab (mlabel *mlbl, char *do_emit);
+STATICFNDCL void cg_lab (mlabel *mlbl, char *do_emit);
void obj_code (uint4 src_lines, void *checksum_ctx)
{
- int i;
- uint4 lits_pad_size, object_pad_size, lnr_pad_size;
+ int i, status;
+ uint4 lits_pad_size, object_pad_size, lnr_pad_size, lnkname_pad_size;
int4 offset;
int4 old_code_size;
rhdtyp rhead;
mline *mlx, *mly;
+ gtm_uint16 objhash;
var_tabent *vptr;
DCL_THREADGBL_ACCESS;
@@ -137,8 +149,8 @@ void obj_code (uint4 src_lines, void *checksum_ctx)
curr_addr = PTEXT_OFFSET;
cg_phase = CGP_APPROX_ADDR;
cg_phase_last = CGP_NOSTATE;
- IA64_ONLY(calculated_code_size = 0;)
- IA64_DEBUG_ONLY(calculated_count = 0;)
+ IA64_ONLY(calculated_code_size = 0);
+ IA64_DEBUG_ONLY(calculated_count = 0);
code_gen();
code_size = curr_addr;
cg_phase = CGP_ADDR_OPT;
@@ -158,7 +170,7 @@ void obj_code (uint4 src_lines, void *checksum_ctx)
if (!(cmd_qlf.qlf & CQ_OBJECT))
return;
/* Executable code offset setup */
- IA64_ONLY(assert(!(PTEXT_OFFSET % SECTION_ALIGN_BOUNDARY));)
+ IA64_ONLY(assert(!(PTEXT_OFFSET % SECTION_ALIGN_BOUNDARY)));
rhead.ptext_adr = (unsigned char *)PTEXT_OFFSET;
rhead.ptext_end_adr = (unsigned char *)(size_t)code_size;
/* Line number table offset setup */
@@ -172,6 +184,11 @@ void obj_code (uint4 src_lines, void *checksum_ctx)
rhead.literal_text_len = lits_text_size;
code_size += lits_text_size;
assert(0 == PADLEN(code_size, NATIVE_WSIZE));
+ /* Literal extern (linkage) names section (same # of entries as linkage table) */
+ rhead.linkage_names = (mstr *)(size_t)code_size;
+ code_size += ((linkage_size / SIZEOF(lnk_tabent)) * SIZEOF(mstr));
+ lnkname_pad_size = PADLEN(code_size, NATIVE_WSIZE);
+ code_size += lnkname_pad_size;
/* Literal mval section offset setup */
rhead.literal_adr = (mval *)(size_t)code_size;
rhead.literal_len = lits_mval_size / SIZEOF(mval);
@@ -207,6 +224,7 @@ void obj_code (uint4 src_lines, void *checksum_ctx)
object_pad_size = PADLEN(code_size, OBJECT_SIZE_ALIGNMENT);
code_size += object_pad_size;
gtm_object_size = code_size;
+ rhead.object_len = gtm_object_size;
set_rtnhdr_checksum(&rhead, (gtm_rtn_src_chksum_ctx *)checksum_ctx);
rhead.objlabel = MAGIC_COOKIE;
rhead.temp_mvals = sa_temps[TVAL_REF];
@@ -214,11 +232,16 @@ void obj_code (uint4 src_lines, void *checksum_ctx)
rhead.compiler_qlf = cmd_qlf.qlf;
if (cmd_qlf.qlf & CQ_EMBED_SOURCE)
rhead.routine_source_offset = TREF(routine_source_offset);
- /* Start the creation of the output object */
+ /* Start the creation of the output object. On Linux, Solaris, and HPUX, we use ELF routines to push out native object
+ * code wrapper so the wrapper is not part of the object code hash. However, on AIX, the native XCOFF wrapper is pushed
+ * out by our own routines so is part of the hash. Note for AIX, the create_object_file() routine will duplicate the
+ * hash initialization macro below after the native header is written out but before the GT.M object header is written.
+ */
+ HASH128_STATE_INIT(TREF(objhash_state), 0);
create_object_file(&rhead);
cg_phase = CGP_MACHINE;
- IA64_ONLY(generated_code_size = 0;)
- IA64_DEBUG_ONLY(generated_count = 0;)
+ IA64_ONLY(generated_code_size = 0);
+ IA64_DEBUG_ONLY(generated_count = 0);
code_gen();
IA64_DEBUG_ONLY(
if (calculated_code_size != generated_code_size)
@@ -285,27 +308,35 @@ void obj_code (uint4 src_lines, void *checksum_ctx)
/* The label table */
if (mlabtab)
walktree((mvar *)mlabtab, cg_lab, (char *)TRUE);
- /* Resolve locally defined symbols */
- resolve_sym();
- /* Output relocation entries for the linkage section */
- output_relocation();
- /* Output the symbol table text pool */
- output_symbol();
+ resolve_sym(); /* Associate relocation entries for the same symbol/linkage-table slot together */
+ output_relocation(); /* Output relocation entries for the linkage section */
+ output_symbol(); /* Output the symbol table text pool */
/* If there is padding we need to do to fill out the object to the required boundary do it.. */
if (object_pad_size)
{
assert(STR_LIT_LEN(PADCHARS) >= object_pad_size);
emit_immed(PADCHARS, object_pad_size);
}
- close_object_file();
+ finish_object_file(); /* Flushes object file buffers and writes remaining native object structures */
+ /* Get our 128 bit hash though only the first 8 bytes of it get saved in the routine header */
+ gtmmrhash_128_result(TADR(objhash_state), gtm_object_size, &objhash);
+ DBGARLNK((stderr, "obj_code: Computed hash value of 0x"lvaddr" for file %.*s\n", objhash.one, object_name_len,
+ object_file_name));
+ if ((off_t)-1 == lseek(object_file_des, (off_t)(NATIVE_HDR_LEN + OFFSETOF(rhdtyp, objhash)), SEEK_SET))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_OBJFILERR, 2, object_name_len, object_file_name, errno);
+ emit_immed((char *)&objhash.one, SIZEOF(gtm_uint64_t)); /* Update 8 bytes of objhash in the file header */
+ buff_flush(); /* Push it out */
+ CLOSE_OBJECT_FILE(object_file_des, status);
+ if (-1 == status)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("close()"), CALLFROM, errno);
/* Ready to make object visible. Rename from tmp name to real routine name */
- rename_tmp_object_file(object_file_name);
+ RENAME_TMP_OBJECT_FILE(object_file_name);
}
/* Routine called to process a given label. Cheezy 2nd parm is due to general purpose
* mechanism of the walktree routine that calls us.
*/
-void cg_lab(mlabel *mlbl, char *do_emit)
+STATICFNDEF void cg_lab(mlabel *mlbl, char *do_emit)
{
lab_tabent lent;
mstr glob_name;
@@ -315,11 +346,13 @@ void cg_lab(mlabel *mlbl, char *do_emit)
if (do_emit)
{ /* Output (2nd) pass, emit the interesting information */
lent.lab_name.len = mlbl->mvname.len;
- lent.lab_name.addr = (char *)(mlbl->mvname.addr - (char *)stringpool.base);
- /* Offset into literal text pool */
+ lent.lab_name.addr = (0 < lent.lab_name.len) /* Offset into literal text pool */
+ ? (char *)(mlbl->mvname.addr - (char *)stringpool.base) : NULL;
lent.LABENT_LNR_OFFSET = (lnr_tabent *)(SIZEOF(lnr_tabent) * mlbl->ml->line_number);
/* Offset into lnr table */
lent.has_parms = (NO_FORMALLIST != mlbl->formalcnt); /* Flag to indicate any formallist */
+ GTM64_ONLY(lent.filler = 0); /* Remove garbage due so hashes well */
+ UNICODE_ONLY(lent.lab_name.char_len = 0); /* .. ditto .. */
emit_immed((char *)&lent, SIZEOF(lent));
} else
{ /* 1st pass, do the definition but no emissions */
diff --git a/sr_unix/obj_file.c b/sr_unix/obj_file.c
index eaa3b6c..a61710d 100644
--- a/sr_unix/obj_file.c
+++ b/sr_unix/obj_file.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -28,6 +28,7 @@
#include "gtmio.h"
#include "mmemory.h"
#include "obj_file.h"
+#include "mmrhash.h"
GBLREF char object_file_name[];
GBLREF short object_name_len;
@@ -51,32 +52,35 @@ static char emit_buff[OBJ_EMIT_BUF_SIZE]; /* buffer for emit output */
static int emit_buff_used; /* number of chars in emit_buff */
static int symcnt;
static struct rel_table *link_rel, *link_rel_end; /* Linkage relocation entries. */
-static struct linkage_entry *linkage_first, *linkage_last;
-static struct sym_table *symbols;
-void emit_link_reference(int4 refoffset, mstr *name);
+static int tmpcnt;
-void drop_object_file(void)
+error_def(ERR_OBJFILERR);
+error_def(ERR_STRINGOFLOW);
+
+STATICFNDCL void emit_link_reference(int4 refoffset, mstr *name);
+
+/* Routine to clear/delete the existing object file (used to delete existing temporary object file name
+ * on an error.
+ */
+void drop_object_file(void)
{
int rc;
if (0 < object_file_des)
{
UNLINK(object_file_name);
- CLOSEFILE_RESET(object_file_des, rc); /* resets "object_file_des" to FD_INVALID */
+ CLOSE_OBJECT_FILE(object_file_des, rc); /* Resets "object_file_des" to FD_INVALID */
}
}
-error_def(ERR_OBJFILERR);
-error_def(ERR_STRINGOFLOW);
-
/*
* emit_link_reference
*
* Description: If not already defined, create relocation entry for
* a linkage table entry to be resolved later.
*/
-void emit_link_reference(int4 refoffset, mstr *name)
+STATICFNDEF void emit_link_reference(int4 refoffset, mstr *name)
{
struct sym_table *sym;
struct rel_table *newrel;
@@ -86,7 +90,7 @@ void emit_link_reference(int4 refoffset, mstr *name)
if ((N_TEXT | N_EXT) != sym->n.n_type)
{
newrel = (struct rel_table *)mcalloc(SIZEOF(struct rel_table));
- newrel->next = (struct rel_table *)0;
+ newrel->next = NULL;
newrel->resolve = 0;
newrel->r.r_address = refoffset;
newrel->r.r_symbolnum = 0;
@@ -101,16 +105,17 @@ void emit_link_reference(int4 refoffset, mstr *name)
}
}
-
/*
* emit_immed
*
* Args: buffer of executable code, and byte count to be output.
*/
-void emit_immed(char *source, uint4 size)
+void emit_immed(char *source, uint4 size)
{
- short int write;
+ int4 write;
+ if (0 == size)
+ return; /* Not sure why but this does happen */
if (run_time)
{
if (!IS_STP_SPACE_AVAILABLE_PRO(size))
@@ -120,7 +125,7 @@ void emit_immed(char *source, uint4 size)
} else
{
DEBUG_ONLY(obj_bytes_written += size);
- while (size > 0)
+ while (0 < size)
{
write = SIZEOF(emit_buff) - emit_buff_used;
write = size < write ? size : write;
@@ -134,16 +139,20 @@ void emit_immed(char *source, uint4 size)
}
}
-
/*
* buff_emit
*
* Output partially or completely filled buffer
*/
-void buff_emit(void)
+void buff_emit(void)
{
int stat;
+ DCL_THREADGBL_ACCESS;
+ SETUP_THREADGBL_ACCESS;
+ /* Accumulate object code piece in the object hash with progressive murmurhash call */
+ tmpcnt++;
+ gtmmrhash_128_ingest(TADR(objhash_state), emit_buff, emit_buff_used);
DOWRITERC(object_file_des, emit_buff, emit_buff_used, stat);
if (0 != stat)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_OBJFILERR, 2, object_name_len, object_file_name, stat);
@@ -155,7 +164,7 @@ void buff_emit(void)
*
* Flush the contents of emit_buff to the file.
*/
-void buff_flush(void)
+void buff_flush(void)
{
if (emit_buff_used)
buff_emit();
@@ -176,13 +185,15 @@ struct sym_table *define_symbol(unsigned char psect, mstr *name)
struct sym_table *sym, *sym1, *newsym;
stringkey symkey;
ht_ent_str *syment;
+ DCL_THREADGBL_ACCESS;
+ SETUP_THREADGBL_ACCESS;
usehtab = (SYM_HASH_CUTOVER < symcnt);
DEBUG_ONLY(syment = NULL);
if (!usehtab)
- { /* "Brute force" version of lookup for now */
+ { /* "Brute force" version of lookup for now (until SYM_HASH_CUTOVER symbols defined) */
assert(NULL == compsyms_hashtab || NULL == compsyms_hashtab->base);
- sym = symbols;
+ sym = TREF(defined_symbols);
sym1 = NULL;
while (sym)
{ /* Consider this a match only if type is N_EXT. If we are inserting an external reference symbol
@@ -190,7 +201,7 @@ struct sym_table *define_symbol(unsigned char psect, mstr *name)
* (N_EXT) entry so that the symbol table is correctly formed.
*/
if ((0 >= (cmp = memvcmp(name->addr, (int)name->len, &sym->name[0], sym->name_len - 1)))
- && (N_EXT == sym->n.n_type))
+ && (N_EXT == sym->n.n_type))
break;
sym1 = sym;
sym = sym->next;
@@ -198,11 +209,7 @@ struct sym_table *define_symbol(unsigned char psect, mstr *name)
if (!cmp && sym)
return sym;
} else
- { /* Hashtable lookup -- Note use of hashtab_mname for this is somewhat overloading the usage since there
- are compound symbols of the form "routine"."label" which can exceed the typical size of an mname but
- since mnames are just addr/length pairs at the definition level, this works for us and is easier than
- defining a new hashtable type identical to the mname hash in all but name.
- */
+ { /* Hashtable lookup */
if (!compsyms_hashtab)
{ /* Allocate if not allocated yet */
compsyms_hashtab = (hash_table_str *)malloc(SIZEOF(hash_table_str));
@@ -212,7 +219,7 @@ struct sym_table *define_symbol(unsigned char psect, mstr *name)
{ /* Need to initialize hash table and load it with the elements so far */
init_hashtab_str(compsyms_hashtab, SYM_HASH_CUTOVER * 2, HASHTAB_NO_COMPACT, HASHTAB_NO_SPARE_TABLE);
assert(compsyms_hashtab->base);
- for (sym = symbols; sym; sym = sym->next)
+ for (sym = TREF(defined_symbols); sym; sym = sym->next)
{
if (N_EXT != sym->n.n_type) /* Consider this a match only if type is N_EXT. See comment above */
continue;
@@ -236,7 +243,6 @@ struct sym_table *define_symbol(unsigned char psect, mstr *name)
return sym;
}
}
-
/* Didn't find it in existing symbols; create new symbol. */
newsym = (struct sym_table *)mcalloc(SIZEOF(struct sym_table) + name->len);
newsym->name_len = name->len + 1;
@@ -244,22 +250,22 @@ struct sym_table *define_symbol(unsigned char psect, mstr *name)
newsym->name[name->len] = 0;
newsym->n.n_type = N_EXT;
if (GTM_CODE == psect)
- newsym->n.n_type |= N_TEXT; /* if symbol is in GTM_CODE, it is defined */
+ newsym->n.n_type |= N_TEXT; /* If symbol is in GTM_CODE, it is defined */
else
- lnkrel_cnt++; /* otherwise it's external (only one reference in linkage Psect) */
+ lnkrel_cnt++; /* Otherwise it's external (only one reference in linkage Psect) */
newsym->resolve = 0;
- newsym->linkage_offset = -1; /* don't assign linkage Psect offset unless it's used */
+ newsym->linkage_offset = -1; /* Don't assign linkage Psect offset unless it's used */
if (!usehtab)
{ /* Brute force -- add into the queue where the test failed (keeping sorted) */
newsym->next = sym;
if (sym1)
sym1->next = newsym;
else
- symbols = newsym;
+ TREF(defined_symbols) = newsym;
} else
{ /* Hashtab usage -- add at beginning .. easiest since sorting doesn't matter for future lookups */
- newsym->next = symbols;
- symbols = newsym;
+ newsym->next = TREF(defined_symbols);
+ TREF(defined_symbols) = newsym;
assert(syment);
syment->value = newsym;
}
@@ -268,23 +274,26 @@ struct sym_table *define_symbol(unsigned char psect, mstr *name)
return newsym;
}
-
-void resolve_sym (void)
+/* Routine to resolve all the symbols of a given name to the same symbol number to associate relocation table
+ * entries together properly so all references for a given name associate to the same linkage table entry.
+ */
+void resolve_sym (void)
{
uint4 symnum;
struct sym_table *sym;
struct rel_table *rel;
+ DCL_THREADGBL_ACCESS;
- for (sym = symbols, symnum = 0; sym; sym = sym->next, symnum++)
+ SETUP_THREADGBL_ACCESS;
+ for (sym = TREF(defined_symbols), symnum = 0; sym; sym = sym->next, symnum++)
{
for (rel = sym->resolve; rel; rel = rel->resolve)
rel->r.r_symbolnum = symnum;
}
}
-
/* Output the relocation table for the linkage section */
-void output_relocation (void)
+void output_relocation (void)
{
struct rel_table *rel;
@@ -292,16 +301,17 @@ void output_relocation (void)
emit_immed((char *)&rel->r, SIZEOF(rel->r));
}
-
#ifdef DEBUG
/* Size that output_symbol() below will eventually generate -- used to verify validity of OUTPUT_SYMBOL_SIZE macro */
-int output_symbol_size(void)
+int output_symbol_size(void)
{
uint4 string_length;
struct sym_table *sym;
+ DCL_THREADGBL_ACCESS;
+ SETUP_THREADGBL_ACCESS;
string_length = SIZEOF(int4);
- sym = symbols;
+ sym = TREF(defined_symbols);
while (sym)
{
string_length += sym->name_len;
@@ -311,19 +321,20 @@ int output_symbol_size(void)
}
#endif
-
/* Symbol string table output. Consists of a series of null terminated
- strings in symbol number order.
-*/
-void output_symbol(void)
+ * strings in symbol number order.
+ */
+void output_symbol(void)
{
uint4 string_length;
struct sym_table *sym;
+ DCL_THREADGBL_ACCESS;
+ SETUP_THREADGBL_ACCESS;
string_length = SIZEOF(int4) + sym_table_size;
assert(string_length == output_symbol_size());
emit_immed((char *)&string_length, SIZEOF(string_length));
- sym = symbols;
+ sym = TREF(defined_symbols);
while (sym)
{
emit_immed((char *)&sym->name[0], sym->name_len);
@@ -331,40 +342,43 @@ void output_symbol(void)
}
}
-
/*
* obj_init
*
* Description: Initialize symbol list, relocation information, linkage Psect list, linkage_size.
*/
-void obj_init(void)
+void obj_init(void)
{
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
lnkrel_cnt = symcnt = 0;
link_rel = link_rel_end = NULL;
- symbols = NULL;
+ TREF(defined_symbols) = NULL;
+ TREF(linkage_first) = NULL;
+ TREF(linkage_last) = NULL;
sym_table_size = 0;
-
- linkage_first = linkage_last = NULL;
- linkage_size = MIN_LINK_PSECT_SIZE; /* minimum size of linkage Psect, assuming no references from generated code */
-
+ linkage_size = MIN_LINK_PSECT_SIZE; /* Minimum size of linkage Psect, assuming no references from generated code */
+ tmpcnt = 0;
return;
}
-
/*
* comp_linkages
*
* Description: Define the symbols and relocation entries we will need to create
* the linkage section when this module is linked in.
*/
-void comp_linkages(void)
+void comp_linkages(void)
{
mstr name;
struct linkage_entry *linkagep;
+ DCL_THREADGBL_ACCESS;
- for (linkagep = linkage_first; NULL != linkagep; linkagep = linkagep->next)
+ SETUP_THREADGBL_ACCESS;
+ for (linkagep = TREF(linkage_first); NULL != linkagep; linkagep = linkagep->next)
{
- name.len = linkagep->symbol->name_len - 1; /* don't count '\0' terminator */
+ name.len = linkagep->symbol->name_len - 1; /* Don't count '\0' terminator */
name.addr = (char *)&linkagep->symbol->name[0];
emit_link_reference(linkagep->symbol->linkage_offset, &name);
}
@@ -372,16 +386,19 @@ void comp_linkages(void)
return;
}
-
-void emit_literals(void)
+void emit_literals(void)
{
- uint4 offset, padsize;
- mliteral *p;
+ mstr name;
+ uint4 offset, padsize;
+ mliteral *p;
+ struct linkage_entry *linkagep;
+ DCL_THREADGBL_ACCESS;
+ SETUP_THREADGBL_ACCESS;
/* emit the literal text pool which includes the source file path and routine name */
offset = (uint4)(stringpool.free - stringpool.base);
emit_immed((char *)stringpool.base, offset);
- padsize = (uint4)(PADLEN(offset, NATIVE_WSIZE)); /* comp_lits aligns the start of source path on NATIVE_WSIZE boundary.*/
+ padsize = (uint4)(PADLEN(offset, NATIVE_WSIZE)); /* comp_lits() aligns literal area on NATIVE_WSIZE boundary */
if (padsize)
{
emit_immed(PADCHARS, padsize);
@@ -389,7 +406,7 @@ void emit_literals(void)
}
emit_immed(source_file_name, source_name_len);
offset += source_name_len;
- padsize = (uint4)(PADLEN(offset, NATIVE_WSIZE)); /* comp_lits aligns the start of routine_name on NATIVE_WSIZE boundary.*/
+ padsize = (uint4)(PADLEN(offset, NATIVE_WSIZE)); /* comp_lits() aligns routine_name on NATIVE_WSIZE boundary */
if (padsize)
{
emit_immed(PADCHARS, padsize);
@@ -397,15 +414,43 @@ void emit_literals(void)
}
emit_immed(routine_name.addr, routine_name.len);
offset += routine_name.len;
- padsize = (uint4)(PADLEN(offset, NATIVE_WSIZE)); /* comp_lits aligns the start of literal area on NATIVE_WSIZE boundary.*/
+ padsize = (uint4)(PADLEN(offset, NATIVE_WSIZE)); /* comp_lits() aligns extern symbols on NATIVE_WSIZE boundary */
if (padsize)
{
emit_immed(PADCHARS, padsize);
offset += padsize;
}
+ /* Emit the names associated with the linkage table */
+ for (linkagep = TREF(linkage_first); NULL != linkagep; linkagep = linkagep->next)
+ {
+ emit_immed((char *)linkagep->symbol->name, linkagep->symbol->name_len - 1);
+ offset += linkagep->symbol->name_len - 1;
+ padsize = (uint4)(PADLEN(offset, NATIVE_WSIZE)); /* comp_lits() aligns extern symbols on NATIVE_WSIZE boundary */
+ if (padsize)
+ {
+ emit_immed(PADCHARS, padsize);
+ offset += padsize;
+ }
+ }
assert(offset == lits_text_size);
-
- /* emit the literal mval list */
+ /* Emit the linkage name mstr table (never relocated - always offset/length pair). Same index as linkage table */
+ offset = 0;
+ for (linkagep = TREF(linkage_first); NULL != linkagep; linkagep = linkagep->next)
+ {
+ name.char_len = 0; /* No need for this length */
+ name.len = linkagep->symbol->name_len - 1; /* Don't count '\0' terminator */
+ name.addr = (char *)linkagep->lit_offset;
+ emit_immed((char *)&name, SIZEOF(mstr));
+ offset += SIZEOF(mstr);
+ }
+ padsize = (uint4)(PADLEN(offset, NATIVE_WSIZE));
+ if (padsize)
+ {
+ emit_immed(PADCHARS, padsize);
+ offset += padsize;
+ }
+ assert(0 == (uint4)(PADLEN(offset, NATIVE_WSIZE)));
+ /* Emit the literal mval list (also aligned by comp_lits() on NATIVE_WSIZE boundary */
offset = 0;
dqloop(&literal_chain, que, p)
{
@@ -416,13 +461,15 @@ void emit_literals(void)
else
p->v.str.addr = NULL;
p->v.fnpc_indx = (unsigned char)-1;
+ if (!(MV_UTF_LEN & p->v.mvtype))
+ p->v.str.char_len = 0;
+ assert(MAX_STRLEN >= p->v.str.char_len);
emit_immed((char *)&p->v, SIZEOF(p->v));
offset += SIZEOF(p->v);
}
assert (offset == lits_mval_size);
}
-
/*
* find_linkage
*
@@ -430,13 +477,14 @@ void emit_literals(void)
*
* Description: Returns the offset into the linkage Psect of a global symbol.
*/
-int4 find_linkage(mstr* name)
+int4 find_linkage(mstr* name)
{
struct linkage_entry *newlnk;
struct sym_table *sym;
+ DCL_THREADGBL_ACCESS;
+ SETUP_THREADGBL_ACCESS;
sym = define_symbol(GTM_LITERALS, name);
-
if (-1 == sym->linkage_offset)
{
/* Add new linkage psect entry at end of list. */
@@ -445,18 +493,17 @@ int4 find_linkage(mstr* name)
newlnk = (struct linkage_entry *)mcalloc(SIZEOF(struct linkage_entry));
newlnk->symbol = sym;
newlnk->next = NULL;
- if (NULL == linkage_first)
- linkage_first = newlnk;
- if (NULL != linkage_last)
- linkage_last->next = newlnk;
- linkage_last = newlnk;
+ if (NULL == TREF(linkage_first))
+ TREF(linkage_first) = newlnk;
+ if (NULL != TREF(linkage_last))
+ (TREF(linkage_last))->next = newlnk;
+ TREF(linkage_last) = newlnk;
linkage_size += SIZEOF(lnk_tabent);
}
return sym->linkage_offset;
}
-
/*
* literal_offset
*
diff --git a/sr_unix/obj_filesp.h b/sr_unix/obj_filesp.h
index 02890a9..9f8a96e 100644
--- a/sr_unix/obj_filesp.h
+++ b/sr_unix/obj_filesp.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -16,6 +16,7 @@ typedef struct linkage_entry
{
struct linkage_entry *next;
struct sym_table *symbol;
+ size_t lit_offset; /* Offset into literal string pool where string name was stored */
} linkage_entry;
struct sym_table *define_symbol(unsigned char psect, mstr *name);
diff --git a/sr_unix/obj_fileu.c b/sr_unix/obj_fileu.c
new file mode 100644
index 0000000..6037967
--- /dev/null
+++ b/sr_unix/obj_fileu.c
@@ -0,0 +1,147 @@
+/****************************************************************
+ * *
+ * Copyright 2013, 2014 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <sys/types.h>
+#include "gtm_stat.h"
+#include "gtm_stdlib.h"
+#include "gtm_string.h"
+#include "gtm_limits.h"
+
+#include "cmd_qlf.h"
+#include "gtmio.h"
+#include "parse_file.h"
+#include <rtnhdr.h>
+#include "obj_file.h"
+
+GBLREF command_qualifier cmd_qlf;
+GBLREF char object_file_name[];
+GBLREF short object_name_len;
+GBLREF mident module_name;
+
+#define MKSTEMP_MASK "XXXXXX"
+#define MAX_MKSTEMP_RETRIES 100
+
+error_def(ERR_FILEPARSE);
+error_def(ERR_OBJFILERR);
+error_def(ERR_SYSCALL);
+error_def(ERR_TEXT);
+
+/********************************************************************************************************************************
+ *
+ * While these routines might rightly belong in obj_file.c, since these routines are needed both in sr_unix and in sr_unix_nsb,
+ * it was decided to create this module to share routines that are the same across both unix and linux-i386 so the routines only
+ * need to exist in one place.
+ *
+ ********************************************************************************************************************************/
+
+/* Routine to create a temporary object file. This file is created in the directory it is supposed to reside in but is created
+ * with a temporary name. When complete, it is renamed to what it was meant to be replacing the previous version.
+ *
+ * Parameters:
+ *
+ * object_fname - Character array of the object path/name.
+ * object_fname_len - Length of that array in bytes.
+ *
+ * Return value:
+ * File descriptor for the open object file.
+ */
+int mk_tmp_object_file(const char *object_fname, int object_fname_len)
+{
+ int fdesc, status, umask_creat, umask_orig, retry;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ /* Make sure room in buffer for addition of unique-ifying MKSTEMP_MASK on end of file name */
+ if ((object_fname_len + SIZEOF(MKSTEMP_MASK) - 1) > TLEN(tmp_object_file_name))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_OBJFILERR, 2, object_fname_len, object_fname, ERR_TEXT,
+ 2, RTS_ERROR_TEXT("Object file name exceeds buffer size"));
+ /* The mkstemp() routine is known to bogus-fail for no apparent reason at all especially on AIX 6.1. In the event
+ * this shortcoming plagues other platforms as well, we add a low-cost retry wrapper.
+ */
+ retry = MAX_MKSTEMP_RETRIES;
+ do
+ {
+ memcpy(TADR(tmp_object_file_name), object_fname, object_fname_len);
+ /* Note memcpy() below purposely includes null terminator */
+ memcpy(TADR(tmp_object_file_name) + object_fname_len, MKSTEMP_MASK, SIZEOF(MKSTEMP_MASK));
+ fdesc = mkstemp(TADR(tmp_object_file_name));
+ } while ((-1 == fdesc) && (EEXIST == errno) && (0 < --retry));
+ if (FD_INVALID == fdesc)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_OBJFILERR, 2, object_fname_len, object_fname, errno);
+ umask_orig = umask(000); /* Determine umask (destructive) */
+ (void)umask(umask_orig); /* Reset umask */
+ umask_creat = 0666 & ~umask_orig;
+ /* Change protections to be those generated by previous versions. In some future version, the permissions may
+ * become tied to the permissions of the source but this works for now.
+ */
+ status = FCHMOD(fdesc, umask_creat);
+ if (-1 == status)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fchmod()"), CALLFROM, errno);
+ return fdesc;
+}
+
+/* Routine to rename the most recent temporary object file (name stored in threadgbl tmp_object_file_name) to the name
+ * passed in via parameter.
+ *
+ * Parameters:
+ * object_fname - non-temporary name of object file
+ *
+ * Global input:
+ * tmp_object_file_name - private/unique file created by mkstemp() in routine above.
+ */
+void rename_tmp_object_file(const char *object_fname)
+{
+ int status;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ status = rename(TADR(tmp_object_file_name), object_fname);
+ if (-1 == status)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("rename()"), CALLFROM, errno);
+}
+
+/* Routine to determine and initialize the fully qualified object name and path.
+ *
+ * Parameters:
+ * - none
+ *
+ * Global inputs:
+ * cmd_qlf.object_file - value from -object= option
+ * module_name - routine name
+ * Global outputs:
+ * object_file_name - full path of object file
+ * object_name_len - length of full path (not including null terminator)
+ */
+void init_object_file_name(void)
+{
+ int status, rout_len;
+ char obj_name[SIZEOF(mident_fixed) + 5];
+ mstr fstr;
+ parse_blk pblk;
+
+ memset(&pblk, 0, SIZEOF(pblk));
+ pblk.buffer = object_file_name;
+ pblk.buff_size = MAX_FBUFF;
+ fstr.len = (MV_DEFINED(&cmd_qlf.object_file) ? cmd_qlf.object_file.str.len : 0);
+ fstr.addr = cmd_qlf.object_file.str.addr;
+ rout_len = (int)module_name.len;
+ memcpy(&obj_name[0], module_name.addr, rout_len);
+ memcpy(&obj_name[rout_len], DOTOBJ, SIZEOF(DOTOBJ)); /* Includes null terminator */
+ pblk.def1_size = rout_len + SIZEOF(DOTOBJ) - 1; /* Length does not include null terminator */
+ pblk.def1_buf = obj_name;
+ status = parse_file(&fstr, &pblk);
+ if (0 == (status & 1))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_FILEPARSE, 2, fstr.len, fstr.addr, status);
+ object_name_len = pblk.b_esl;
+ object_file_name[object_name_len] = '\0';
+}
diff --git a/sr_unix/ojchildioclean.c b/sr_unix/ojchildioclean.c
index 24a28f3..b85fce7 100644
--- a/sr_unix/ojchildioclean.c
+++ b/sr_unix/ojchildioclean.c
@@ -30,7 +30,6 @@
#endif
#include <rtnhdr.h>
#include "relinkctl.h"
-#include "zhist.h"
GBLREF int mutex_sock_fd;
@@ -77,7 +76,7 @@ void ojchildioclean(void)
#endif
/* Since we are removing artifacts from the originating process (which still has these files open), there is
* no need to decrement the counts (they will increase if this process links the same files). The FALSE
- * argument prevents the count from being modified in this cleanup.
+ * argument prevents the relinkctl-attach & rtnobj-reference counts from being modified in this cleanup.
*/
- USHBIN_ONLY(relinkctl_rundown(FALSE));
+ ARLINK_ONLY(relinkctl_rundown(FALSE, FALSE));
}
diff --git a/sr_unix/ojchildparms.c b/sr_unix/ojchildparms.c
index a99afb0..ea4a9e6 100644
--- a/sr_unix/ojchildparms.c
+++ b/sr_unix/ojchildparms.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -27,16 +27,39 @@
#include "op.h" /* for op_nullexp() */
#include "io.h"
#include "iosocketdef.h"
-
+#include "indir_enum.h"
#include <errno.h>
+#include "gtm_maxstr.h"
+#include "job_addr.h"
+#include "gtmci.h"
+#include "cache.h"
+#include "hashtab_objcode.h"
+#include "gtmio.h"
+
+GBLREF spdesc stringpool;
+GBLREF io_log_name *dollar_principal;
+GBLREF io_pair io_std_device;
+GBLREF unsigned char *source_buffer;
+GBLREF int4 aligned_source_buffer[];
+GBLREF stack_frame *frame_pointer;
+GBLREF hash_table_objcode cache_table;
+#ifdef DEBUG
+GBLREF unsigned char *msp;
+static unsigned char *save_msp;
+#endif
+static char *sp;
-GBLREF spdesc stringpool;
-GBLREF io_log_name *dollar_principal;
-GBLREF io_pair io_std_device;
+STATICFNDCL void receive_child_locals_init(char **local_buff, mval **comm_stack_ptr);
+STATICFNDCL void receive_child_locals_finalize(char **local_buff);
+/* All other platforms use this much faster direct return */
+void gtm_levl_ret_code(void);
error_def(ERR_CLOSEFAIL);
error_def(ERR_JOBSETUP);
error_def(ERR_STRINGOFLOW);
+error_def(ERR_JOBLVN2LONG);
+
+#define MAX_COMM_FRAME 5
/*
* ------------------------------------------------
@@ -44,9 +67,8 @@ error_def(ERR_STRINGOFLOW);
* parameter structure
* ------------------------------------------------
*/
-void ojchildparms(job_params_type *jparms, gcall_args *g_args, mval *arglst)
+STATICFNDEF void ojchildparms(job_params_type *jparms, gcall_args *g_args, mval *arglst)
{
- char *sp, *parmbuf;
char parm_string[8];
int4 argcnt, i;
int setup_fd;
@@ -59,29 +81,30 @@ void ojchildparms(job_params_type *jparms, gcall_args *g_args, mval *arglst)
job_buffer_size_msg buffer_size;
d_socket_struct *dsocketptr;
socket_struct *socketptr;
+ char *local_buff = NULL;
+ int comm_arg_count;
+ mval *command_str[MAX_COMM_FRAME];
- assertpro((sp = GETENV(CHILD_FLAG_ENV)) && sp[0]); /* note assignment */
+ if ((NULL == sp) && (!((sp = GETENV(CHILD_FLAG_ENV)) && sp[0]))) /* note assignment */
+ return;
setup_fd = (int)ATOL(sp);
-
- g_args->callargs = 0;
-
+ if (NULL != g_args)
+ g_args->callargs = 0;
while(!setup_done)
{
- RECV(setup_fd, &setup_op, SIZEOF(setup_op), 0, rc);
+ DOREADRC(setup_fd, &setup_op, SIZEOF(setup_op), rc);
if (rc < 0)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBSETUP, 2, LEN_AND_LIT("setup operation"), errno, 0);
- assert(SIZEOF(setup_op) == rc);
switch(setup_op)
{
case job_done:
+ case local_trans_done:
setup_done = TRUE;
break;
-
case job_set_params:
- RECV(setup_fd, ¶ms, SIZEOF(params), 0, rc);
+ DOREADRC(setup_fd, ¶ms, SIZEOF(params), rc);
if (rc < 0)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBSETUP, 2, LEN_AND_LIT("job parameters"), errno, 0);
- assert(SIZEOF(params) == rc);
jparms->directory.len = params.directory_len;
jparms->gbldir.len = params.gbldir_len;
@@ -134,14 +157,11 @@ void ojchildparms(job_params_type *jparms, gcall_args *g_args, mval *arglst)
jparms->label.addr = malloc(jparms->label.len + 1);
memcpy(jparms->label.addr, params.label, jparms->label.len + 1);
}
-
break;
-
case job_set_parm_list:
- RECV(setup_fd, &arg_count, SIZEOF(arg_count), 0, rc);
+ DOREADRC(setup_fd, &arg_count, SIZEOF(arg_count), rc);
if (rc < 0)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBSETUP, 2, LEN_AND_LIT("argument count"), errno, 0);
- assert(SIZEOF(arg_count) == rc);
g_args->callargs = arg_count + 4;
g_args->truth = 1;
g_args->retval = 0;
@@ -149,11 +169,10 @@ void ojchildparms(job_params_type *jparms, gcall_args *g_args, mval *arglst)
g_args->argcnt = arg_count;
for (i = 0; i < arg_count; i++)
{
- RECV(setup_fd, &arg_msg, SIZEOF(arg_msg), 0, rc);
+ DOREADRC(setup_fd, &arg_msg, SIZEOF(arg_msg), rc);
if (rc < 0)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBSETUP, 2, LEN_AND_LIT("argument"),
errno, 0);
- assert(SIZEOF(arg_msg) == rc);
if (0 > arg_msg.len)
g_args->argval[i] = op_nullexp(); /* negative len indicates null arg */
else
@@ -177,27 +196,117 @@ void ojchildparms(job_params_type *jparms, gcall_args *g_args, mval *arglst)
assertpro(-1 != dsocketptr->current_socket);
assertpro(dsocketptr->current_socket < dsocketptr->n_socket);
socketptr = dsocketptr->socket[dsocketptr->current_socket];
-
- RECV(setup_fd, &buffer_size, SIZEOF(buffer_size), 0, rc);
+ DOREADRC(setup_fd, &buffer_size, SIZEOF(buffer_size), rc);
if (rc < 0)
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBSETUP, 2, LEN_AND_LIT("input buffer size"),
- errno, 0);
- assert(SIZEOF(buffer_size) == rc);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBSETUP, 2,
+ LEN_AND_LIT("input buffer size"), errno, 0);
assertpro(buffer_size <= DEFAULT_SOCKET_BUFFER_SIZE);
assertpro(buffer_size <= socketptr->buffer_size);
-
- RECV(setup_fd, socketptr->buffer, buffer_size, 0, rc);
+ DOREADRC(setup_fd, socketptr->buffer, buffer_size, rc);
if (rc < 0)
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBSETUP, 2, LEN_AND_LIT("input buffer"), errno, 0);
- assert(buffer_size == rc);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBSETUP, 2,
+ LEN_AND_LIT("input buffer"), errno, 0);
socketptr->buffered_length = buffer_size;
socketptr->buffered_offset = 0;
break;
-
+ case job_set_locals:
+ /* We should get here from the second ojchildparams() call only */
+ assert(NULL == jparms);
+ if (NULL == local_buff)
+ { /* Initializations to receive the local vars */
+ receive_child_locals_init(&local_buff, command_str);
+ comm_arg_count = 0;
+ }
+ command_str[comm_arg_count]->mvtype = MV_STR;
+ command_str[comm_arg_count]->str.addr = local_buff;
+ DOREADRC(setup_fd, &buffer_size, SIZEOF(buffer_size), rc);
+ if (rc < 0)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBSETUP, 2,
+ LEN_AND_LIT("receive buffer size"), errno, 0);
+ if (buffer_size > MAX_STRLEN)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_JOBLVN2LONG, 2, MAX_STRLEN, buffer_size);
+ assert(buffer_size > 0);
+ DOREADRC(setup_fd, local_buff, buffer_size, rc);
+ if (rc < 0)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBSETUP, 2,
+ LEN_AND_LIT("local fragment"), errno, 0);;
+ assert((NULL != command_str[comm_arg_count]->str.addr) && (0 != buffer_size));
+ command_str[comm_arg_count]->str.len = buffer_size;
+ s2pool(&command_str[comm_arg_count]->str);
+ op_commarg(command_str[comm_arg_count], indir_set);
+ comm_arg_count++;
+ if (MAX_COMM_FRAME == comm_arg_count)
+ { /* grouping op_commargs() for one dm_start() is faster */
+ dm_start();
+ comm_arg_count = 0;
+ }
+ break;
default:
assertpro(FALSE && setup_op);
}
}
- if ((rc = close(setup_fd)) < 0)
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CLOSEFAIL, 1, setup_fd, errno, 0);
+ if (NULL != local_buff)
+ {
+ if (comm_arg_count != 0)
+ dm_start();
+ receive_child_locals_finalize(&local_buff);
+ }
+ /* Keep the pipe alive until local transfer is done which is done at the second call to this function */
+ if (local_trans_done == setup_op)
+ if ((rc = close(setup_fd)) < 0)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CLOSEFAIL, 1, setup_fd, errno, 0);
+}
+
+STATICFNDEF void receive_child_locals_init(char **local_buff, mval **command_str)
+{
+ rhdtyp *base_addr;
+ int i;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ assert(active_ch == ctxt);
+ assert(ctxt == chnd);
+ DEBUG_ONLY(save_msp = msp);
+ *local_buff = malloc(MAX_STRLEN);
+ source_buffer = malloc(MAX_STRLEN + 2);
+ TREF(max_advancewindow_line) = MAX_STRLEN + 1;
+ /* Get space from the stack to save the command strings before putting the base stack frame This must be done first (before
+ * putting the base frame) so that dm_start does not unintentionally pop strings off the stack
+ */
+ for (i = 0; i < MAX_COMM_FRAME; i++)
+ {
+ PUSH_MV_STENT(MVST_MVAL);
+ command_str[i] = &mv_chain->mv_st_cont.mvs_mval;
+ }
+ /* Setup the base frame */
+ base_addr = make_cimode();
+ frame_pointer->flags |= SFF_IMPLTSTART_CALLD; /* Do not return to this frame via MUM_TSTART */
+ base_frame(base_addr);
+ /* Finish base frame initialization - reset mpc/context to return to us without unwinding base frame */
+ frame_pointer->type |= SFT_TRIGR;
+ frame_pointer->mpc = CODE_ADDRESS(gtm_levl_ret_code);
+ frame_pointer->ctxt = GTM_CONTEXT(gtm_levl_ret_code);
+}
+
+STATICFNDEF void receive_child_locals_finalize(char **local_buff)
+{
+ int i;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ /* Unwind the base frame */
+ op_unwind();
+ frame_pointer = *(stack_frame**)msp;
+ msp += SIZEOF(stack_frame *); /* Remove frame save pointer from stack */
+ free(*local_buff);
+ free(source_buffer);
+ /* Reset the source buffer */
+ TREF(max_advancewindow_line) = MAX_SRCLINE;
+ source_buffer = (unsigned char *)aligned_source_buffer;
+ /* Return the space saved for command strings */
+ i = MAX_COMM_FRAME;
+ while (i--)
+ POP_MV_STENT();
+ ctxt = active_ch = chnd; /* Clear extra condition handlers added by dm_start()s */
+ assert(save_msp == msp);
}
diff --git a/sr_unix/ojparams.c b/sr_unix/ojparams.c
index 9600faa..8fe0c16 100644
--- a/sr_unix/ojparams.c
+++ b/sr_unix/ojparams.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -63,6 +63,7 @@ void ojparams (char *p, job_params_type *job_params)
job_params->directory.addr = 0;
job_params->cmdline.len = 0;
job_params->cmdline.addr = 0;
+ job_params->passcurlvn = FALSE;
/* Process parameter list */
while (*p != jp_eol)
@@ -129,6 +130,9 @@ void ojparams (char *p, job_params_type *job_params)
}
break;
+ case jp_passcurlvn:
+ job_params->passcurlvn = TRUE;
+ break;
case jp_account:
case jp_detached:
case jp_image:
diff --git a/sr_unix/ojstartchild.c b/sr_unix/ojstartchild.c
index c3e2d09..7f8a967 100644
--- a/sr_unix/ojstartchild.c
+++ b/sr_unix/ojstartchild.c
@@ -43,18 +43,32 @@
#include "compiler.h"
#include "job_addr.h"
#include "util.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
#include "gtm_facility.h"
#include "fileinfo.h"
#include "gtmio.h"
#include "fork_init.h"
+#include "rtnobj.h"
+#include "getjobnum.h"
+#include "zshow.h"
+#include "zwrite.h"
+#include "gtm_maxstr.h"
GBLREF bool jobpid; /* job's output files should have the pid appended to them. */
GBLREF volatile boolean_t ojtimeout;
GBLREF boolean_t gtm_pipe_child;
GBLREF int job_errno;
+GBLREF zshow_out *zwr_output;
+GBLREF uint4 pat_everything[];
+GBLREF mstr_len_t sizeof_pat_everything;
+GBLREF io_pair io_curr_device;
static joberr_t joberr = joberr_gen;
static int pipe_fd;
+static int setup_fds[2]; /* socket pair for setup of final mumps process */
+static pid_t child_pid;
#ifndef SYS_ERRLIST_INCLUDE
/* currently either stdio.h or errno.h both of which are included above needed by TIMEOUT_ERROR in jobsp.h */
@@ -119,7 +133,7 @@ LITREF gtmImageName gtmImageNames[];
kill(child_pid, SIGTERM); \
joberr = joberr_io_setup_op_write; \
job_errno = errno; \
- DOWRITERC(pipe_fds[1], &job_errno, SIZEOF(job_errno), pipe_status); \
+ DOWRITERC(pipe_fd, &job_errno, SIZEOF(job_errno), pipe_status); \
_exit(joberr); \
}
@@ -132,8 +146,18 @@ LITREF gtmImageName gtmImageNames[];
_exit(joberr); \
}
+#ifdef AUTORELINK_SUPPORTED
+#define RELINKCTL_RUNDOWN_MIDDLE_PARENT(NEED_RTNOBJ_SHM_FREE, RTNHDR) \
+{ \
+ if (NEED_RTNOBJ_SHM_FREE) \
+ rtnobj_shm_free(RTNHDR, LATCH_GRABBED_FALSE); \
+ relinkctl_rundown(TRUE, FALSE); \
+}
+#endif
+
error_def(ERR_GTMDISTUNVERIF);
error_def(ERR_JOBFAIL);
+error_def(ERR_JOBLVN2LONG);
error_def(ERR_JOBPARTOOLONG);
error_def(ERR_LOGTOOLONG);
error_def(ERR_TEXT);
@@ -142,8 +166,9 @@ error_def(ERR_TEXT);
* not want to run.
*/
-void job_term_handler(int sig);
-static int io_rename(job_params_msg *params, const int jobid);
+STATICFNDCL void job_term_handler(int sig);
+STATICFNDCL int io_rename(job_params_msg *params, const int jobid);
+STATICFNDCL void local_variable_marshalling(void);
/* Middle process sets the entryref for the jobbed-off process by calling job_addr(). job_addr() internally calls op_zlink(). If
* rts_error occurs when we are in the job_addr() function, the topmost condition handler inherited from parent process will be
@@ -154,11 +179,12 @@ static CONDITION_HANDLER(middle_child)
{
int pipe_status;
START_CH(FALSE);
- DOWRITERC(pipe_fd, &job_errno, SIZEOF(job_errno), pipe_status);
/* As of now, middle process could encounter rts_error only while setting entryref. Hence the following assert.
* Do assert after write to prevent parent hang.
*/
assert(joberr == joberr_rtn);
+ ARLINK_ONLY(RELINKCTL_RUNDOWN_MIDDLE_PARENT(FALSE, NULL);) /* decrement refcnts for relinkctl shm */
+ DOWRITERC(pipe_fd, &job_errno, SIZEOF(job_errno), pipe_status);
_exit(joberr);
}
@@ -175,7 +201,7 @@ static CONDITION_HANDLER(grand_child)
* successfully forked-off the job.
*/
-void job_term_handler(int sig)
+STATICFNDEF void job_term_handler(int sig)
{
int ret;
int status;
@@ -195,7 +221,7 @@ void job_term_handler(int sig)
return;
}
-static int io_rename(job_params_msg *params, const int jobid)
+STATICFNDEF int io_rename(job_params_msg *params, const int jobid)
{
char path[MAX_STDIOE_LEN];
@@ -218,6 +244,76 @@ static int io_rename(job_params_msg *params, const int jobid)
return 0;
}
+void ojmidchild_send_var(void)
+{
+ job_setup_op setup_op;
+ int rc, pipe_status;
+ job_buffer_size_msg buffer_size;
+
+ setup_op = job_set_locals;
+ SEND(setup_fds[0], &setup_op, SIZEOF(setup_op), 0, rc);
+ if (rc < 0)
+ SETUP_OP_FAIL();
+ buffer_size = zwr_output->ptr - zwr_output->buff;
+ /* Crop the ' ;*' string at the end of the aliases */
+ if (zwr_output->buff[buffer_size - 1] == '*' && zwr_output->buff[buffer_size - 2] == ';'
+ && zwr_output->buff[buffer_size - 3] == ' ')
+ buffer_size -= 3;
+ assert(buffer_size > 0);
+ /* We must send the buffer_size regardless of its value. The child has its own check for size. It is going to terminate if
+ * the size is excessive.
+ */
+ SEND(setup_fds[0], &buffer_size, SIZEOF(buffer_size), 0, rc);
+ if (rc < 0)
+ SETUP_OP_FAIL();
+ if (buffer_size > MAX_STRLEN)
+ {
+ rc = ERR_JOBLVN2LONG;
+ DOWRITERC(pipe_fd, &rc, SIZEOF(rc), pipe_status);
+ /* No need to SIGTERM the child because child will issue a proper error message and quit */
+ _exit(joberr_io_setup_op_write);
+ }
+ SEND(setup_fds[0], zwr_output->buff, buffer_size, 0, rc);
+ if (rc < 0)
+ SETUP_OP_FAIL();
+ zwr_output->ptr = zwr_output->buff;
+ return;
+}
+
+STATICFNDEF void local_variable_marshalling(void)
+{
+ /* Setup buffer to write local variables one at a time */
+ zshow_out output;
+ mval pattern;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ memset(&output, 0, SIZEOF(output));
+ output.code = 'V';
+ output.type = ZSHOW_BUFF_ONLY;
+ /* Expanded MAXSTR_BUFF_DECL/MAXSTR_BUFF_INIT below because they are designed to handle the size of MAX_STRBUFF_INIT when we
+ * really want is MAX_STRLEN The condition handler established within MAXSTR_BUFF_INIT is futile because any error we
+ * encounter here is fatal
+ */
+ output.buff = malloc(MAX_STRLEN);
+ output.size = MAX_STRLEN;
+ maxstr_stack_level++;
+ assert(maxstr_stack_level < MAXSTR_STACK_SIZE);
+ maxstr_buff[maxstr_stack_level].len = output.size;
+ maxstr_buff[maxstr_stack_level].addr = NULL;
+ output.ptr = output.buff;
+ TREF(midchild_send_locals) = TRUE;
+ pattern.str.addr = (char *)pat_everything;
+ pattern.str.len = sizeof_pat_everything;
+ pattern.mvtype = MV_STR;
+ lvzwr_init(zwr_patrn_mval, &pattern);
+ lvzwr_fini(&output, ZWRITE_END);
+ TREF(midchild_send_locals) = FALSE;
+ free(output.buff);
+ return;
+}
+
+
/*
* --------------------------------------------------------------------------------------------------------------------------------
* The current process (P) FORKs a middle child process (M) that tests various job parameters. It then forks off the actual Job (J)
@@ -241,6 +337,7 @@ static int io_rename(job_params_msg *params, const int jobid)
int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_return, int pipe_fds[])
{
+ boolean_t need_rtnobj_shm_free;
char cbuff[TEMP_BUFF_SIZE], pbuff[TEMP_BUFF_SIZE], cmdbuff[TEMP_BUFF_SIZE];
char tbuff[MAX_JOB_LEN], tbuff2[MAX_JOB_LEN], fname_buf[MAX_STDIOE_LEN];
char *pgbldir_str;
@@ -249,34 +346,33 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
int wait_status, save_errno, kill_ret;
int rc, dup_ret, in_fd;
int status;
- pid_t child_pid, done_pid;
+ pid_t done_pid;
job_parm *jp;
- rhdtyp *base_addr;
+ rhdtyp *rtnhdr;
struct sigaction act, old_act;
int pipe_status, env_len;
int mproc_fds[2]; /* pipe between middle process and grandchild process */
int decision;
- int setup_fds[2]; /* socket pair for setup of final mumps process */
job_setup_op setup_op;
job_params_msg params;
job_arg_count_msg arg_count;
job_arg_msg arg_msg;
job_buffer_size_msg buffer_size;
-
-#ifdef __osf__
-/* These must be O/S-compatible 64-bit pointers for OSF/1. */
-#pragma pointer_size (save)
-#pragma pointer_size (long)
-#endif
-
+# ifdef __osf__
+ /* These must be O/S-compatible 64-bit pointers for OSF/1. */
+# pragma pointer_size (save)
+# pragma pointer_size (long)
+# endif
char *c1, *c2, **c3;
char *argv[4];
char **env_ary, **env_ind;
char **new_env_cur, **new_env_top, **old_env_cur, **old_env_top, *env_end;
+# ifdef __osf__
+# pragma pointer_size (restore)
+# endif
+ DCL_THREADGBL_ACCESS;
-#ifdef __osf__
-#pragma pointer_size (restore)
-#endif
+ SETUP_THREADGBL_ACCESS;
/* Do the fork and exec but BEFORE that do a FFLUSH(NULL) to make sure any fclose (done in io_rundown
* in the child process) does not affect file offsets in this (parent) process' file descriptors
*/
@@ -292,6 +388,10 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
* much hitch. If any error occurs during this, exit with appropriate status so the waiting parent can diagnose.
*/
+ getjobnum(); /* set "process_id" to a value different from parent. This is particularly needed for the
+ * RELINKCTL_RUNDOWN_MIDDLE_PARENT macro since it does rtnobj_shm_free which deals with latches
+ * that in turn rely on the "process_id" global variable reflecting the current pid.
+ */
/* set to TRUE so any child process associated with a pipe device will know it is not the parent in iorm_close() */
gtm_pipe_child = TRUE;
joberr = joberr_gen;
@@ -371,11 +471,30 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
DOWRITERC(pipe_fds[1], &job_errno, SIZEOF(job_errno), pipe_status);
_exit(status);
}
-
+ /* Record the fact that this process is interested in the relinkctl files inherited from the parent by
+ * incrementing the linkctl->hdr->nattached count. This is required by the relinkctl_rundown(TRUE, FALSE)
+ * call done as part of the RELINKCTL_RUNDOWN_MIDDLE_PARENT macro in the middle child or the grandchild.
+ * Do this BEFORE the call to job_addr. In case that does a relinkctl_attach of a new relinkctl file,
+ * we would increment the counter automatically so dont want that to go through a double-increment.
+ */
+ ARLINK_ONLY(relinkctl_incr_nattached());
joberr = joberr_rtn;
- if (!job_addr(&jparms->routine, &jparms->label, jparms->offset, (char **)&base_addr, &transfer_addr))
+ /* We are the middle child. It is possible the below call to job_addr loads an object into shared memory
+ * using "rtnobj_shm_malloc". In that case, as part of halting we need to do a "rtnobj_shm_free" to keep
+ * the rtnobj reference counts in shared memory intact. The variable "need_rtnobj_shm_free" servers this purpose.
+ * Note that we cannot safely call relinkctl_rundown since we do not want to decrement reference counts for
+ * routines that have already been loaded by our parent process (which we inherited due to the fork) since
+ * the parent process is the one that will do the decrement later. We should decrement the count only for
+ * routines that we load ourselves. And the only one possible is due to the below call to "job_addr".
+ * Note that the balancing decrement/free happens in the middle child until the grandchild is forked.
+ * Once the grandchild fork succeeds, the grandchild is incharge of doing this cleanup. This flow is needed
+ * so the decrement (and potential removal of rtnobj shmid) only happens AFTER when it is needed.
+ */
+ if (!job_addr(&jparms->routine, &jparms->label, jparms->offset, (char **)&rtnhdr, &transfer_addr,
+ &need_rtnobj_shm_free))
{
DOWRITERC(pipe_fds[1], &job_errno, SIZEOF(job_errno), pipe_status);
+ ARLINK_ONLY(RELINKCTL_RUNDOWN_MIDDLE_PARENT(need_rtnobj_shm_free, rtnhdr);)
_exit(joberr);
}
@@ -384,14 +503,16 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
{
job_errno = errno;
DOWRITERC(pipe_fds[1], &job_errno, SIZEOF(job_errno), pipe_status);
+ ARLINK_ONLY(RELINKCTL_RUNDOWN_MIDDLE_PARENT(need_rtnobj_shm_free, rtnhdr);)
_exit(joberr);
}
joberr = joberr_sp;
- if (-1 == (rc = socketpair(AF_UNIX, SOCK_DGRAM, 0, setup_fds)))
+ if (-1 == (rc = socketpair(AF_UNIX, SOCK_STREAM, 0, setup_fds)))
{
job_errno = errno;
DOWRITERC(pipe_fds[1], &job_errno, SIZEOF(job_errno), pipe_status);
+ ARLINK_ONLY(RELINKCTL_RUNDOWN_MIDDLE_PARENT(need_rtnobj_shm_free, rtnhdr);)
_exit(joberr);
}
@@ -430,7 +551,6 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
_exit(joberr);
}
}
-
/* Inform grandchild that everything is properly set for it and it is ready to continue. */
decision = JOB_CONTINUE;
DOWRITERC(mproc_fds[1], &decision, SIZEOF(decision), pipe_status);
@@ -442,13 +562,11 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
DOWRITERC(pipe_fds[1], &job_errno, SIZEOF(job_errno), pipe_status);
_exit(joberr);
}
-
/* send job parameters and arguments to final mumps process over setup socket */
setup_op = job_set_params;
SEND(setup_fds[0], &setup_op, SIZEOF(setup_op), 0, rc);
if (rc < 0)
SETUP_OP_FAIL();
-
params.directory_len = jparms->directory.len;
memcpy(params.directory, jparms->directory.addr, jparms->directory.len);
if (0 < jparms->gbldir.len)
@@ -484,17 +602,14 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
SEND(setup_fds[0], ¶ms, SIZEOF(params), 0, rc);
if (rc < 0)
SETUP_DATA_FAIL();
-
setup_op = job_set_parm_list;
SEND(setup_fds[0], &setup_op, SIZEOF(setup_op), 0, rc);
if (rc < 0)
SETUP_OP_FAIL();
-
arg_count = argcnt;
SEND(setup_fds[0], &arg_count, SIZEOF(arg_count), 0, rc);
if (rc < 0)
SETUP_DATA_FAIL();
-
for (jp = jparms->parms; jp ; jp = jp->next)
{
if (jp->parm->str.len > MAX_JOB_LEN - 2)
@@ -512,31 +627,37 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
if (rc < 0)
SETUP_DATA_FAIL();
}
-
if (0 < jparms->input_prebuffer_size)
{
setup_op = job_set_input_buffer;
SEND(setup_fds[0], &setup_op, SIZEOF(setup_op), 0, rc);
if (rc < 0)
SETUP_OP_FAIL();
-
buffer_size = jparms->input_prebuffer_size;
SEND(setup_fds[0], &buffer_size, SIZEOF(buffer_size), 0, rc);
if (rc < 0)
SETUP_DATA_FAIL();
-
SEND(setup_fds[0], jparms->input_prebuffer, jparms->input_prebuffer_size, 0, rc);
if (rc < 0)
SETUP_DATA_FAIL();
/* input_prebuffer leaks, but the middle process is about to exit, so don't worry about it */
}
-
- /* tell job to proceed */
setup_op = job_done;
SEND(setup_fds[0], &setup_op, SIZEOF(setup_op), 0, rc);
if (rc < 0)
SETUP_OP_FAIL();
-
+ /* Send the local variables */
+ if (jparms->passcurlvn)
+ local_variable_marshalling();
+ /* tell job to proceed */
+ setup_op = local_trans_done;
+ SEND(setup_fds[0], &setup_op, SIZEOF(setup_op), 0, rc);
+ if (rc < 0)
+ SETUP_OP_FAIL();
+ /* tell job to proceed but before that detach from relinkctl/rtnobj shared memory in case the grandchild
+ * needs to remove those (due to linkctl->hdr->nattached being 0).
+ */
+ ARLINK_ONLY(relinkctl_rundown(FALSE, FALSE)); /* do not decrement counters, just shmdt */
/* write child_pid into pipe to be read by parent process(P) for $ZJOB */
/* Ignore the status if this fails, as the child is already running, and there is likely not a parent
* to report to.
@@ -547,21 +668,26 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
/* This is now the grandchild process (actual Job process) -- an orphan as soon as the exit(EXIT_SUCCESS) above
* occurs. Revert the condition handler established by middle process and establish its own condition handler */
REVERT;
+ getjobnum(); /* set "process_id" to a value different from parent (middle child). This is particularly needed
+ * for the RELINKCTL_RUNDOWN_MIDDLE_PARENT macro since it does rtnobj_shm_free which deals with
+ * latches that in turn rely on the "process_id" global variable reflecting the current pid.
+ */
ESTABLISH_RET(grand_child, 0);
sigaction(SIGTERM, &old_act, 0); /* restore the SIGTERM handler */
CLOSEFILE_RESET(mproc_fds[1], pipe_status); /* resets "mproc_fds[0]" to FD_INVALID */
CLOSEFILE_RESET(setup_fds[0], pipe_status); /* resets "setup_fds[0]" to FD_INVALID */
DOREADRC(mproc_fds[0], &decision, SIZEOF(decision), pipe_status);
if (pipe_status) /* We failed to read the communication from middle process */
+ {
+ ARLINK_ONLY(RELINKCTL_RUNDOWN_MIDDLE_PARENT(need_rtnobj_shm_free, rtnhdr);)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2,
LEN_AND_LIT("Error reading from pipe"), errno);
- else {
+ } else {
if (JOB_EXIT == decision)
exit(EXIT_SUCCESS);
assert(JOB_CONTINUE == decision);
}
CLOSEFILE_RESET(mproc_fds[0], pipe_status); /* resets "mproc_fds[0]" to FD_INVALID */
-
/* Run down any open flat files to reclaim their file descriptors */
io_rundown(RUNDOWN_EXCEPT_STD);
@@ -569,9 +695,6 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
CLOSEFILE_RESET(pipe_fds[0], pipe_status); /* resets "pipe_fds[0]" to FD_INVALID */
CLOSEFILE_RESET(pipe_fds[1], pipe_status); /* resets "pipe_fds[1]" to FD_INVALID */
- /* do common cleanup in child */
- ojchildioclean();
-
/* Count the number of environment variables. */
for (environ_count = 0, c3 = environ, c2 = *c3; c2; c3++, c2 = *c3)
environ_count++;
@@ -617,7 +740,10 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
string_len = STRLEN("%s=%d") + STRLEN(CHILD_FLAG_ENV) + MAX_NUM_LEN - 4;
if (string_len > MAX_JOB_LEN)
+ {
+ ARLINK_ONLY(RELINKCTL_RUNDOWN_MIDDLE_PARENT(need_rtnobj_shm_free, rtnhdr);)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG);
+ }
c1 = (char *)malloc(string_len + 1);
#ifdef KEEP_zOS_EBCDIC
#pragma convlit(suspend)
@@ -639,7 +765,10 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
*(pbuff + jparms->gbldir.len) = '\0';
string_len = STRLEN("%s=%s") + STRLEN(GBLDIR_ENV) + STRLEN(pbuff) - 4;
if (string_len > TEMP_BUFF_SIZE)
+ {
+ ARLINK_ONLY(RELINKCTL_RUNDOWN_MIDDLE_PARENT(need_rtnobj_shm_free, rtnhdr);)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG);
+ }
c1 = (char *)malloc(string_len + 1);
#ifdef KEEP_zOS_EBCDIC
#pragma convlit(suspend)
@@ -700,9 +829,11 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
c2 = &tbuff[string_len];
strcpy(c2, MUMPS_EXE_STR);
} else
+ {
+ ARLINK_ONLY(RELINKCTL_RUNDOWN_MIDDLE_PARENT(need_rtnobj_shm_free, rtnhdr);)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_LOGTOOLONG, 3, string_len, c1,
SIZEOF(tbuff) - SIZEOF(MUMPS_EXE_STR));
-
+ }
# ifdef KEEP_zOS_EBCDIC_ /* use real strcpy to preserve env in native code set */
# pragma convlit(suspend)
# endif
@@ -720,6 +851,15 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
*(cmdbuff + jparms->cmdline.len) = 0;
} else
memset(cmdbuff, 0, TEMP_BUFF_SIZE);
+ /* Now that all job parameters (which could potentially be in relinkctl rtnobj shared memory) have been
+ * copied over, we can get rid of our relinkctl files. Note that the below macro decrements
+ * linkctl->hdr->nattached in the grandchild on behalf of the middle child (who did the increment).
+ */
+ ARLINK_ONLY(RELINKCTL_RUNDOWN_MIDDLE_PARENT(need_rtnobj_shm_free, rtnhdr);)
+ /* Do common cleanup in child. Note that the below call to "ojchildioclean" invokes "relinkctl_rundown"
+ * but that is not needed since we have already done it in the RELINKCTL_RUNDOWN_MIDDLE_PARENT invocation.
+ */
+ ojchildioclean();
#ifdef KEEP_zOS_EBCDIC
__getEstring1_a_copy(tbuff2, STR_AND_LEN(tbuff));
@@ -784,6 +924,5 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
return (EINVAL); /* return some error condition */
}
}
-
return (EINVAL); /* This should never get executed, added to make compiler happy */
}
diff --git a/sr_unix/op_fnzpeek.c b/sr_unix/op_fnzpeek.c
index 73c81db..1aae1b0 100644
--- a/sr_unix/op_fnzpeek.c
+++ b/sr_unix/op_fnzpeek.c
@@ -14,6 +14,7 @@
#include <signal.h>
#include "gtm_unistd.h"
#include "gtm_string.h"
+#include "gtm_time.h"
#include "send_msg.h"
#include "error.h"
@@ -33,31 +34,39 @@
#include "gtmrecv.h"
#include "anticipatory_freeze.h"
#include "gtm_caseconv.h"
+#include "jnl.h"
+#include "dollarh.h"
error_def(ERR_BADZPEEKARG);
error_def(ERR_BADZPEEKFMT);
error_def(ERR_BADZPEEKRANGE);
error_def(ERR_MAXSTRLEN);
+error_def(ERR_ZPEEKNOJNLINFO);
error_def(ERR_ZPEEKNORPLINFO);
#define FMTHEXDGT(spfree, digit) *spfree++ = digit + ((digit <= 9) ? '0' : ('A' - 0x0A))
#define ARGUMENT_MAX_LEN MAX_MIDENT_LEN
/* Codes for peek operation mnemonics */
-#define PO_CSAREG 0 /* Region information - sgmnt_addrs struct - process private structure */
-#define PO_FHREG 1 /* Fileheader information from sgmnt_data for specified region */
-#define PO_GDRREG 2 /* Region information - gd_region struct - process private structure */
-#define PO_NLREG 3 /* Fileheader information from node_local for specified region (transient - non permanent) */
-#define PO_NLREPL 4 /* Fileheader information from node_local for replication dummy region */
-#define PO_GLFREPL 5 /* Replication information from gtmsrc_lcl_array structure */
-#define PO_GSLREPL 6 /* Replication information from gtmsource_local_array structure */
-#define PO_JPCREPL 7 /* Replication information from jnlpool_ctl structure */
-#define PO_PEEK 8 /* Generalized peek specifying (base) address argument */
-#define PO_RIHREPL 9 /* Replication information from repl_inst_hdr structure */
-#define PO_RPCREPL 10 /* Replication information from recvpool_ctl_struct */
-#define PO_UPLREPL 11 /* Replication information from upd_proc_local_struct */
-#define PO_GRLREPL 12 /* Replication information from gtmrecv_local_struct */
-#define PO_UHCREPL 13 /* Replication information from upd_helper_ctl */
+typedef enum
+{
+ PO_CSAREG = 0, /* 0 Region information - sgmnt_addrs struct - process private structure */
+ PO_FHREG, /* 1 Fileheader information from sgmnt_data for specified region */
+ PO_GDRREG, /* 2 Region information - gd_region struct - process private structure */
+ PO_NLREG, /* 3 Fileheader information from node_local for specified region (transient - non permanent) */
+ PO_NLREPL, /* 4 Fileheader information from node_local for replication dummy region */
+ PO_GLFREPL, /* 5 Replication information from gtmsrc_lcl_array structure */
+ PO_GSLREPL, /* 6 Replication information from gtmsource_local_array structure */
+ PO_JPCREPL, /* 7 Replication information from jnlpool_ctl structure */
+ PO_PEEK, /* 8 Generalized peek specifying (base) address argument */
+ PO_RIHREPL, /* 9 Replication information from repl_inst_hdr structure */
+ PO_RPCREPL, /* 10 Replication information from recvpool_ctl_struct */
+ PO_UPLREPL, /* 11 Replication information from upd_proc_local_struct */
+ PO_GRLREPL, /* 12 Replication information from gtmrecv_local_struct */
+ PO_UHCREPL, /* 13 Replication information from upd_helper_ctl */
+ PO_JNLREG, /* 14 Journal information - jnl_private_control */
+ PO_JBFREG /* 15 Journal buffer information - jnl_buffer_ptr_t */
+} zpeek_mnemonic;
GBLREF boolean_t created_core;
GBLREF sigset_t blockalrm;
@@ -94,22 +103,26 @@ LITDEF nametabent zpeek_names[] =
,{3, "GLF"}, {7, "GLFREPL"} /* 6, 7 */
,{3, "GRL"}, {7, "GRLREPL"} /* 8, 9 */
,{3, "GSL"}, {7, "GSLREPL"} /* 10, 11 */
- ,{3, "JPC"}, {7, "JPCREPL"} /* 12, 13 */
- ,{2, "NL"}, {5, "NLREG"} /* 14, 15 */
- ,{6, "NLREPL"} /* 16 */
- ,{4, "PEEK"} /* 17 */
- ,{3, "RIH"}, {7, "RIHREPL"} /* 18, 19 */
- ,{3, "RPC"}, {7, "RPCREPL"} /* 20, 21 */
- ,{3, "UHC"}, {7, "UHCREPL"} /* 22, 23 */
- ,{3, "UPL"}, {7, "UPLREPL"} /* 24, 25 */
- /* Total length 26 */
+ ,{3, "JBF"}, {6, "JBFREG"} /* 12, 13 */
+ ,{3, "JPC"}, {7, "JPCREPL"} /* 14, 15 */
+ ,{3, "JNL"}, {6, "JNLREG"} /* 16, 17 */
+ ,{2, "NL"}, {5, "NLREG"} /* 18, 19 */
+ ,{6, "NLREPL"} /* 20 */
+ ,{4, "PEEK"} /* 21 */
+ ,{3, "RIH"}, {7, "RIHREPL"} /* 22, 23 */
+ ,{3, "RPC"}, {7, "RPCREPL"} /* 24, 25 */
+ ,{3, "UHC"}, {7, "UHCREPL"} /* 26, 27 */
+ ,{3, "UPL"}, {7, "UPLREPL"} /* 28, 29 */
+ /* Total length 30 */
};
+/* Index to first entry with given starting letter */
LITDEF unsigned char zpeek_index[] =
{
0, 0, 0, 2, 2, 2, 4, 12, 12, /* a b c d e f g h i */
- 12, 14, 14, 14, 14, 17, 17, 18, 18, /* j k l m n o p q r */
- 22, 22, 22, 26, 26, 26, 26, 26, 26 /* s t u v w x y z ~ */
+ 12, 18, 18, 18, 18, 21, 21, 22, 22, /* j k l m n o p q r */
+ 26, 26, 26, 30, 30, 30, 30, 30, 30 /* s t u v w x y z ~ */
};
+/* Associated fetch code for each entry with flag for whether arguments accepted after code (e.g. CSAREG:MUMPS) */
LITDEF zpeek_data_typ zpeek_data[] =
{
{PO_CSAREG, 1}, {PO_CSAREG, 1}
@@ -118,7 +131,9 @@ LITDEF zpeek_data_typ zpeek_data[] =
,{PO_GLFREPL, 1}, {PO_GLFREPL, 1}
,{PO_GRLREPL, 0}, {PO_GRLREPL, 0}
,{PO_GSLREPL, 1}, {PO_GSLREPL, 1}
+ ,{PO_JBFREG, 1}, {PO_JBFREG, 1}
,{PO_JPCREPL, 0}, {PO_JPCREPL, 0}
+ ,{PO_JNLREG, 1}, {PO_JNLREG, 1}
,{PO_NLREG, 1}, {PO_NLREG, 1}
,{PO_NLREPL, 0}
,{PO_PEEK, 1}
@@ -221,6 +236,9 @@ STATICFNDEF int op_fnzpeek_stpcopy(char *zpeekadr, int len, mval *ret, char fmtc
gtm_uint64_t uint64;
unsigned char *numstrstart, *numstrend;
unsigned char *hexchr, *hexchrend, hexc, hexdgt, *spfree;
+ char timebuff[MAXNUMLEN + 1];
+ time_t seconds;
+ uint4 days;
ESTABLISH_RET(op_fnzpeek_ch, ERR_BADZPEEKRANGE); /* If get an exception, likely due to bad range */
ret->mvtype = 0; /* Prevent GC of incomplete field */
@@ -324,6 +342,18 @@ STATICFNDEF int op_fnzpeek_stpcopy(char *zpeekadr, int len, mval *ret, char fmtc
ret->str.len = INTCAST(numstrend - numstrstart);
stringpool.free = numstrend;
break;
+ case 'T': /* Time ($HOROLOG) format */
+ if ((SIZEOF(uint4) != len) && (SIZEOF(gtm_uint64_t) != len))
+ return ERR_BADZPEEKFMT;
+ ENSURE_STP_FREE_SPACE(MAXNUMLEN + 1);
+ seconds = (SIZEOF(gtm_uint64_t) == len) ? *(gtm_uint64_t *)zpeekadr : *(uint4 *)zpeekadr;
+ dollarh(seconds, &days, &seconds);
+ ret->str.addr = (char *)stringpool.free;
+ stringpool.free = i2asc(stringpool.free, days);
+ *stringpool.free++ = ',';
+ stringpool.free = i2asc(stringpool.free, (uint4)seconds);
+ ret->str.len = INTCAST((char *)stringpool.free - ret->str.addr);
+ break;
case 'Z': /* Hex format (no 0x prefix) of storage as it exists */
if ((len * 2) > MAX_STRLEN)
{ /* Requested string return is too large */
@@ -412,6 +442,7 @@ void op_fnzpeek(mval *structid, int offset, int len, mval *format, mval *ret)
replpool_identifier replpool_id;
unsigned int full_len;
unsigned char argument_uc_buf[ARGUMENT_MAX_LEN];
+ sgmnt_addrs *csa;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
@@ -452,6 +483,8 @@ void op_fnzpeek(mval *structid, int offset, int len, mval *format, mval *ret)
case PO_FHREG:
case PO_GDRREG:
case PO_NLREG:
+ case PO_JNLREG:
+ case PO_JBFREG:
/* Uppercase the region name since that is what GDE does when creating them */
lower_to_upper(argument_uc_buf, argptr, arglen);
argptr = argument_uc_buf; /* Reset now to point to upper case version */
@@ -522,6 +555,13 @@ void op_fnzpeek(mval *structid, int offset, int len, mval *format, mval *ret)
case PO_NLREG: /* r_ptr set from option processing */
zpeekadr = (&FILE_INFO(r_ptr)->s_addrs)->nl;
break;
+ case PO_JNLREG: /* r_ptr set from option processing */
+ case PO_JBFREG:
+ csa = &FILE_INFO(r_ptr)->s_addrs;
+ if ((NULL == csa->jnl) || (jnl_open != csa->hdr->jnl_state))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZPEEKNOJNLINFO, 2, REG_LEN_STR(r_ptr));
+ zpeekadr = (PO_JNLREG == mnemonic_opcode) ? (void *)csa->jnl : (void *)csa->jnl->jnl_buff;
+ break;
case PO_GLFREPL: /* This set of opcodes all require the journal pool to be initialized. Verify it */
case PO_GSLREPL:
case PO_JPCREPL:
@@ -612,6 +652,7 @@ void op_fnzpeek(mval *structid, int offset, int len, mval *format, mval *ret)
case 'C': /* Character data - returned as is */
case 'I': /* Signed integer format - up to 31 bits */
case 'S': /* String data - Same as 'C' except string is NULL terminated */
+ case 'T': /* Time ($H) format - length must be of 4 or 8 byte unsigned int */
case 'U': /* Unsigned integer format - up to 64 bits */
case 'X': /* Humeric hex format: e.g. 0x12AB. Total length is (2 * bytes) + 2 */
case 'Z': /* Hex format - not treated as numeric. Shown as occurs in memory (subject to endian)
diff --git a/sr_unix/op_fnzsearch.c b/sr_unix/op_fnzsearch.c
index 6f2332f..a268e2b 100644
--- a/sr_unix/op_fnzsearch.c
+++ b/sr_unix/op_fnzsearch.c
@@ -72,7 +72,7 @@ int op_fnzsearch(mval *file, mint indx, mint mfunc, mval *ret)
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
- if (mfunc && ((MAX_STRM_CT < indx) || ( 0 > indx))) /* Allow out-of-range stream if internal call */
+ if (mfunc && ((MAX_STRM_CT <= indx) || ( 0 > indx))) /* Allow out-of-range stream if internal call */
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZSRCHSTRMCT);
ESTABLISH_RET(fnzsrch_ch, -1);
TREF(fnzsearch_nullsubs_sav) = TREF(lv_null_subs);
diff --git a/sr_unix/op_lab_ext.c b/sr_unix/op_lab_ext.c
index 6fa4396..01bc85b 100644
--- a/sr_unix/op_lab_ext.c
+++ b/sr_unix/op_lab_ext.c
@@ -13,7 +13,7 @@
#include <rtnhdr.h>
-#ifdef USHBIN_SUPPORTED /* entire file */
+#ifdef AUTORELINK_SUPPORTED /* entire file */
/* Routine to provide the content of the thread-local variable "lab_lnr" as a return value to
* generated code.
*
@@ -29,4 +29,4 @@ void *op_lab_ext(void)
SETUP_THREADGBL_ACCESS;
return TREF(lab_lnr);
}
-#endif /* USHBIN_SUPPORTED over entire file */
+#endif /* AUTORELINK_SUPPORTED over entire file */
diff --git a/sr_unix/op_rhd_ext.c b/sr_unix/op_rhd_ext.c
index 13673ae..aa469aa 100644
--- a/sr_unix/op_rhd_ext.c
+++ b/sr_unix/op_rhd_ext.c
@@ -11,14 +11,16 @@
#include "mdef.h"
-#ifdef USHBIN_SUPPORTED /* entire file */
+#ifdef AUTORELINK_SUPPORTED /* entire file */
#include "gtm_string.h"
#include <rtnhdr.h>
#include "op.h"
#include "relinkctl.h"
-#include "zhist.h"
#include "min_max.h"
+#include "zbreak.h"
+
+GBLREF z_records zbrk_recs; /* ZBREAKs in effect */
/* Rebuffering macro for routine and label name for use when needed. Note we don't even do the
* MV_FORCE_STR() on the given mval until we know we are going to use it.
@@ -52,12 +54,9 @@ rhdtyp *op_rhd_ext(mval *rtname, mval *lbname, rhdtyp *rhd, void *lnr)
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
- /* The are two potential future updates here:
- * 1. Desire to remove the two additional opcodes and revert back to the single call opcode (op_call, op_extexfun, etc).
- * This would have positive performance enhancements through less generated code and shorter call path if doable.
- * 2. Intention is to change the syntax of ZRUPDATE such that routines can be specified in groups surrounded by
- * parentheses (e.g. ZRUPDATE (a.o,b.o,c.o)) which would make all 3 routines available simultaneously instead of
- * serially. This will likely require some sort of locking protocols but is not yet defined.
+ /* Future TODO:
+ * Remove the two additional opcodes and revert back to the single call opcode (op_call, op_extexfun, etc).
+ * This would have positive performance enhancements through less generated code and shorter call path if doable.
*/
if (NULL == rhd)
{ /* Routine is not yet linked - perform auto-ZLINK */
@@ -70,23 +69,27 @@ rhdtyp *op_rhd_ext(mval *rtname, mval *lbname, rhdtyp *rhd, void *lnr)
return rhd;
}
/* Routine is already linked, but we need to check if a new version is available. This involves traversing the
- * "validation linked list", looking for changes in different $zro entries. But we also need to base our checks
- * on the most recent version of the routine loaded.
+ * "validation linked list", looking for changes in different $ZROUTINES entries. But we also need to base our
+ * checks on the most recent version of the routine loaded. Note autorelink is only possible when no ZBREAKs are
+ * defined in the given routine.
*/
- rhd = rhd->current_rhead_adr;
- if ((NULL != rhd->zhist) && need_relink(rhd, (zro_hist *)rhd->zhist))
- {
- REBUFFER_MIDENT(rtname, &rtnname, rtnname_buff);
- REBUFFER_MIDENT(lbname, &lblname, lblname_buff);
- op_zlink(&rtnname, NULL);
- rhd = rhd->current_rhead_adr; /* Pickup routine header of new version to avoid lookup */
- assert((NULL == rhd->zhist) || (((zro_hist *)(rhd->zhist))->zroutines_cycle == TREF(set_zroutines_cycle)));
- op_labaddr(rhd, &lblname, 0);
- TREF(lab_lnr) = &((TREF(lab_proxy)).lnr_adr);
- return rhd;
+ if (!rhd->has_ZBREAK)
+ { /* Only look for autorelink when no ZBREAKs are defined in this routine */
+ rhd = rhd->current_rhead_adr; /* Update rhd to most currently linked version */
+ if ((NULL != rhd->zhist) && need_relink(rhd, (zro_hist *)rhd->zhist))
+ { /* Relink appears to be needed */
+ REBUFFER_MIDENT(rtname, &rtnname, rtnname_buff);
+ REBUFFER_MIDENT(lbname, &lblname, lblname_buff);
+ op_zlink(&rtnname, NULL);
+ rhd = rhd->current_rhead_adr; /* Pickup routine header of new version to avoid lookup */
+ assert((NULL == rhd->zhist) || (((zro_hist *)(rhd->zhist))->zroutines_cycle == TREF(set_zroutines_cycle)));
+ op_labaddr(rhd, &lblname, 0);
+ TREF(lab_lnr) = &((TREF(lab_proxy)).lnr_adr);
+ return rhd;
+ }
}
/* Linked routine is already the latest */
TREF(lab_lnr) = lnr;
return rhd;
}
-#endif /* USHBIN_SUPPORTED */
+#endif /* AUTORELINK_SUPPORTED */
diff --git a/sr_unix/op_zedit.c b/sr_unix/op_zedit.c
index c995e3f..5dcdca5 100644
--- a/sr_unix/op_zedit.c
+++ b/sr_unix/op_zedit.c
@@ -26,13 +26,15 @@
#include "setterm.h"
#include "op.h"
#include "fork_init.h"
+#include "geteditor.h"
+#include "wbox_test_init.h"
GBLREF io_pair io_std_device;
GBLREF mval dollar_zsource;
GBLREF mstr editor;
GBLREF int4 dollar_zeditor;
-error_def(ERR_FILENOTFND);
+error_def(ERR_NOEDITOR);
error_def(ERR_ZEDFILSPEC);
void op_zedit(mval *v, mval *p)
@@ -43,9 +45,9 @@ void op_zedit(mval *v, mval *p)
int objcnt;
int waitid;
unsigned int childid, status;
-#ifdef _BSD
+# ifdef _BSD
union wait wait_status;
-#endif
+# endif
bool has_ext, exp_dir;
parse_blk pblk;
mstr src;
@@ -54,12 +56,13 @@ void op_zedit(mval *v, mval *p)
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
+ geteditor();
if (!editor.len)
{
edt = GETENV("EDITOR");
if (!edt)
edt = "editor";
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_FILENOTFND, 2, LEN_AND_STR(edt));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_NOEDITOR, 2, LEN_AND_STR(edt));
}
MV_FORCE_STR(v);
MV_FORCE_STR(p);
@@ -117,7 +120,7 @@ void op_zedit(mval *v, mval *p)
src.addr = es;
src.len = path_len;
srcdir = (zro_ent *)0;
- zro_search(0, 0, &src, &srcdir, TRUE);
+ zro_search(NULL, NULL, &src, &srcdir, TRUE);
if (NULL == srcdir)
{ /* find the first source directory */
objcnt = (TREF(zro_root))->count;
@@ -184,7 +187,9 @@ void op_zedit(mval *v, mval *p)
setterm(io_std_device.in);
} else
{
+ if (WBTEST_ENABLED(WBTEST_BADEXEC_OP_ZEDIT))
+ STRCPY(editor.addr, "");
EXECL(editor.addr, editor.addr, es, 0);
- exit(-1);
+ _exit(-1);
}
}
diff --git a/sr_unix/op_zlink.c b/sr_unix/op_zlink.c
index ebc5c32..efd31d3 100644
--- a/sr_unix/op_zlink.c
+++ b/sr_unix/op_zlink.c
@@ -18,6 +18,9 @@
#include <errno.h>
#include "stringpool.h"
+#ifdef AUTORELINK_SUPPORTED
+# include "rtnhdr.h"
+#endif
#include "zroutines.h"
#include "cmd_qlf.h"
#include "parse_file.h"
@@ -27,12 +30,15 @@
#include "incr_link.h"
#include "compiler.h"
#ifdef __MVS__
-#include "gtm_zos_io.h"
+# include "gtm_zos_io.h"
#endif
-#define SRC 1
-#define OBJ 2
-#define NOTYPE 3
+typedef enum
+{
+ SRC = 1,
+ OBJ,
+ NOTYPE
+} linktyp;
/* On shared platforms, skip parameter should be FALSE to indicate an auto-ZLINK so that
* zro_search looks into shared libraries. On non-shared platforms, it should be
@@ -58,21 +64,47 @@
#elif defined(__hpux) && defined(__ia64)
# define st_nmtime st_nmtime
#endif
+/* Macro to close object file and give appropriate error */
+#define CLOSE_OBJECT_FD(FD, STATUS) \
+{ \
+ CLOSE_OBJECT_FILE(FD, STATUS); /* Resets "object_file_des" to FD_INVALID */ \
+ if (-1 == status) \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("close()"), CALLFROM, errno); \
+}
-#define CLOSE_OBJECT_FD(FD, STATUS) CLOSEFILE_RESET(FD, STATUS) /* resets "object_file_des" to FD_INVALID */
+#ifdef AUTORELINK_SUPPORTED
+# define CHECK_OBJECT_HISTORY(OBJPATH, OBJDIR, RECENT_ZHIST_PARM) \
+{ \
+ if (TREF(arlink_enabled) && !TREF(trigger_compile)) \
+ { /* Autorelink is enabled, this is not a trigger and we need a search history for the object file to pass \
+ * to incr_link(). We had to wait till this point to discover the search history since at the time of the \
+ * call to zro_search(), there may not have been an object file to find or, given where we found the source, \
+ * the object file we are linking now may be different from one found before so create the history array given \
+ * the supplied object file path and our $ZROUTINES directory array. \
+ * \
+ * Note we cannot assert RECENT_ZHIST_PARM is null here as we may be about to link a recompiled module after \
+ * a failed ZLINK but incr_link() took care of releasing the old history in its error path. \
+ */ \
+ RECENT_ZHIST_PARM = zro_search_hist(OBJPATH, &OBJDIR); \
+ } \
+}
+#else
+# define CHECK_OBJECT_HISTORY(OBJPATH, OBJDIR, RECENT_ZHIST_PARM)
+#endif
GBLREF spdesc stringpool;
GBLREF command_qualifier glb_cmd_qlf, cmd_qlf;
GBLREF mval dollar_zsource;
GBLREF int object_file_des;
-error_def(ERR_WILDCARD);
-error_def(ERR_VERSION);
error_def(ERR_FILENOTFND);
-error_def(ERR_ZLINKFILE);
-error_def(ERR_ZLNOOBJECT);
error_def(ERR_FILEPARSE);
+error_def(ERR_SYSCALL);
error_def(ERR_TEXT);
+error_def(ERR_VERSION);
+error_def(ERR_WILDCARD);
+error_def(ERR_ZLINKFILE);
+error_def(ERR_ZLNOOBJECT);
ZOS_ONLY(error_def(ERR_BADTAG);)
/* Routine to locate object files, or source and compile to an object file if necessary, and drive the linker to link the file
@@ -91,8 +123,8 @@ ZOS_ONLY(error_def(ERR_BADTAG);)
*/
void op_zlink (mval *v, mval *quals)
{
- int status, qlf, tslash;
- unsigned short type;
+ int status, qlf, tslash, save_errno;
+ linktyp type;
char srcnamebuf[MAX_FBUFF + 1], objnamebuf[MAX_FBUFF + 1], *fname;
uint4 objnamelen, srcnamelen;
char inputf[MAX_FBUFF + 1], obj_file[MAX_FBUFF + 1], list_file[MAX_FBUFF + 1],
@@ -103,17 +135,23 @@ void op_zlink (mval *v, mval *quals)
parse_blk pblk;
mval qualifier;
struct stat obj_stat, src_stat;
+ ARLINK_ONLY(zro_hist *recent_zhist;)
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
+ ARLINK_ONLY(recent_zhist = NULL);
MV_FORCE_STR(v);
- if (!v->str.len || (MAX_FBUFF < v->str.len))
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZLINKFILE, 2, v->str.len, v->str.addr);
+ if (!v->str.len)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZLINKFILE, 2, v->str.len, v->str.addr, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Filename/path is missing"));
+ if (MAX_FBUFF < v->str.len)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZLINKFILE, 2, v->str.len, v->str.addr, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Filename/path exceeds max length"));
object_file_des = FD_INVALID;
srcdir = objdir = NULL;
expdir = FALSE;
if (quals)
- { /* Explicit ZLINK */
+ { /* Explicit ZLINK from generated code or from gtm_trigger() */
memset(&pblk, 0, SIZEOF(pblk));
pblk.buff_size = MAX_FBUFF;
pblk.buffer = inputf;
@@ -147,13 +185,13 @@ void op_zlink (mval *v, mval *quals)
dollar_zsource.str.len = file.len;
stringpool.free += file.len;
if (OBJ == type)
- {
- memmove(objnamebuf,file.addr, file.len + pblk.b_ext);
+ { /* Object file extension specified */
+ memmove(objnamebuf, file.addr, file.len + pblk.b_ext);
objnamelen = file.len + pblk.b_ext;
assert (objnamelen <= MAX_FBUFF + 1);
objnamebuf[objnamelen] = 0;
} else if (SRC == type)
- {
+ { /* Non-object file extension specified */
memmove(srcnamebuf, file.addr,file.len + pblk.b_ext);
srcnamelen = file.len + pblk.b_ext;
assert (srcnamelen <= MAX_FBUFF + 1);
@@ -162,11 +200,11 @@ void op_zlink (mval *v, mval *quals)
if (pblk.b_name > MAX_MIDENT_LEN)
objnamelen = expdir ? (pblk.b_dir + MAX_MIDENT_LEN) : MAX_MIDENT_LEN;
memcpy(objnamebuf, file.addr, objnamelen);
- memcpy(&objnamebuf[objnamelen], DOTOBJ, SIZEOF(DOTOBJ));
+ memcpy(&objnamebuf[objnamelen], DOTOBJ, SIZEOF(DOTOBJ)); /* Copies null terminator */
objnamelen += STR_LIT_LEN(DOTOBJ);
assert (objnamelen + SIZEOF(DOTOBJ) <= MAX_FBUFF + 1);
} else
- {
+ { /* No file extension specified */
if ((file.len + SIZEOF(DOTM) > SIZEOF(srcnamebuf)) ||
(file.len + SIZEOF(DOTOBJ) > SIZEOF(objnamebuf)))
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZLINKFILE, 2, v->str.len, v->str.addr);
@@ -175,40 +213,40 @@ void op_zlink (mval *v, mval *quals)
srcnamelen = file.len + SIZEOF(DOTM) - 1;
assert (srcnamelen + SIZEOF(DOTM) <= MAX_FBUFF + 1);
memcpy(objnamebuf,file.addr,file.len);
- memcpy(&objnamebuf[file.len], DOTOBJ, SIZEOF(DOTOBJ));
+ memcpy(&objnamebuf[file.len], DOTOBJ, SIZEOF(DOTOBJ)); /* Copies null terminator */
objnamelen = file.len + SIZEOF(DOTOBJ) - 1;
assert (objnamelen + SIZEOF(DOTOBJ) <= MAX_FBUFF + 1);
}
if (!expdir)
- {
+ { /* No full or relative directory specified on file to link - fill it in */
srcstr.addr = srcnamebuf;
srcstr.len = srcnamelen;
objstr.addr = objnamebuf;
objstr.len = objnamelen;
if (OBJ == type)
- {
+ { /* Explicit ZLINK of object - don't locate source */
zro_search(&objstr, &objdir, NULL, NULL, SKIP_SHLIBS);
- if (!objdir)
+ if (NULL == objdir)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZLINKFILE, 2, dollar_zsource.str.len,
- dollar_zsource.str.addr, ERR_FILENOTFND,2, dollar_zsource.str.len,
- dollar_zsource.str.addr);
+ dollar_zsource.str.addr, ERR_FILENOTFND,2, dollar_zsource.str.len,
+ dollar_zsource.str.addr);
} else if (SRC == type)
- {
+ { /* Explicit ZLINK of source - locate both source and object*/
zro_search(&objstr, &objdir, &srcstr, &srcdir, SKIP_SHLIBS);
- if (!srcdir)
+ if (NULL == srcdir)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZLINKFILE, 2, srcnamelen, srcnamebuf,
- ERR_FILENOTFND, 2, srcnamelen, srcnamebuf);
+ ERR_FILENOTFND, 2, srcnamelen, srcnamebuf);
} else
- {
+ { /* Explicit ZLINK no file type specified - locate both source and object */
zro_search(&objstr, &objdir, &srcstr, &srcdir, PROBE_SHLIBS);
- if (!objdir && !srcdir)
+ if ((NULL == objdir) && (NULL == srcdir))
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZLINKFILE, 2, dollar_zsource.str.len,
- dollar_zsource.str.addr, ERR_FILENOTFND,2, dollar_zsource.str.len,
- dollar_zsource.str.addr);
+ dollar_zsource.str.addr, ERR_FILENOTFND,2, dollar_zsource.str.len,
+ dollar_zsource.str.addr);
}
}
} else
- { /* auto-ZLINK */
+ { /* auto-ZLINK for execution, ZBREAK, $TEXT(), or ZEDIT (i.e. non-specific call to op_zlink()) */
type = NOTYPE;
memcpy(srcnamebuf, v->str.addr, v->str.len);
memcpy(&srcnamebuf[v->str.len], DOTM, SIZEOF(DOTM));
@@ -216,56 +254,54 @@ void op_zlink (mval *v, mval *quals)
if ('%' == srcnamebuf[0])
srcnamebuf[0] = '_';
memcpy(objnamebuf, srcnamebuf, v->str.len);
- memcpy(&objnamebuf[v->str.len], DOTOBJ, SIZEOF(DOTOBJ));
+ memcpy(&objnamebuf[v->str.len], DOTOBJ, SIZEOF(DOTOBJ)); /* Copies null terminator */
objnamelen = v->str.len + SIZEOF(DOTOBJ) - 1;
srcstr.addr = srcnamebuf;
srcstr.len = srcnamelen;
objstr.addr = objnamebuf;
objstr.len = objnamelen;
zro_search(&objstr, &objdir, &srcstr, &srcdir, PROBE_SHLIBS);
- if (!objdir && !srcdir)
+ if ((NULL == objdir) && (NULL == srcdir))
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZLINKFILE, 2, v->str.len, v->str.addr,
- ERR_FILENOTFND, 2, v->str.len, v->str.addr);
+ ERR_FILENOTFND, 2, v->str.len, v->str.addr);
qualifier.mvtype = MV_STR;
qualifier.str = TREF(dollar_zcompile);
quals = &qualifier;
}
if (OBJ == type)
- {
+ { /* Object file extension specified */
if (objdir)
- {
+ { /* Object file found via zro_search() */
assert(ZRO_TYPE_OBJLIB != objdir->type);
if (objdir->str.len + objnamelen + 2 > SIZEOF(objnamebuf))
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZLINKFILE, 2, v->str.len, v->str.addr);
if (objdir->str.len)
{
tslash = ('/' == objdir->str.addr[objdir->str.len - 1]) ? 0 : 1;
- memmove(&objnamebuf[ objdir->str.len + tslash], objnamebuf, objnamelen);
+ memmove(&objnamebuf[objdir->str.len + tslash], objnamebuf, objnamelen);
if (tslash)
- objnamebuf[ objdir->str.len ] = '/';
+ objnamebuf[objdir->str.len] = '/';
memcpy(objnamebuf, objdir->str.addr, objdir->str.len);
objnamelen += objdir->str.len + tslash;
- objnamebuf[ objnamelen ] = 0;
+ objnamebuf[objnamelen] = 0;
}
}
OPEN_OBJECT_FILE(objnamebuf, O_RDONLY, object_file_des);
if (FD_INVALID == object_file_des)
+ /* Could not find object file */
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZLINKFILE, 2, dollar_zsource.str.len, dollar_zsource.str.addr,
- errno);
- if (IL_RECOMPILE == incr_link(object_file_des, NULL, objnamelen, objnamebuf))
+ errno);
+ /* Note - if explicit ZLINK, objdir can be NULL if link is from a directory not mentioned in $ZROUTINES */
+ CHECK_OBJECT_HISTORY(objnamebuf, objdir, RECENT_ZHIST);
+ if (IL_RECOMPILE == INCR_LINK(object_file_des, objdir, RECENT_ZHIST, objnamelen, objnamebuf))
{
- CLOSE_OBJECT_FD(object_file_des, status); /* No checking for error here as the priority error
- * right now is the version issue.
- */
+ CLOSE_OBJECT_FILE(object_file_des, status); /* Priority error is version issue so ignore any on close */
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZLINKFILE, 2, dollar_zsource.str.len, dollar_zsource.str.addr,
- ERR_VERSION);
+ ERR_VERSION);
}
CLOSE_OBJECT_FD(object_file_des, status);
- if (-1 == status)
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZLINKFILE, 2, dollar_zsource.str.len, dollar_zsource.str.addr,
- errno);
} else
- { /* either NO type or SOURCE type */
+ { /* Either NO file extension specified or is SOURCE file extension type */
cmd_qlf.object_file.str.addr = obj_file;
cmd_qlf.object_file.str.len = MAX_FBUFF;
cmd_qlf.list_file.str.addr = list_file;
@@ -273,31 +309,33 @@ void op_zlink (mval *v, mval *quals)
cmd_qlf.ceprep_file.str.addr = ceprep_file;
cmd_qlf.ceprep_file.str.len = MAX_FBUFF;
if (srcdir)
- {
+ { /* A source directory containing routine was found by zro_search() */
assert(ZRO_TYPE_OBJLIB != objdir->type);
if (srcdir->str.len + srcnamelen > SIZEOF(srcnamebuf) - 1)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZLINKFILE, 2, v->str.len, v->str.addr);
if (srcdir->str.len)
{
tslash = ('/' == srcdir->str.addr[srcdir->str.len - 1]) ? 0 : 1;
- memmove(&srcnamebuf[ srcdir->str.len + tslash ], srcnamebuf, srcnamelen);
+ memmove(&srcnamebuf[srcdir->str.len + tslash], srcnamebuf, srcnamelen);
if (tslash)
- srcnamebuf[ srcdir->str.len ] = '/';
+ srcnamebuf[srcdir->str.len] = '/';
memcpy(srcnamebuf, srcdir->str.addr, srcdir->str.len);
srcnamelen += srcdir->str.len + tslash;
- srcnamebuf[ srcnamelen ] = 0;
+ srcnamebuf[srcnamelen] = 0;
}
}
if (objdir)
- {
+ { /* An object directory or shared library containing the routine was found by zro_search() */
if (ZRO_TYPE_OBJLIB == objdir->type)
- {
+ { /* For object libraries, there are no auto-relink complications so no need to hunt down
+ * any history for it or to pass in any.
+ */
assert(objdir->shrlib);
assert(objdir->shrsym);
/* The incr_link() routine should drive errors for any issue found with linking from a shared
* library so IL_DONE is the only valid return code we *ever* expect back.
*/
- assertpro(IL_DONE == incr_link(0, objdir, objnamelen, objnamebuf));
+ assertpro(IL_DONE == INCR_LINK(0, objdir, NULL, objnamelen, objnamebuf));
return;
}
if (objdir->str.len + objnamelen > SIZEOF(objnamebuf) - 1)
@@ -305,17 +343,20 @@ void op_zlink (mval *v, mval *quals)
if (objdir->str.len)
{
tslash = ('/' == objdir->str.addr[objdir->str.len - 1]) ? 0 : 1;
- memmove(&objnamebuf[ objdir->str.len + tslash ], objnamebuf, objnamelen);
+ memmove(&objnamebuf[objdir->str.len + tslash], objnamebuf, objnamelen);
if (tslash)
- objnamebuf[ objdir->str.len ] = '/';
+ objnamebuf[objdir->str.len] = '/';
memcpy(objnamebuf, objdir->str.addr, objdir->str.len);
objnamelen += objdir->str.len + tslash;
- objnamebuf[ objnamelen ] = 0;
+ objnamebuf[objnamelen] = 0;
}
}
+ /* Check which source/object we ended up with and whether they are for the same file or not so we can determine if
+ * recompilation might be required.
+ */
src_found = obj_found = compile = FALSE;
if (SRC != type)
- {
+ { /* Object or NO file extension specified - check object file exists */
OPEN_OBJECT_FILE(objnamebuf, O_RDONLY, object_file_des);
if (FD_INVALID == object_file_des)
{
@@ -325,68 +366,82 @@ void op_zlink (mval *v, mval *quals)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZLINKFILE, 2, objnamelen, objnamebuf, errno);
} else
obj_found = TRUE;
- } else
+ } else /* If source file extension specified, force re-compile */
compile = TRUE;
- STAT_FILE(srcnamebuf, &src_stat, status);
+ STAT_FILE(srcnamebuf, &src_stat, status); /* Check if source file exists */
if (-1 == status)
{
if ((ENOENT == errno) && (SRC != type))
src_found = FALSE;
else
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZLINKFILE,2,srcnamelen,srcnamebuf,errno);
+ {
+ save_errno = errno;
+ if (FD_INVALID != object_file_des) /* Chose object file if open, ignore error */
+ CLOSE_OBJECT_FILE(object_file_des, status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZLINKFILE, 2, srcnamelen, srcnamebuf, save_errno);
+ }
} else
src_found = TRUE;
if (SRC != type)
- {
+ { /* If object or no file extension type specified, check if have both source and object and if so, decide
+ * if source needs to be recompiled.
+ */
if (src_found)
{
if (obj_found)
{
FSTAT_FILE(object_file_des, &obj_stat, status);
if (-1 == status)
+ {
+ save_errno = errno;
+ if (FD_INVALID != object_file_des) /* Close object file if open */
+ CLOSE_OBJECT_FILE(object_file_des, status);
rts_error_csa(CSA_ARG(NULL)VARLSTCNT(5) ERR_ZLINKFILE, 2, objnamelen, objnamebuf,
- errno);
+ save_errno);
+ }
if ((src_stat.st_mtime > obj_stat.st_mtime)
- || ((src_stat.st_mtime == obj_stat.st_mtime)
- && (src_stat.st_nmtime > obj_stat.st_nmtime)))
+ || ((src_stat.st_mtime == obj_stat.st_mtime)
+ && (src_stat.st_nmtime > obj_stat.st_nmtime)))
{
CLOSE_OBJECT_FD(object_file_des, status);
- if (-1 == status)
- rts_error_csa(CSA_ARG(NULL)VARLSTCNT(5) ERR_ZLINKFILE, 2, objnamelen,
- objnamebuf, errno);
compile = TRUE;
}
} else
+ {
compile = TRUE;
+ assert(FD_INVALID == object_file_des); /* Make sure closed */
+ }
} else if (!obj_found)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZLINKFILE, 2, objnamelen, objnamebuf,
- ERR_FILENOTFND, 2, objnamelen, objnamebuf);
+ ERR_FILENOTFND, 2, objnamelen, objnamebuf);
}
if (compile)
- {
+ { /* (Re)Compile source file */
zl_cmd_qlf(&quals->str, &cmd_qlf);
if (!MV_DEFINED(&cmd_qlf.object_file))
- {
+ { /* -object= parameter NOT specified - fill in default */
cmd_qlf.object_file.mvtype = MV_STR;
cmd_qlf.object_file.str.addr = objnamebuf;
cmd_qlf.object_file.str.len = objnamelen;
}
qlf = cmd_qlf.qlf;
- if (!(cmd_qlf.qlf & CQ_OBJECT) && (SRC != type))
+ if (!(qlf & CQ_OBJECT) && (SRC != type))
{
cmd_qlf.qlf = glb_cmd_qlf.qlf;
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZLINKFILE, 2, srcnamelen, srcnamebuf, ERR_ZLNOOBJECT);
}
zlcompile(srcnamelen, (uchar_ptr_t)srcnamebuf);
+ assert(FD_INVALID == object_file_des); /* zlcompile() should have driven obj_code() which closes object */
if ((SRC == type) && !(qlf & CQ_OBJECT))
return;
+ OPEN_OBJECT_FILE(objnamebuf, O_RDONLY, object_file_des);
}
- status = incr_link(object_file_des, objdir, objnamelen, objnamebuf);
+ assert(FD_INVALID != object_file_des); /* Object file should be open at this point */
+ CHECK_OBJECT_HISTORY(objnamebuf, objdir, RECENT_ZHIST);
+ status = INCR_LINK(object_file_des, objdir, RECENT_ZHIST, objnamelen, objnamebuf);
if (IL_RECOMPILE == status)
- { /* due only to version mismatch, so recompile */
+ { /* Failure due only to version mismatch, so recompile */
CLOSE_OBJECT_FD(object_file_des, status);
- if (-1 == status)
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZLINKFILE, 2, objnamelen, objnamebuf, errno);
assertpro(!compile);
if (!src_found)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZLINKFILE, 2, srcnamelen, srcnamebuf, ERR_VERSION);
@@ -403,15 +458,16 @@ void op_zlink (mval *v, mval *quals)
cmd_qlf.qlf = glb_cmd_qlf.qlf;
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZLINKFILE, 2, srcnamelen, srcnamebuf, ERR_ZLNOOBJECT);
}
+ assert(FD_INVALID == object_file_des); /* zlcompile() should have driven obj_code() which closes it */
+ OPEN_OBJECT_FILE(objnamebuf, O_RDONLY, object_file_des);
+ CHECK_OBJECT_HISTORY(objnamebuf, objdir, RECENT_ZHIST);
/* We just did a fresh re-compile a few lines above so IL_DONE is the only return code we ever
* expect to see back. Only a race-condition created by a different version overlaying the newly
* created object file could conceivably cause an IL_RECOMPILE code here (incr_link handles all
* the other errors itself). Not at this time considered worthy of special coding.
*/
- assertpro(IL_DONE == incr_link(object_file_des, objdir, objnamelen, objnamebuf));
+ assertpro(IL_DONE == INCR_LINK(object_file_des, objdir, RECENT_ZHIST, objnamelen, objnamebuf));
}
CLOSE_OBJECT_FD(object_file_des, status);
- if (-1 == status)
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZLINKFILE, 2, objnamelen, objnamebuf, errno);
}
}
diff --git a/sr_unix/op_zrupdate.c b/sr_unix/op_zrupdate.c
index e478dac..939e691 100644
--- a/sr_unix/op_zrupdate.c
+++ b/sr_unix/op_zrupdate.c
@@ -19,39 +19,59 @@
#include "gtm_stat.h"
#include "gtm_stdlib.h"
+#include "gtmio.h"
#include "io.h"
#include "iosp.h"
#include <rtnhdr.h>
#include "relinkctl.h"
-#include "zhist.h"
#include "parse_file.h"
#include "eintr_wrappers.h"
#include "error.h"
#include "min_max.h"
#include "op.h"
#include "op_fnzsearch.h"
+#include "interlock.h"
+#include "toktyp.h"
+#include "valid_mname.h"
+#ifdef DEBUG
+# include "toktyp.h" /* Needed for "valid_mname.h" */
+#endif
+#define DOTOBJEXT ".o"
#define OBJEXT 'o'
#define WILDCARD '*'
+LITREF mval literal_null;
-#ifndef USHBIN_SUPPORTED
+error_def(ERR_FILEPARSE);
+error_def(ERR_PARNORMAL);
+error_def(ERR_TEXT);
+
+#ifndef AUTORELINK_SUPPORTED
/* Stub routine for unsupported platforms */
void op_zrupdate(int argcnt, ...)
{
return;
}
#else
-/************************************************************/
-
-LITREF mval literal_null;
-
-error_def(ERR_FILEPARSE);
-error_def(ERR_PARNORMAL);
-error_def(ERR_TEXT);
-
-/*
- * TODO: Add description of syntax/operation
+/* The ZRUPDATE command drives this routine once through for each argument (object file path and object file - potentially
+ * containing wildcards). Each file specified, or found in a wildcard search, is separated into its path and its routine
+ * name, the path is looked up and the appropriate relinkctl file opened where we lookup the routine name and bump its cycle.
+ *
+ * Although this routine is setup to handle a variable argument list, more than 1 argument is not currently supported. The
+ * ZRUPDATE command itself does support a commented list of filespecs but the compiler turns each argument into a separate
+ * call to this routine. The purpose of the variable argument list is to support a future proposed enhancement which would
+ * allow a ZRUPDATE argument to be a parenthesized list of filespecs with the intention all of them are simultaneously
+ * updated. Such a list, when supported would be passed as a list of files to this routine - hence the multi-arg support.
+ *
+ * To get a consistent view of each directory, the directory is run through realpath() to resolve soft links and normalize the
+ * directory name consistently.
+ *
+ * Parameters:
+ * argcnt - currently always 1 (see note above).
+ * objfilespec - mval address holding string containing filespec to process.
+ *
+ * No return value.
*/
void op_zrupdate(int argcnt, ...)
@@ -59,16 +79,17 @@ void op_zrupdate(int argcnt, ...)
mval *objfilespec;
va_list var;
mval objpath;
- char tranbuf[MAX_FBUFF + 1], *chptr;
+ char tranbuf[MAX_FBUFF + 1], *chptr, chr;
open_relinkctl_sgm *linkctl;
- relinkrec_loc_t rec;
+ relinkrec_t *rec;
plength plen;
- int status, fextlen;
+ int status, fextlen, fnamlen, fcnt;
parse_blk pblk;
struct stat outbuf;
int stat_res;
- boolean_t seenfext, seenwildcard;
+ boolean_t seenfext, fileexists;
mstr objdir, rtnname;
+ uint4 hash, prev_hash_index;
/* Currently only expecting one value per invocation right now. That will change in phase 2 hence the stdarg setup */
va_start(var, argcnt);
@@ -76,50 +97,103 @@ void op_zrupdate(int argcnt, ...)
objfilespec = va_arg(var, mval *);
va_end(var);
MV_FORCE_STR(objfilespec);
- /* First some pre-processing to determine if an explicit file type was specified. If so, it must be ".o" for this
- * phase of implementation. Later phases may allow ".m" to be specified but not initially. Use parse_file() to
+ /* First some pre-processing to determine if an explicit file name or type was specified. If so, it must be ".o" for
+ * this phase of implementation. Later phases may allow ".m" to be specified but not initially. Use parse_file() to
* parse everything out and isolate any extention.
*/
memset(&pblk, 0, SIZEOF(pblk));
pblk.buffer = tranbuf;
- pblk.buff_size = (unsigned char)(MAX_FBUFF);
- pblk.fnb = 0;
+ pblk.buff_size = (unsigned char)(MAX_FBUFF); /* Pass size of buffer - 1 (standard protocol for parse_file) */
+ pblk.def1_buf = DOTOBJEXT; /* Default .o file type if not specified */
+ pblk.def1_size = SIZEOF(DOTOBJEXT) - 1;
+ pblk.fop = F_SYNTAXO; /* Syntax check only - bypass directory existence check */
status = parse_file(&objfilespec->str, &pblk);
if (ERR_PARNORMAL != status)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_FILEPARSE, 2, objfilespec->str.len, objfilespec->str.addr, status);
+ tranbuf[pblk.b_esl] = '\0'; /* Needed for subsequent STAT_FILE */
+ seenfext = FALSE;
if (0 != pblk.b_ext)
{ /* If a file extension was specified - get the extension sans any potential wildcard character */
- seenfext = seenwildcard = FALSE;
for (chptr = pblk.l_ext + 1, fextlen = pblk.b_ext - 1; 0 < fextlen; chptr++, fextlen--)
{ /* Check each character in the extension except first which is the dot if ext exists at all */
if (WILDCARD != *chptr)
{ /* We see a char that isn't a wildcard character. If we've already seen our "o" file extension,
* this char makes our requirement filetype impossible so raise an error.
- * TODO - more appropriate error
*/
if (seenfext || (OBJEXT != *chptr))
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_FILEPARSE, 2, objfilespec->str.len,
- objfilespec->str.addr);
- seenfext = TRUE; /* No return from rts_error() above so this is our object file type */
- } else
- seenwildcard = TRUE;
+ /* No return from this error */
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_FILEPARSE,
+ 2, objfilespec->str.len, objfilespec->str.addr,
+ ERR_TEXT, 2, RTS_ERROR_TEXT("Unsupported filetype specified"));
+ seenfext = TRUE;
+ }
+ }
+ }
+ /* Do a simlar check for the file type */
+ if (0 != pblk.b_name)
+ { /* A file name was specified (if not, tiz probably hard to find the file but that can be dealt with later).
+ * Like in the above, the name must be comprised of valid chars for routine names.
+ */
+ for (chptr = pblk.l_name, fnamlen = pblk.b_name; 0 < fnamlen; chptr++, fnamlen--)
+ {
+ if (WILDCARD != *chptr)
+ { /* Substitute '%' for '_'. While this substitution is really only valid on the first char, only the
+ * first char check allows "%" so a 2nd or later char check would fail the '%' substitution anyway.
+ */
+ chr = ('_' == *chptr) ? '%' : *chptr;
+ /* We see a char that isn't a wildcard character. If this is the first character, it can be
+ * alpha or percent. If the second or later character, it can be alphanumeric.
+ */
+ if (((fnamlen != pblk.b_name) && !VALID_MNAME_NFCHAR(chr)) /* 2nd char or later check */
+ || ((fnamlen == pblk.b_name) && !VALID_MNAME_FCHAR(chr))) /* 1st char check */
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_FILEPARSE,
+ 2, objfilespec->str.len, objfilespec->str.addr,
+ ERR_TEXT, 2, RTS_ERROR_TEXT("Filename is not a valid routine name"));
+ }
+ }
}
}
/* When specifying a non-wildcarded object file, it is possible for the file to have been removed, in which case we still
* need to update its relinkctl entry (if exists) to notify other processes about the object's deletion.
- * TODO: should this see if given object exists in relinkctl file? If not, should it error or just ignore?
*/
- if (!seenwildcard & seenfext)
- {
+ if (!(pblk.fnb & F_WILD) & seenfext)
+ { /* If no wildcards in path and saw the extension we want - no need to wash through zsearch() */
objdir.addr = pblk.l_dir;
objdir.len = pblk.b_dir;
linkctl = relinkctl_attach(&objdir); /* Create/attach/open relinkctl file */
- if (NULL == linkctl)
- return; /* Path doesn't exist - ignore */
- rtnname.len = MIN(MAX_MIDENT_LEN, pblk.b_name); /* Avoid overflow */
+ if (NULL == linkctl) /* Non-existant path and no associated relinkctl file */
+ /* Note this reference to errno depends on nothing in relinkctl_attach() doing anything to modify
+ * errno after the realpath() call. No return from this error.
+ */
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_FILEPARSE, 2, objfilespec->str.len, objfilespec->str.addr,
+ errno);
+ /* What we do at this point depends on the following conditions:
+ *
+ * 1) If the specified file exists, we can add it to relinkctl file and/or update its cycle.
+ * 2) If the file doesn't exist on disk but the routine is found in the relinkctl file, update cycle.
+ * 3) If no file and no entry, just ignore it and do nothing (info error removed by request).
+ */
+ STAT_FILE(tranbuf, &outbuf, stat_res);
+ if (-1 == stat_res)
+ {
+ if (ENOENT != errno)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_FILEPARSE, 2, objfilespec->str.len,
+ objfilespec->str.addr, errno);
+ fileexists = FALSE;
+ } else
+ fileexists = TRUE;
+ rtnname.len = pblk.b_name;
rtnname.addr = pblk.l_name;
+ CONVERT_FILENAME_TO_RTNNAME(rtnname); /* Set rtnname right before searching in relinkctl file */
+ assert(valid_mname(&rtnname));
+ COMPUTE_RELINKCTL_HASH(&rtnname, hash);
+ rec = relinkctl_find_record(linkctl, &rtnname, hash, &prev_hash_index);
+ if ((NULL == rec) && !fileexists)
+ return; /* No file and no entry - ignore */
+ /* Either the file exists or the entry exists so add or update it */
rec = relinkctl_insert_record(linkctl, &rtnname);
- RELINKCTL_CYCLE_INCR(linkctl, rec); /* Increment cycle indicating change to world */
+ RELINKCTL_CYCLE_INCR(rec, linkctl); /* Increment cycle indicating change to world */
return;
}
/* If we have a wildcarded request or one without the object filetype, reprocess the string with $ZSEARCH using our
@@ -127,35 +201,57 @@ void op_zrupdate(int argcnt, ...)
* any file that doesn't have a ".o" extension.
*/
op_fnzsearch((mval *)&literal_null, STRM_ZRUPDATE, 0, &objpath); /* Clear any existing cache */
- while(TRUE)
+ for (fcnt = 0; ; fcnt++)
{
plen.p.pint = op_fnzsearch(objfilespec, STRM_ZRUPDATE, 0, &objpath);
if (0 == objpath.str.len)
- /* End of file list */
+ { /* End of file list */
+ if (0 == fcnt)
+ /* Still looking to process our first file - give no objects found message as a "soft" message
+ * (INFO level message - supressed in other than direct mode)
+ */
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) MAKE_MSG_INFO(ERR_FILEPARSE), 2, objfilespec->str.len,
+ objfilespec->str.addr, ERR_TEXT, 2, RTS_ERROR_TEXT("No object files found"));
break;
+ }
/* The extension contains the extension-start character ('.') so we are looking for the extension '.o' hence
* the length must be 2 and the 2nd char must be OBJEXT.
*/
if ((2 == plen.p.pblk.b_ext) && (OBJEXT == *(objpath.str.addr + plen.p.pblk.b_dir + plen.p.pblk.b_name + 1)))
- { /* This is (probably) an object file. Double check file is a file and not a directory */
+ { /* This is (probably) an object file. Double check file is a file and not a directory */
memcpy(tranbuf, objpath.str.addr, objpath.str.len); /* Need null terminated version for STAT */
- tranbuf[objpath.str.len] = '\0';
+ tranbuf[objpath.str.len] = '\0'; /* Not guaranteed null termination from op_fnzsearch */
STAT_FILE(tranbuf, &outbuf, stat_res);
/* If either something happened to the file since op_fnzsearch() saw it or the file is not a file, then
* ignore it.
*/
if ((-1 == stat_res) || !S_ISREG(outbuf.st_mode))
+ {
+ fcnt--; /* Don't count files not found for whatever reason */
continue;
+ }
+ /* Before opening the relinkctl file, verify we actually do have a valid routine name */
+ rtnname.len = plen.p.pblk.b_name;
+ rtnname.addr = objpath.str.addr + plen.p.pblk.b_dir;
+ CONVERT_FILENAME_TO_RTNNAME(rtnname); /* Set rtnname right before searching in relinkctl file */
+ if (!valid_mname(&rtnname))
+ {
+ fcnt--;
+ continue; /* Ignore files that are invalid wildcard matches */
+ }
objdir.addr = objpath.str.addr;
objdir.len = plen.p.pblk.b_dir;
linkctl = relinkctl_attach(&objdir); /* Create/attach/open relinkctl file */
if (NULL == linkctl)
- continue; /* Path disappeared - ignore */
- rtnname.len = MIN(MAX_MIDENT_LEN, plen.p.pblk.b_name); /* Avoid overflow */
- rtnname.addr = objpath.str.addr + plen.p.pblk.b_dir;
+ {
+ fcnt--; /* Path disappeared - don't count it */
+ continue;
+ }
rec = relinkctl_insert_record(linkctl, &rtnname);
- RELINKCTL_CYCLE_INCR(linkctl, rec); /* Increment cycle indicating change to world */
- }
+ RELINKCTL_CYCLE_INCR(rec, linkctl); /* Increment cycle indicating change to world */
+ } else
+ fcnt--; /* Don't count ignored files */
+
}
}
-#endif /* USHBIN_SUPPORTED */
+#endif /* AUTORELINK_SUPPORTED */
diff --git a/sr_unix/open_object_file.c b/sr_unix/open_object_file.c
deleted file mode 100644
index 6e35c42..0000000
--- a/sr_unix/open_object_file.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/****************************************************************
- * *
- * Copyright 2013, 2014 Fidelity Information Services, Inc *
- * *
- * This source code contains the intellectual property *
- * of its copyright holder(s), and is made available *
- * under a license. If you do not know the terms of *
- * the license, please stop and do not read further. *
- * *
- ****************************************************************/
-
-#include "mdef.h"
-
-#include <sys/types.h>
-#include "gtm_stat.h"
-#include "gtm_stdlib.h"
-#include "gtm_string.h"
-#include "gtm_limits.h"
-
-#include "cmd_qlf.h"
-#include "gtmio.h"
-#include "parse_file.h"
-
-GBLDEF char tmp_object_file_name[MAX_FBUFF + 1];
-
-GBLREF command_qualifier cmd_qlf;
-GBLREF char object_file_name[];
-GBLREF short object_name_len;
-GBLREF mident module_name;
-
-error_def(ERR_FILEPARSE);
-error_def(ERR_OBJFILERR);
-
-/* Open object file - TODO: make into macro instead of routine */
-int open_object_file(const char *fname, int fflag)
-{
- int fdesc;
-
- OPENFILE3(fname, fflag, 0666, fdesc);
- return fdesc;
-}
-
-/* TODO - Move these routines to obj_file.c */
-/* Routine to create a temporary object file. This file is created in the directory it is supposed to reside in but is created
- * with a temporary name. When complete, it is renamed to what it was meant to be replacing the previous version.
- *
- * Parameters:
- *
- * object_fname - Character array of the object path/name.
- * object_fname_len - Length of that array in bytes.
- *
- * Output:
- * File descriptor for the open object file.
- */
-int mk_tmp_object_file(const char *object_fname, int object_fname_len)
-{
- int fdesc, status;
- int umask_creat, umask_orig;
-
- /* TODO Verify addition of XXXXXX doesn't exceed dimensions of array */
- memcpy(tmp_object_file_name, object_fname, object_fname_len);
- memcpy(&tmp_object_file_name[object_fname_len], "XXXXXX", 7); /* Includes null terminator */
- fdesc = mkstemp(tmp_object_file_name);
- if (FD_INVALID == fdesc)
- {
- printf("tmp_object_file_name: %s\n", tmp_object_file_name);
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_OBJFILERR, 2, object_fname_len, object_fname, errno);
- }
- umask_orig = umask(000); /* Determine umask (destructive) */
- (void)umask(umask_orig); /* Reset umask */
- umask_creat = 0666 & ~umask_orig;
- /* TODO: set protections appropriately (if this isn't it) */
- FCHMOD(fdesc, umask_creat);
- return fdesc;
-}
-
-void rename_tmp_object_file(const char *object_fname)
-{
- rename(tmp_object_file_name, object_fname); /* TODO - Handle error (SEE) and make into macro instead of routine */
-}
-
-/*
- * Inputs: cmd_qlf.object_file, module_name
- * Outputs: object_file_name, object_name_len
- */
-void init_object_file_name(void)
-{
- int status, rout_len;
- char obj_name[SIZEOF(mident_fixed) + 5];
- mstr fstr;
- parse_blk pblk;
-
- memset(&pblk, 0, SIZEOF(pblk));
- pblk.buffer = object_file_name;
- pblk.buff_size = MAX_FBUFF;
-
- /* Create the object file */
- fstr.len = (MV_DEFINED(&cmd_qlf.object_file) ? cmd_qlf.object_file.str.len : 0);
- fstr.addr = cmd_qlf.object_file.str.addr;
- rout_len = (int)module_name.len;
- memcpy(&obj_name[0], module_name.addr, rout_len);
- memcpy(&obj_name[rout_len], DOTOBJ, SIZEOF(DOTOBJ)); /* includes null terminator */
- pblk.def1_size = rout_len + SIZEOF(DOTOBJ) - 1; /* Length does not include null terminator */
- pblk.def1_buf = obj_name;
- status = parse_file(&fstr, &pblk);
- if (0 == (status & 1))
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_FILEPARSE, 2, fstr.len, fstr.addr, status);
-
- object_name_len = pblk.b_esl;
- object_file_name[object_name_len] = '\0';
-}
diff --git a/sr_unix/parse_file.h b/sr_unix/parse_file.h
index 0dffb0d..f05a9b4 100644
--- a/sr_unix/parse_file.h
+++ b/sr_unix/parse_file.h
@@ -54,8 +54,8 @@ typedef struct plength_struct
#define F_HAS_DIR 4 /* 0x04 If file has explicit directory path */
#define F_WILD_NAME 8 /* 0x08 If there is a wild card character in the name */
#define F_WILD_DIR 16 /* 0x10 If there is a wild card character in the directory */
-#define F_WILD 24 /* 0x20 If there is a wild card character in the result */
-#define F_HAS_NODE 32 /* 0x40 If there is a node specification on the front - db opening only */
+#define F_WILD 24 /* 0x18 If there is a wild card character in the result (dir or name) */
+#define F_HAS_NODE 32 /* 0x20 If there is a node specification on the front - db opening only */
#define V_HAS_EXT 0 /* Bit offsets for F_ constants */
#define V_HAS_NAME 1
@@ -64,7 +64,9 @@ typedef struct plength_struct
#define V_WILD_DIR 4
#define V_HAS_NODE 5 /* DB opening only */
-#define F_SYNTAXO 1 /* SYNTAX ONLY */
+#define F_SYNTAXO 1 /* SYNTAX ONLY - Otherwise checks on directory existence returning ERR_FILENOTFOUND if
+ * directory does not exist or is not a directory.
+ */
#define F_PARNODE 2 /* Look for a node specification - db opening only */
int4 parse_file(mstr *file, parse_blk *pblk);
diff --git a/sr_port/md5_digest2hex.h b/sr_unix/probecrit_rec.h
similarity index 53%
rename from sr_port/md5_digest2hex.h
rename to sr_unix/probecrit_rec.h
index fe3322c..d1f29ae 100644
--- a/sr_port/md5_digest2hex.h
+++ b/sr_unix/probecrit_rec.h
@@ -9,13 +9,20 @@
* *
****************************************************************/
-#ifndef MD5_DIGEST2HEX_INCLUDED
-#define MD5_DIGEST2HEX_INCLUDED
+#ifndef PROBECRIT_REC_H_INCLUDED
+#define PROBECRIT_REC_H_INCLUDED
+#define TAB_PROBECRIT_REC(A,B,C) A,
+enum probecrit_rec_type
+{
+# include "tab_probecrit_rec.h"
+ n_probecrit_rec_types
+};
+#undef TAB_PROBECRIT_REC
-#include "md5hash.h"
-
-#define MD5_HEXSTR_LENGTH 33
-
-void md5_digest2hex(char hexstr[MD5_HEXSTR_LENGTH], const unsigned char digest[MD5_DIGEST_LENGTH]);
-
-#endif /* MD5_DIGEST2HEX_INCLUDED */
+typedef struct probecrit_rec_struct
+{
+# define TAB_PROBECRIT_REC(A,B,C) gtm_uint64_t A;
+# include "tab_probecrit_rec.h"
+} probecrit_rec_t;
+#undef TAB_PROBECRIT_REC
+#endif
diff --git a/sr_unix/rel_latch.c b/sr_unix/rel_latch.c
new file mode 100644
index 0000000..6cfa572
--- /dev/null
+++ b/sr_unix/rel_latch.c
@@ -0,0 +1,31 @@
+/****************************************************************
+ * *
+ * Copyright 2014 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#ifdef DEBUG
+#include "gtm_unistd.h" /* for "getpid" */
+#endif
+
+#include "interlock.h"
+
+GBLREF volatile int4 fast_lock_count; /* Stop interrupts while we have our parts exposed */
+GBLREF uint4 process_id;
+
+/* Grab a latch. If cannot get it, return FALSE, else TRUE. */
+void rel_latch(sm_global_latch_ptr_t latch)
+{
+ ++fast_lock_count; /* Disable interrupts (i.e. wcs_stale) for duration to avoid potential deadlocks */
+ assert(process_id == getpid()); /* make sure "process_id" global variable is reliable (used below in RELEASE_SWAPLOCK) */
+ RELEASE_SWAPLOCK(latch);
+ --fast_lock_count;
+ assert(0 <= fast_lock_count);
+}
diff --git a/sr_unix/relinkctl.c b/sr_unix/relinkctl.c
index 3ea1596..9cb1429 100644
--- a/sr_unix/relinkctl.c
+++ b/sr_unix/relinkctl.c
@@ -13,6 +13,9 @@
#include <sys/mman.h>
#include <sys/types.h>
+#include <sys/shm.h>
+
+#include "gtm_ipc.h"
#include "gtm_limits.h"
#include "gtm_fcntl.h"
#include "gtm_unistd.h"
@@ -26,31 +29,46 @@
#include "gtmio.h"
#include <rtnhdr.h>
#include "relinkctl.h"
-#include "zhist.h"
-#include "md5hash.h"
-#include "md5_digest2hex.h"
-#include "stringpool.h"
-
-/*
- * This module contains routines that maintain autorelink 'relinkctl' structures.
+#include "mmrhash.h"
+#include "iosp.h"
+#include "do_shmat.h"
+#include "hashtab.h"
+#include "ipcrmid.h"
+#include "eintr_wrappers.h"
+#include "stack_frame.h"
+#ifdef DEBUG
+# include "wbox_test_init.h"
+# include "toktyp.h" /* needed by "valid_mname.h" */
+# include "valid_mname.h"
+#endif
+#include "arlinkdbg.h"
+#include "min_max.h"
+#include "rtnobj.h"
+#include "gtmmsg.h"
+#include "hugetlbfs_overrides.h" /* for the ADJUST_SHM_SIZE_FOR_HUGEPAGES macro */
+#include "gtm_permissions.h"
+
+/* This module contains routines that maintain autorelink 'relinkctl' structures.
* TODO - add description
*/
DEBUG_ONLY(GBLDEF int saved_errno;)
-GBLREF uint4 process_id;
+GBLREF uint4 process_id;
+GBLREF rtn_tabent *rtn_names, *rtn_names_end;
+GBLREF stack_frame *frame_pointer;
+OS_PAGE_SIZE_DECLARE
-STATICFNDCL void relinkctl_map(open_relinkctl_sgm *linkctl, uint4 n_records);
+STATICFNDCL void relinkctl_map(open_relinkctl_sgm *linkctl);
STATICFNDCL void relinkctl_unmap(open_relinkctl_sgm *linkctl);
-STATICFNDCL uint4 relinkctl_recs2map(uint4 n_records);
STATICFNDCL int relinkctl_fcntl_lock(int fd, int l_type);
-STATICFNDCL void relinkctl_get_key(char key[GTM_PATH_MAX], mstr *zro_entry_name);
STATICFNDCL void relinkctl_delete(open_relinkctl_sgm *linkctl);
-#define ISSUE_RELINKCTLERR_SYSCALL(ZRO_ENTRY_NAME, LIBCALL) \
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_RELINKCTLERR, 2, RTS_ERROR_MSTR(ZRO_ENTRY_NAME), \
- ERR_SYSCALL, 5, LEN_AND_STR(LIBCALL), CALLFROM, DEBUG_ONLY(saved_errno = )errno)
-
+error_def(ERR_PERMGENFAIL);
error_def(ERR_RELINKCTLERR);
+error_def(ERR_RELINKCTLFULL);
+error_def(ERR_REQRLNKCTLRNDWN);
+error_def(ERR_RLNKCTLRNDWNFL);
+error_def(ERR_RLNKCTLRNDWNSUC);
error_def(ERR_SYSCALL);
error_def(ERR_TEXT);
@@ -65,19 +83,20 @@ error_def(ERR_TEXT);
open_relinkctl_sgm *relinkctl_attach(mstr *obj_container_name)
{
open_relinkctl_sgm *linkctl, *new_link;
- int len, save_errno;
+ int i, len, save_errno;
mstr objdir;
char pathin[GTM_PATH_MAX], resolvedpath[GTM_PATH_MAX]; /* Includes null terminator char */
char *pathptr;
boolean_t pathfound;
+ char relinkctl_path[GTM_PATH_MAX], *ptr;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
-# ifdef USHBIN_SUPPORTED
+# ifdef AUTORELINK_SUPPORTED
/* Directory name normalization - the directory name must always be the same for purposes of mapping the relinkctl
* file. To accomplish this takes two steps:
* 1. Use realpath() on the directory name to disambiguate it.
- * 2. Remove trailing slash(es) in the object directory name.
+ * 2. Remove trailing slash(es) so the object directory name.
*/
pathfound = TRUE; /* Assume we'll find the path */
assert(GTM_PATH_MAX > obj_container_name->len); /* Should have been checked by our caller */
@@ -86,28 +105,54 @@ open_relinkctl_sgm *relinkctl_attach(mstr *obj_container_name)
pathptr = realpath(pathin, resolvedpath);
if (NULL == pathptr)
{
- pathfound = FALSE; /* Path no longer exists - use our best attempt to find it */
- pathptr = pathin;
+ if (ENOENT == (save_errno = errno)) /* Note assignment */
+ {
+ pathfound = FALSE; /* Path no longer exists - use our best attempt to find it */
+ pathptr = pathin;
+ } else
+ /* This error is appropriate here as the directory was checked in the caller before coming here
+ * so this error is "just-in-case".
+ */
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("realpath()"), CALLFROM,
+ save_errno);
}
objdir.addr = pathptr;
objdir.len = strlen(pathptr);
+ assert(objdir.len < ARRAYSIZE(resolvedpath));
while ((1 < objdir.len) && ('/' == *(objdir.addr + objdir.len - 1)))
objdir.len--;
- /* Now look the directory up in our list to see if we have it or not already */
+ /* Now look the directory up in our list to see if we have it or not already*/
for (linkctl = TREF(open_relinkctl_list); NULL != linkctl; linkctl = linkctl->next)
{
if (MSTR_EQ(&objdir, &linkctl->zro_entry_name))
return linkctl;
}
- /* If realpath() didn't find the path and we don't already have it open, don't create a relinkctl file for it */
+ /* If realpath() didn't find the path and we don't already have it open, don't create a relinkctl file for it. Note if
+ * the caller is op_zrupdate(), very shortly we are going to try to use the errno value set above in realpath(). If
+ * anything gets added to this module between the realpath() above and here, a different mechanism for passing errno
+ * needs to be found.
+ */
if (!pathfound)
return NULL;
/* Not already open */
- new_link = malloc(SIZEOF(open_relinkctl_sgm));
- new_link->zro_entry_name = objdir;
- s2pool(&new_link->zro_entry_name); /* Migrate string to stringpool for safe keeping */
+ len = relinkctl_get_key(relinkctl_path, &objdir) + 1; /* + 1 for trailing null in relinkctl_path */
+ assert(len <= ARRAYSIZE(relinkctl_path));
+ new_link = malloc(SIZEOF(open_relinkctl_sgm) + objdir.len + 1 + len); /* + 1 for trailing null in zro_entry_name */
+ memset(new_link, 0, SIZEOF(open_relinkctl_sgm));
+ new_link->zro_entry_name.len = objdir.len;
+ new_link->zro_entry_name.addr = ptr = (char *)(new_link + 1);
+ memcpy(ptr, objdir.addr, objdir.len);
+ ptr += objdir.len;
+ *ptr++ = '\0'; /* trailing null for "new_link->zro_entry_name" */
+ new_link->relinkctl_path = ptr;
+ memcpy(ptr, relinkctl_path, len);
+ assert('\0' == new_link->relinkctl_path[len - 1]);
+ for (i = 0; i < NUM_RTNOBJ_SHM_INDEX; i++)
+ new_link->rtnobj_shmid[i] = INVALID_SHMID;
/* Open + map structure */
- relinkctl_open(new_link);
+ relinkctl_open(new_link); /* initializes new_link->fd, new_link->hdr, new_link->n_records,
+ * new_link->rec_base, new_link->shm_hashbase and new_link->locked
+ */
/* Add to open list */
new_link->next = TREF(open_relinkctl_list);
TREF(open_relinkctl_list) = new_link;
@@ -115,169 +160,362 @@ open_relinkctl_sgm *relinkctl_attach(mstr *obj_container_name)
# else
return NULL;
# endif
-
}
-/*
- * Given linkctl->zro_entry_name -- an object directory in $ZROUTINES -- open() and mmap() relink ctl structure, thus
- * filling in linkctl->fd and linkctl->hdr.
+/* Routine to open and mmap a relinkctl file for a given $ZROUTINES object directory.
+ *
+ * Parameter:
+ * linkctl - open_relinkctl_sgm (process private) block describing shared (mmap'd) entry and supplying the path/name
+ * of the relinkctl file comprised of both static and hashed directory name values for uniqueness.
+ *
+ * Returns:
+ * Various fields in linkctl (fd, hdr).
+ *
* The control structure should be both readable *and* writable by anything that can read the object directory.
*/
void relinkctl_open(open_relinkctl_sgm *linkctl)
{
- int fd, status, save_errno;
- int umask_creat, umask_orig;
- char relinkctl_path[GTM_PATH_MAX];
- struct stat stat_buf;
+# ifdef AUTORELINK_SUPPORTED
+ int fd, i, j, rc, save_errno, shmid, status, retries;
+ struct stat stat_buf;
+ size_t shm_size;
+ boolean_t is_mu_rndwn_rlnkctl, shm_removed;
+ relinkshm_hdr_t *shm_base;
+ rtnobjshm_hdr_t *rtnobj_shm_hdr;
+ relinkctl_data *hdr;
+ char errstr[256];
+ struct stat dir_stat_buf;
+ int stat_res;
+ int user_id;
+ int group_id;
+ int perm;
+ struct perm_diag_data pdd;
+ struct shmid_ds shmstat;
+ DCL_THREADGBL_ACCESS;
-# ifdef USHBIN_SUPPORTED
+ SETUP_THREADGBL_ACCESS;
linkctl->hdr = NULL;
/* open the given relinkctl file */
- relinkctl_get_key(relinkctl_path, &linkctl->zro_entry_name);
- DBGARLNK((stderr, "relinkctl_open: Opening relinkctl file %s for entry %.*s\n", relinkctl_path,
- linkctl->zro_entry_name.len, linkctl->zro_entry_name.addr));
- /* RW permissions for owner and others as determined by umask. */
- umask_orig = umask(000); /* determine umask (destructive) */
- (void)umask(umask_orig); /* reset umask */
- umask_creat = 0666 & ~umask_orig;
+ DBGARLNK((stderr, "relinkctl_open: pid = %d : Opening relinkctl file %s for entry %.*s\n", getpid(),
+ linkctl->relinkctl_path, linkctl->zro_entry_name.len, linkctl->zro_entry_name.addr));
/* Anybody that has read permissions to the object container should have write permissions to the relinkctl file */
- fd = OPEN3(relinkctl_path, O_CREAT | O_RDWR, umask_creat);
- /* TODO: get permissions right. see comment above . important */
- /* Do we want a relinkctl sitting around for $gtm_dist? */
- if (FD_INVALID == fd)
- ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, "open()");
- linkctl->fd = fd;
- /* If file is newly created, initialize it */
- FSTAT_FILE(fd, &stat_buf, status);
- if (0 != status)
- ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, "fstat()");
- if (0 == stat_buf.st_size)
+ retries = 0;
+ is_mu_rndwn_rlnkctl = TREF(is_mu_rndwn_rlnkctl);
+ do
{
+ assert('\0' == linkctl->zro_entry_name.addr[linkctl->zro_entry_name.len]); /* needed for STAT_FILE */
+ STAT_FILE(linkctl->zro_entry_name.addr, &dir_stat_buf, stat_res);
+ if (-1 == stat_res)
+ {
+ SNPRINTF(errstr, SIZEOF(errstr), "stat() of file %s failed", linkctl->zro_entry_name.addr);
+ ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, errno);
+ }
+ if (gtm_permissions(&dir_stat_buf, &user_id, &group_id, &perm, PERM_IPC, &pdd) < 0)
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_RELINKCTLERR, 2, RTS_ERROR_MSTR(&linkctl->zro_entry_name),
+ ERR_PERMGENFAIL, 4, RTS_ERROR_STRING("relinkctl"),
+ RTS_ERROR_MSTR(&linkctl->zro_entry_name));
+ }
+ /* Attempt to create file with desired permissions */
+ fd = OPEN3(linkctl->relinkctl_path, O_CREAT | O_RDWR | O_EXCL, perm);
+ /* If file created, set owner/group, if needed */
+ if ((FD_INVALID != fd)
+ && (((-1 != user_id) && (user_id != stat_buf.st_uid))
+ || ((-1 != group_id) && (group_id != stat_buf.st_gid)))
+ && (-1 == fchown(fd, user_id, group_id)))
+ {
+ save_errno = errno;
+ CLOSEFILE_RESET(fd, rc);
+ SNPRINTF(errstr, SIZEOF(errstr), "fchown() of file %s failed", linkctl->relinkctl_path);
+ ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, save_errno);
+ }
+ if ((FD_INVALID == fd) && (errno == EEXIST))
+ { /* file already existed, open existing */
+ fd = OPEN3(linkctl->relinkctl_path, O_CREAT | O_RDWR, 0);
+ }
+ if (FD_INVALID == fd)
+ {
+ SNPRINTF(errstr, SIZEOF(errstr), "open() of file %s failed", linkctl->relinkctl_path);
+ ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, errno);
+ }
+
+ linkctl->fd = fd;
relinkctl_lock_exclu(linkctl);
+
FSTAT_FILE(fd, &stat_buf, status);
if (0 != status)
{
- relinkctl_unlock_exclu(linkctl);
- ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, "fstat()");
+ save_errno = errno;
+ CLOSEFILE_RESET(fd, rc);
+ SNPRINTF(errstr, SIZEOF(errstr), "fstat() of file %s failed", linkctl->relinkctl_path);
+ ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, save_errno);
}
- if (0 == stat_buf.st_size)
+ if (RELINKCTL_MMAP_SZ != stat_buf.st_size)
{
- /* TODO: fix file extension so we don't need to preallocate so much space */
- ftruncate(fd, SIZEOF(relinkctl_data) + 1000000 * SIZEOF(relinkrec_t));
- relinkctl_map(linkctl, 0);
- linkctl->hdr->n_records = 0; /* what happens if kill -9'd between ftruncate and n_records = 0? */
- SET_LATCH_GLOBAL(&linkctl->hdr->attach_latch, LOCK_AVAILABLE);
+ DBGARLNK((stderr, "relinkctl_open: file size = %d\n", stat_buf.st_size));
+ if (RELINKCTL_MMAP_SZ != stat_buf.st_size)
+ {
+ FTRUNCATE(fd, RELINKCTL_MMAP_SZ, rc);
+ if (0 != rc)
+ {
+ save_errno = errno;
+ relinkctl_unlock_exclu(linkctl);
+ SNPRINTF(errstr, SIZEOF(errstr), "ftruncate() of file %s failed", linkctl->relinkctl_path);
+ ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, save_errno);
+ }
+ }
+ }
+ relinkctl_map(linkctl); /* linkctl->hdr is now accessible */
+ hdr = linkctl->hdr;
+ if (hdr->file_deleted)
+ { /* Some other process concurrently opened and closed/deleted the relinkctl file while
+ * we were still inside relinkctl_open. Reattach to new file (create it if necessary)
+ * instead of using the current fd as this wont be visible to other new processes.
+ */
+ DBGARLNK((stderr, "relinkctl_open: file_deleted = 1. Retrying open.\n"));
+ relinkctl_unlock_exclu(linkctl);
relinkctl_unmap(linkctl);
+ assert(NULL == linkctl->hdr);
+ assertpro(16 > retries++); /* too many loops is not practically possible. prevent infinite loops */
+ continue;
+ }
+ shm_size = RELINKCTL_SHM_SIZE;
+ ADJUST_SHM_SIZE_FOR_HUGEPAGES(shm_size, shm_size); /* second parameter "shm_size" is adjusted size */
+ if (hdr->initialized)
+ { /* Not creator of shared memory. Need to attach to shared memory.
+ * Need lock (already obtained) to prevent interaction with concurrent initialization, nattached = 0.
+ */
+ shmid = hdr->relinkctl_shmid;
+ DBGARLNK((stderr, "relinkctl_open: file already initialized : pre-increment hdr->nattached = %d"
+ " : shmid = %d\n", hdr->nattached, shmid));
+ assert(INVALID_SHMID != shmid);
+ assert(!hdr->file_deleted);
+ hdr->nattached++;
+ if (!is_mu_rndwn_rlnkctl)
+ relinkctl_unlock_exclu(linkctl);
+ if (-1 == (sm_long_t)(shm_base = (relinkshm_hdr_t *)do_shmat(shmid, 0, 0)))
+ {
+ save_errno = errno;
+ shm_removed = SHM_REMOVED(save_errno);
+ /* If shm has been removed, then direct one to use MUPIP RUNDOWN -RELINKCTL */
+ if (!shm_removed || !is_mu_rndwn_rlnkctl)
+ {
+ if (!is_mu_rndwn_rlnkctl)
+ relinkctl_lock_exclu(linkctl);
+ hdr->nattached--;
+ relinkctl_unlock_exclu(linkctl);
+ relinkctl_unmap(linkctl);
+ if (!shm_removed)
+ {
+ SNPRINTF(errstr, SIZEOF(errstr), "shmat() failed for "
+ "shmid=%d shmsize=%llu [0x%llx]", shmid, shm_size, shm_size);
+ ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, save_errno);
+ } else
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_REQRLNKCTLRNDWN, 2,
+ RTS_ERROR_MSTR(&linkctl->zro_entry_name));
+ } else
+ { /* This is MUPIP RUNDOWN -RELINKCTL and shm is removed. Run this relinkctl file down. */
+ DBGARLNK((stderr, "relinkctl_open: Set hdr->initialized to FALSE\n"));
+ hdr->initialized = FALSE;
+ }
+ }
}
+ if (!hdr->initialized)
+ {
+ DBGARLNK((stderr, "relinkctl_open: file first open\n"));
+ hdr->n_records = 0;
+ /* Create shared memory to store hash buckets of routine names for faster search in relinkctl file */
+ assert(RELINKCTL_HASH_BUCKETS == getprime(RELINKCTL_MAX_ENTRIES));
+ shmid = shmget(IPC_PRIVATE, shm_size, RWDALL | IPC_CREAT);
+ if (-1 == shmid)
+ {
+ save_errno = errno;
+ relinkctl_delete(linkctl);
+ relinkctl_unlock_exclu(linkctl);
+ relinkctl_unmap(linkctl);
+ SNPRINTF(errstr, SIZEOF(errstr), "shmget() failed for shmsize=%llu [0x%llx]", shm_size, shm_size);
+ ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, save_errno);
+ }
+ if (-1 == shmctl(shmid, IPC_STAT, &shmstat))
+ {
+ save_errno = errno;
+ relinkctl_delete(linkctl);
+ relinkctl_unlock_exclu(linkctl);
+ relinkctl_unmap(linkctl);
+ shm_rmid(shmid); /* if error removing shmid we created, just move on */
+ SNPRINTF(errstr, SIZEOF(errstr), "shmctl(IPC_STAT) failed for shmid=%d shmsize=%llu [0x%llx]",
+ shmid, shm_size, shm_size);
+ ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, save_errno);
+ }
+ /* change group and permissions */
+ if ((-1 != user_id) && (user_id != shmstat.shm_perm.uid))
+ shmstat.shm_perm.uid = user_id;
+ if ((-1 != group_id) && (group_id != shmstat.shm_perm.gid))
+ shmstat.shm_perm.gid = group_id;
+ shmstat.shm_perm.mode = perm;
+ if (-1 == shmctl(shmid, IPC_SET, &shmstat))
+ {
+ save_errno = errno;
+ relinkctl_delete(linkctl);
+ relinkctl_unlock_exclu(linkctl);
+ relinkctl_unmap(linkctl);
+ shm_rmid(shmid); /* if error removing shmid we created, just move on */
+ SNPRINTF(errstr, SIZEOF(errstr), "shmctl(IPC_SET) failed for shmid=%d shmsize=%llu [0x%llx]",
+ shmid, shm_size, shm_size);
+ ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, save_errno);
+ }
+ /* Initialize shared memory header */
+ if (-1 == (sm_long_t)(shm_base = (relinkshm_hdr_t *)do_shmat(shmid, 0, 0)))
+ {
+ save_errno = errno;
+ relinkctl_delete(linkctl);
+ relinkctl_unlock_exclu(linkctl);
+ relinkctl_unmap(linkctl);
+ shm_rmid(shmid); /* if error removing shmid we created, just move on */
+ SNPRINTF(errstr, SIZEOF(errstr), "shmat() failed for shmid=%d shmsize=%llu [0x%llx]",
+ shmid, shm_size, shm_size);
+ ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, save_errno);
+ }
+ hdr->relinkctl_shmid = shmid;
+ hdr->relinkctl_shmlen = shm_size;
+ assert(ARRAYSIZE(shm_base->relinkctl_fname) > strlen(linkctl->relinkctl_path));
+ assert(0 == ((UINTPTR_T)shm_base % 8));
+ assert(0 == (SIZEOF(relinkshm_hdr_t) % SIZEOF(uint4))); /* assert SIZEOF(*sm_uint_ptr_t) alignment */
+ memset(shm_base, 0, shm_size);
+ strcpy(shm_base->relinkctl_fname, linkctl->relinkctl_path);
+ shm_base->min_shm_index = TREF(relinkctl_shm_min_index);
+ shm_base->rtnobj_min_shm_index = NUM_RTNOBJ_SHM_INDEX;
+ shm_base->rtnobj_max_shm_index = 0;
+ shm_base->rtnobj_shmid_cycle = 0;
+ shm_base->rndwn_adjusted_nattch = FALSE;
+ DEBUG_ONLY(shm_base->skip_rundown_check = FALSE;)
+ for (i = 0; i < NUM_RTNOBJ_SHM_INDEX; i++)
+ {
+ rtnobj_shm_hdr = &shm_base->rtnobj_shmhdr[i];
+ rtnobj_shm_hdr->rtnobj_shmid = INVALID_SHMID;
+ rtnobj_shm_hdr->rtnobj_min_free_index = NUM_RTNOBJ_SIZE_BITS;
+ for (j = 0; j < NUM_RTNOBJ_SIZE_BITS; j++)
+ {
+ rtnobj_shm_hdr->freeList[j].fl = NULL_RTNOBJ_SM_OFF_T;
+ rtnobj_shm_hdr->freeList[j].bl = NULL_RTNOBJ_SM_OFF_T;
+ }
+ }
+ SET_LATCH_GLOBAL(&shm_base->relinkctl_latch, LOCK_AVAILABLE);
+ hdr->nattached = 1;
+ hdr->zro_entry_name_len = MIN(linkctl->zro_entry_name.len, ARRAYSIZE(hdr->zro_entry_name) - 1);
+ memcpy(hdr->zro_entry_name, linkctl->zro_entry_name.addr, hdr->zro_entry_name_len);
+ hdr->zro_entry_name[hdr->zro_entry_name_len] = '\0';
+ /* shared memory initialization complete */
+ hdr->initialized = TRUE;
+ relinkctl_unlock_exclu(linkctl);
+ } else if (is_mu_rndwn_rlnkctl)
+ relinkctl_unlock_exclu(linkctl);
+ assert(!linkctl->locked);
+ assert(0 == ((UINTPTR_T)shm_base % 8));
+ assert(0 == (SIZEOF(relinkshm_hdr_t) % SIZEOF(uint4))); /* assert SIZEOF(*sm_uint_ptr_t) alignment */
+# ifdef DEBUG
+ if (TREF(gtm_autorelink_keeprtn))
+ shm_base->skip_rundown_check = TRUE;
+# endif
+ linkctl->shm_hashbase = (sm_uint_ptr_t)(sm_uc_ptr_t)(shm_base + 1);
+ /* skip past shm header to reach hash array start */
+ assert(0 == ((UINTPTR_T)linkctl->shm_hashbase % 8)); /* assert each section is 8-byte aligned at least */
+ assert(1 == RELINKCTL_HASH_BUCKETS % 2); /* RELINKSHM_RTNHASH_SIZE definition relies on this for 8-byte alignment */
+ linkctl->rec_base = (relinkrec_t *)((sm_uc_ptr_t)linkctl->shm_hashbase + RELINKSHM_RTNHASH_SIZE);
+ assert(128 >= SIZEOF(relinkrec_t)); /* or else adjust CACHELINE_PAD_COND filler downwards */
+ assert(0 == ((UINTPTR_T)linkctl->rec_base % 8)); /* assert each section is 8-byte aligned at least */
+ break;
+ } while (TRUE);
+# endif
+}
+
+#ifdef AUTORELINK_SUPPORTED
+/* This is called from processes that already have "linkctl" attached but have not done an increment of "linkctl->hdr->nattached".
+ * Example is a jobbed off process in ojstartchild.c
+ */
+void relinkctl_incr_nattached(void)
+{
+ open_relinkctl_sgm *linkctl;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ for (linkctl = TREF(open_relinkctl_list); NULL != linkctl; linkctl = linkctl->next)
+ {
+ relinkctl_lock_exclu(linkctl);
+ DBGARLNK((stderr, "relinkctl_incr_nattached : pid = %d : file %s : pre-incr hdr->nattached = %d\n",
+ getpid(), linkctl->relinkctl_path, linkctl->hdr->nattached));
+ assert(linkctl->hdr->nattached);
+ linkctl->hdr->nattached++;
relinkctl_unlock_exclu(linkctl);
}
- /* Do an small mapping in order to read n_records, then map the full file */
- relinkctl_map(linkctl, 0);
- relinkctl_ensure_fullmap(linkctl);
- /* Need lock to prevent interaction with concurrent initialization, nattached = 0 */
- relinkctl_lock_exclu(linkctl);
- linkctl->hdr->nattached++;
- /*sprintf(buff, "%s - incremented. nattached = %d", linkctl->zro_entry_name, linkctl->hdr->nattached);
- send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_STR(buff));*/
- /*send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2,
- LEN_AND_LIT("%s - incremented. nattached = %d")); debugging TODO*/
- relinkctl_unlock_exclu(linkctl);
- /* TODO: when to close? with ZGOTO 0? or never bother? */
-# endif
}
/* Routine to generate unique key for a $ZROUTINES entry name used to create relinkctl file for that entry in the directory
* $gtm_linktmpdir (e.g. /testarea1/gtm/temp --> $gtm_linktmpdir/gtm-relinkctl-d0f3d074c724430bc1c7679141b96411).
* Theoretically, we'd need a scheme to resolve hash collisions. Say, append -<collision_id> to the key.
- * But since this is MD5, we can assume a collision will never happen in practice, so we do not handle the extremely
- * unlikely event of an MD5 hash collision for the few $ZROUTINES entries used by processes using the same $gtm_linktmpdir
- * value.
+ * But since this is 128-bit MurmurHash3, we can assume a collision will never happen in practice, so we do not
+ * handle the extremely unlikely event of a hash collision for the few $ZROUTINES entries used by processes using
+ * the same $gtm_linktmpdir value.
*
* Parameters:
*
- * key - Generated as $gtm_linktmpdir/gtm-relinkctl-<md5>. Buffer should be GTM_PATH_MAX bytes (output).
+ * key - Generated as $gtm_linktmpdir/gtm-relinkctl-<hash>. Buffer should be GTM_PATH_MAX bytes (output).
* zro_entry_name - Address of mstr containing the fully expanded zroutines entry directory name.
*/
-#ifdef USHBIN_SUPPORTED
-STATICFNDEF void relinkctl_get_key(char key[GTM_PATH_MAX], mstr *zro_entry_name)
+int relinkctl_get_key(char key[GTM_PATH_MAX], mstr *zro_entry_name)
{
- cvs_MD5_CTX md5context;
- unsigned char digest[MD5_DIGEST_LENGTH];
- char hexstr[MD5_HEXSTR_LENGTH];
+ gtm_uint16 hash;
+ unsigned char hexstr[33];
int keylen;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
- cvs_MD5Init(&md5context);
- cvs_MD5Update(&md5context, (const unsigned char *)zro_entry_name->addr, zro_entry_name->len);
- cvs_MD5Final(digest, &md5context);
- md5_digest2hex(hexstr, digest);
- /* Improve efficiency - use memcpy to build string and provide better max-length checking than an assert */
+ gtmmrhash_128(zro_entry_name->addr, zro_entry_name->len, 0, &hash);
+ gtmmrhash_128_hex(&hash, hexstr);
+ hexstr[32] = '\0';
+ /* TODO: Improve efficiency - use memcpy to build string and provide better max-length checking than an assert */
keylen = SNPRINTF(&key[0], GTM_PATH_MAX - 1, "%.*s/gtm-relinkctl-%s", (TREF(gtm_linktmpdir)).len,
(TREF(gtm_linktmpdir)).addr, hexstr);
assert((0 < keylen) && (GTM_PATH_MAX > keylen));
+ return keylen;
}
-#endif
/**
* Relinkctl mmap-related methods
*/
-/*
- * Remap, if entire array of relink records is not mapped.
- */
-void relinkctl_ensure_fullmap(open_relinkctl_sgm *linkctl)
-{
- uint4 nrec;
-
-# ifdef USHBIN_SUPPORTED
- nrec = linkctl->hdr->n_records;
- if (nrec >= relinkctl_recs2map(linkctl->n_records))
- {
- relinkctl_unmap(linkctl);
- relinkctl_map(linkctl, nrec);
- }
- linkctl->n_records = nrec;
-# endif
-}
-
-/*
- * Map at least n_records, currently known number of entries.
+/* Routine to map at least n_records, currently known number of entries.
+ *
+ * Parameter:
+ * linkctl - addr of process-private block describing the shared file.
*
* Fills in:
* linkctl->hdr
* linkctl->n_records
- * linkctl->rec_base
*/
-#ifdef USHBIN_SUPPORTED
-STATICFNDEF void relinkctl_map(open_relinkctl_sgm *linkctl, uint4 n_records)
+STATICFNDEF void relinkctl_map(open_relinkctl_sgm *linkctl)
{
sm_uc_ptr_t addr;
- size_t mapsz;
- mapsz = SIZEOF(relinkctl_data) + (relinkctl_recs2map(n_records) * SIZEOF(relinkrec_t));
- addr = (sm_uc_ptr_t)mmap(NULL, mapsz, (PROT_READ + PROT_WRITE), MAP_SHARED, linkctl->fd, 0);
+ assert(NULL == linkctl->hdr);
+ addr = (sm_uc_ptr_t)mmap(NULL, RELINKCTL_MMAP_SZ, (PROT_READ + PROT_WRITE), MAP_SHARED, linkctl->fd, 0);
if (MAP_FAILED == addr)
- ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, "mmap()");
+ ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, "mmap()", errno);
linkctl->hdr = (relinkctl_data *)addr;
- linkctl->n_records = n_records;
- linkctl->rec_base = &linkctl->hdr->base[0];
+ linkctl->n_records = 0;
}
+/* Routine similar to relink_map except UNMAPs the file */
STATICFNDEF void relinkctl_unmap(open_relinkctl_sgm *linkctl)
{
- /* TODO */
-}
+ sm_uc_ptr_t addr;
+ int rc;
-/*
- * We don't want to repeatedly re-mmap the file, so given some minimum number of records we need to map,
- * compute a larger number to accomodate before we need to remap.
- */
-STATICFNDEF uint4 relinkctl_recs2map(uint4 n_records)
-{
- /* TODO: Improve - right now, limited to fixed initial size */
- return 1000000;
- /* return n_records + 1; - This causes excessive remapping - pick a better increment */
+ addr = (sm_uc_ptr_t)linkctl->hdr;
+ munmap(addr, RELINKCTL_MMAP_SZ); /* If munmap errors, it seems better to move on than stop for a non-critical error */
+ linkctl->hdr = NULL;
+ linkctl->n_records = 0;
+ CLOSEFILE_RESET(linkctl->fd, rc);
}
#endif
@@ -285,8 +523,7 @@ STATICFNDEF uint4 relinkctl_recs2map(uint4 n_records)
* Exclusive locking methods controlling WRITE access to relinkctl control files.
*/
-/*
- * Routine to exclusively lock the relinkctl file.
+/* Routine to exclusively lock the relinkctl file.
*
* Parameter:
*
@@ -296,21 +533,30 @@ void relinkctl_lock_exclu(open_relinkctl_sgm *linkctl)
{
int status;
-# ifdef USHBIN_SUPPORTED
+# ifdef AUTORELINK_SUPPORTED
+ assert(!linkctl->locked);
+ if (linkctl->locked)
+ return;
status = relinkctl_fcntl_lock(linkctl->fd, F_WRLCK);
- assert(0 == status); /* TODO: Deal with error */
+ if (-1 == status)
+ ISSUE_RELINKCTLERR_TEXT(&linkctl->zro_entry_name, "fcntl() lock attempt failed", errno);
linkctl->locked = TRUE;
# endif
return;
}
+/* Routine same as relinkctl_lock_exclu() but instead UNLOCKs the lock */
void relinkctl_unlock_exclu(open_relinkctl_sgm *linkctl)
{
int status;
-# ifdef USHBIN_SUPPORTED
+# ifdef AUTORELINK_SUPPORTED
+ assert(linkctl->locked);
+ if (!linkctl->locked)
+ return;
status = relinkctl_fcntl_lock(linkctl->fd, F_UNLCK);
- assert(0 == status); /* TODO: Deal with error */
+ if (-1 == status)
+ ISSUE_RELINKCTLERR_TEXT(&linkctl->zro_entry_name, "fcntl() unlock attempt failed", errno);
linkctl->locked = FALSE;
# endif
return;
@@ -327,7 +573,7 @@ void relinkctl_unlock_exclu(open_relinkctl_sgm *linkctl)
*
* - status of fcntl() lock or unlock attempt
*/
-#ifdef USHBIN_SUPPORTED
+#ifdef AUTORELINK_SUPPORTED
STATICFNDEF int relinkctl_fcntl_lock(int fd, int l_type)
{
int status;
@@ -345,124 +591,329 @@ STATICFNDEF int relinkctl_fcntl_lock(int fd, int l_type)
}
#endif
+#ifdef AUTORELINK_SUPPORTED
/**
* Relinkctl file record management routines
*/
-/* Like relinkctl_find_record, but inserts a new entry instead of returning REC_NOT_FOUND.
- */
-relinkrec_loc_t relinkctl_insert_record(open_relinkctl_sgm *linkctl, mstr *rtnname)
+/* Like relinkctl_find_record, but inserts a new entry instead of returning NULL */
+relinkrec_t *relinkctl_insert_record(open_relinkctl_sgm *linkctl, mstr *rtnname)
{
- relinkrec_loc_t rec;
- relinkrec_ptr_abs_t base, newrec;
+ relinkrec_t *base, *rec;
+ uint4 hash, prev_hash_index, nrec;
-# ifdef USHBIN_SUPPORTED
- rec = relinkctl_find_record(linkctl, rtnname);
- if (REC_NOT_FOUND == rec)
- {
+ COMPUTE_RELINKCTL_HASH(rtnname, hash);
+ rec = relinkctl_find_record(linkctl, rtnname, hash, &prev_hash_index);
+ if (NULL == rec)
+ { /* Record not found while not under lock - lock it and try again */
relinkctl_lock_exclu(linkctl);
- rec = relinkctl_find_record(linkctl, rtnname);
- if (REC_NOT_FOUND == rec)
- { /* File expansion scenario - TODO - don't assume additional record is available */
+ rec = relinkctl_find_record(linkctl, rtnname, hash, &prev_hash_index);
+ if (NULL == rec)
+ { /* Add a new record if room exists - else error */
assert(linkctl->locked);
- assert(linkctl->n_records == linkctl->hdr->n_records);
+ nrec = linkctl->n_records;
+ assert(nrec == linkctl->hdr->n_records); /* Assured by relinkctl_find_record() */
+ if (RELINKCTL_MAX_ENTRIES == linkctl->hdr->n_records)
+ {
+ relinkctl_unlock_exclu(linkctl);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_RELINKCTLFULL, 3, linkctl->zro_entry_name.len,
+ linkctl->zro_entry_name.addr, RELINKCTL_MAX_ENTRIES);
+ }
base = linkctl->rec_base;
- newrec = base + (UINTPTR_T)linkctl->n_records;
- newrec->cycle = 1; /* Start at cycle 1 instead of 0 */
- memset(&newrec->rtnname_fixed.c[0], 0, SIZEOF(mident_fixed));
+ rec = base + nrec;
+ memset(&rec->rtnname_fixed.c[0], 0, SIZEOF(mident_fixed));
assert(MAX_MIDENT_LEN >= rtnname->len);
- memcpy(&newrec->rtnname_fixed.c[0], rtnname->addr, rtnname->len);
- /* TODO: Insert record's AVL node into AVL tree or hash entry into htab */
+ /* assert(valid_mname(rtnname)) is not needed here because it was already done in relinkctl_find_record */
+ memcpy(&rec->rtnname_fixed.c[0], rtnname->addr, rtnname->len);
+ rec->cycle = 0; /* Note incr_link() will bump this to 1 when routine is linked */
+ rec->hashindex_fl = 0;
+ rec->objhash = 0;
+ rec->rtnobj_shm_offset = (rtnobj_sm_off_t)NULL_RTNOBJ_SM_OFF_T;
+ if (prev_hash_index)
+ {
+ --prev_hash_index;
+ assert(prev_hash_index < nrec);
+ assert(0 == base[prev_hash_index].hashindex_fl);
+ base[prev_hash_index].hashindex_fl = nrec + 1;
+ } else
+ linkctl->shm_hashbase[hash] = nrec + 1;
linkctl->hdr->n_records++;
- rec = RCTLABS2REL(newrec, base);
- assert(rec == relinkctl_find_record(linkctl, rtnname));
+ assert(rec == relinkctl_find_record(linkctl, rtnname, hash, &prev_hash_index));
}
relinkctl_unlock_exclu(linkctl);
}
return rec;
-# else
- return 0;
-# endif
}
-/*
- * Iterate through each relink_record_struct starting at (relink_record_ptr)&linkctl->map_addr[0]
+/* Iterate through each relink_record_struct starting at (relink_record_ptr)&linkctl->map_addr[0]
* Find rec s.t. rec->rtnname == rtnname, return offset of rec.
* Otherwise, return NOMATCH (defined 0xffff..).
*/
-relinkrec_loc_t relinkctl_find_record(open_relinkctl_sgm *linkctl, mstr *rtnname)
+relinkrec_t *relinkctl_find_record(open_relinkctl_sgm *linkctl, mstr *rtnname, uint4 hash, uint4 *prev_hash_index)
{
- relinkrec_ptr_abs_t rec, base, top;
-
-# ifdef USHBIN_SUPPORTED
- relinkctl_ensure_fullmap(linkctl); /* Make sure we search among all currently existing records */
+ relinkrec_t *rec, *base;
+ unsigned int nrec, index;
+ sm_uint_ptr_t ptr;
+ uint4 rtnhash, prev_index;
+
+ assert(valid_mname(rtnname));
+ linkctl->n_records = linkctl->hdr->n_records; /* Make sure we search among all currently existing records */
+ ptr = linkctl->shm_hashbase;
+ assert(RELINKCTL_HASH_BUCKETS > hash);
+ ptr += hash;
+ prev_index = *ptr;
+ index = prev_index - 1; /* 'index' is unsigned so will become huge positive number in case *ptr is 0 */
base = linkctl->rec_base;
- top = base + (UINTPTR_T)linkctl->n_records;
- for (rec = base; rec < top; rec++)
- { /* For each record, check routine name plus null trailer in fixed version */
+ nrec = linkctl->n_records;
+ assert(RELINKCTL_MAX_ENTRIES >= nrec);
+ while (index < nrec)
+ {
+ rec = &base[index];
+ DEBUG_ONLY(COMPUTE_RELINKCTL_HASH(rtnname, rtnhash);)
+ assert(rtnhash == hash);
+ /* Check routine name plus null trailer in fixed version */
if ((0 == memcmp(&rec->rtnname_fixed.c, rtnname->addr, rtnname->len))
- && ('\0' == rec->rtnname_fixed.c[rtnname->len]))
- return RCTLABS2REL(rec, base);
+ && ('\0' == rec->rtnname_fixed.c[rtnname->len]))
+ return rec;
+ assert(RELINKCTL_MAX_ENTRIES >= rec->hashindex_fl);
+ prev_index = index + 1;
+ index = rec->hashindex_fl - 1;
}
-# endif
- return REC_NOT_FOUND;
+ *prev_hash_index = prev_index;
+ return NULL;
}
+#endif
/**
* Relinkctl file rundown routines
*/
/*
- * Close all file descriptors associated with relinkctl structs, and (atomically) decrement nattached in file header.
+ * Unmap all relinkctl structs after (atomically) decrementing nattached field in relinkctl file header
*/
-void relinkctl_rundown(boolean_t decr_attached)
+void relinkctl_rundown(boolean_t decr_attached, boolean_t do_rtnobj_shm_free)
{
-# ifdef USHBIN_SUPPORTED
+# ifdef AUTORELINK_SUPPORTED
int rc;
- open_relinkctl_sgm *linkctl;
+ open_relinkctl_sgm *linkctl, *nextctl;
+ rtn_tabent *rtab;
+ rhdtyp *rtnhdr;
+ relinkctl_data *hdr;
+ int shmid, i, nattached;
+ relinkshm_hdr_t *shm_hdr;
+ rtnobjshm_hdr_t *rtnobj_shm_hdr;
+ stack_frame *fp;
+ boolean_t is_mu_rndwn_rlnkctl, remove_shm;
+ struct shmid_ds shm_buf;
+# ifdef DEBUG
+ relinkrec_t *linkrec, *linktop;
+ int j, k;
+ rtnobj_sm_off_t rtnobj_shm_offset;
+ boolean_t clean_shutdown;
+# endif
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
- for (linkctl = TREF(open_relinkctl_list); NULL != linkctl; linkctl = linkctl->next)
+ if (do_rtnobj_shm_free && !TREF(gtm_autorelink_keeprtn))
{
+ assert(process_exiting);
+ /* Run through all loaded routines and if any are loaded in shared memory, decrement their reference counts.
+ * Since this involves shared memory, this is best accomplished by invoking rtnobj_shm_free.
+ * For non-shared objects, zr_unlink_rtn will only release process-private memory. Since this process is
+ * going to die (asserted by process_exiting above) no need to do anything in that case.
+ * But before that check if the M-stack has any frames with rtnhdr->rtn_relinked TRUE. These are
+ * routine-header structures that are not added to the rtn_names[] array but could potentially have
+ * done rtnobj_shm_malloc(). In that case do rtnobj_shm_free() on those to decrement shared memory refcnts.
+ */
+ for (fp = frame_pointer; NULL != fp; fp = SKIP_BASE_FRAME(fp->old_frame_pointer))
+ {
+ rtnhdr = CURRENT_RHEAD_ADR(fp->rvector);
+ if ((NULL != rtnhdr) && rtnhdr->rtn_relinked && rtnhdr->shared_object)
+ {
+ rtnobj_shm_free(rtnhdr, LATCH_GRABBED_FALSE);
+ rtnhdr->rtn_relinked = FALSE;
+ rtnhdr->shared_object = FALSE;
+ }
+ }
+ for (rtab = rtn_names_end; rtab > rtn_names; rtab--, rtn_names_end = rtab)
+ { /* [0] is not used (for some reason) */
+ rtnhdr = rtab->rt_adr;
+ if (rtnhdr->shared_object)
+ rtnobj_shm_free(rtnhdr, LATCH_GRABBED_FALSE);
+ }
+ }
+ is_mu_rndwn_rlnkctl = TREF(is_mu_rndwn_rlnkctl);
+ for (linkctl = TREF(open_relinkctl_list); NULL != linkctl; linkctl = nextctl)
+ {
+ for (i = 0; i < NUM_RTNOBJ_SHM_INDEX; i++)
+ {
+ if (NULL != linkctl->rtnobj_shm_base[i])
+ {
+ assert(INVALID_SHMID != linkctl->rtnobj_shmid[i]);
+ SHMDT(linkctl->rtnobj_shm_base[i]);
+ linkctl->rtnobj_shm_base[i] = NULL;
+ } else
+ assert(INVALID_SHMID == linkctl->rtnobj_shmid[i]);
+ }
if (decr_attached)
{
relinkctl_lock_exclu(linkctl);
- linkctl->hdr->nattached--;
- /*sprintf(buff, "%s - decremented. nattached = %d", linkctl->zro_entry_name, linkctl->hdr->nattached);
- send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_STR(buff));*/
- /*send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2,
- LEN_AND_STR(linkctl->zro_entry_name));
- send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2,
- LEN_AND_LIT("decremented")); debugging TODO */
- relinkctl_unlock_exclu(linkctl);
- assert(0 <= linkctl->hdr->nattached);
- if (0 == linkctl->hdr->nattached)
+ hdr = linkctl->hdr;
+ assert(0 < hdr->nattached);
+ if (0 < hdr->nattached)
+ hdr->nattached--;
+ nattached = hdr->nattached;
+ DBGARLNK((stderr, "relinkctl_rundown : pid = %d : file %s : post-decr nattached = %d\n",
+ getpid(), linkctl->relinkctl_path, nattached));
+ assert(0 <= nattached);
+ assert(INVALID_SHMID != hdr->relinkctl_shmid);
+ shm_hdr = GET_RELINK_SHM_HDR(linkctl);
+ if (0 == nattached)
+ {
+ DBGARLNK((stderr, "relinkctl_rundown : nattached = 0\n"));
+ remove_shm = TRUE;
+ } else if (is_mu_rndwn_rlnkctl)
+ { /* If MUPIP RUNDOWN -RELINKCTL, check if shm_buff.nattch is 1 (i.e. mupip rundown -relinkctl
+ * is the only one attached to this shm). If so, ignore nattached and run this shm down.
+ * Most likely processees that had bumped nattached got kill -9ed.
+ * If shm_buff.nattch is not 1, fix hdr->nattached to match shm_buf.nattch so when the time
+ * comes for the last GTM process to rundown, it will remove the shm without the need for
+ * any more MUPIP RUNDOWN -RELINKCTL commands.
+ */
+ shmid = hdr->relinkctl_shmid;
+ if (0 != shmctl(shmid, IPC_STAT, &shm_buf))
+ {
+ assert(FALSE);
+ remove_shm = FALSE;
+ } else
+ {
+ nattached = shm_buf.shm_nattch - 1; /* remove self since we will do a SHMDT soon */
+ if (hdr->nattached != nattached)
+ {
+ hdr->nattached = nattached; /* fix hdr->nattached while at this */
+ shm_hdr->rndwn_adjusted_nattch = TRUE;
+ }
+ remove_shm = !nattached;
+ }
+ if (!remove_shm)
+ {
+ assert(nattached);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_RLNKCTLRNDWNFL, 3,
+ RTS_ERROR_MSTR(&linkctl->zro_entry_name), nattached);
+ }
+ } else
+ remove_shm = FALSE;
+ if (remove_shm)
+ {
+# ifdef DEBUG
+ clean_shutdown = (!shm_hdr->rndwn_adjusted_nattch && !shm_hdr->skip_rundown_check);
+ if (clean_shutdown)
+ {
+ /* Check that ALL reference counts are zero */
+ for (linkrec = linkctl->rec_base, linktop = &linkrec[hdr->n_records];
+ linkrec < linktop; linkrec++)
+ {
+ assert(grab_latch(&linkrec->rtnobj_latch, 0)); /* 0 => do not wait for latch */
+ DEBUG_ONLY(rtnobj_shm_offset = linkrec->rtnobj_shm_offset;)
+ assert(NULL_RTNOBJ_SM_OFF_T == rtnobj_shm_offset);
+ assert(0 == linkrec->objLen);
+ assert(0 == linkrec->usedLen);
+ }
+ grab_latch(&shm_hdr->relinkctl_latch, 0); /* 0 => do not wait for latch */
+ }
+ /* No need to release latch as we will be deleting the shared memory anyways */
+# endif
+ for (i = 0; i < NUM_RTNOBJ_SHM_INDEX; i++)
+ {
+ rtnobj_shm_hdr = &shm_hdr->rtnobj_shmhdr[i];
+ assert(!clean_shutdown || (0 == rtnobj_shm_hdr->real_len));
+ assert(!clean_shutdown || (0 == rtnobj_shm_hdr->used_len));
+ shmid = rtnobj_shm_hdr->rtnobj_shmid;
+ if (INVALID_SHMID != shmid)
+ {
+# ifdef DEBUG
+ if (clean_shutdown)
+ { /* Note: shmctl can fail if some other process changes permissions
+ * concurrently (after we had attached to the shmid) so account for
+ * that in the assert below.
+ */
+ if (0 == shmctl(shmid, IPC_STAT, &shm_buf))
+ {
+ /* We expect no one else to be attached to relinkctl shm. One case we
+ * know of is if a process opens a PIPE device and iopi_open forks off
+ * a child (which would cause shm_nattch to increment implicitly) and
+ * continues execution issuing say a CRYPTNOSEEK error and exit BEFORE the
+ * child process has done the EXEC (which would cause the shm_nattch to
+ * decrement it back to the expected value). Account for it in the assert.
+ */
+ assert((0 == shm_buf.shm_nattch) || TREF(fork_without_child_wait));
+ }
+ k = i + MIN_RTNOBJ_SHM_INDEX - MIN_RTNOBJ_SIZE_BITS;
+ assert(rtnobj_shm_hdr->shm_len
+ == ((gtm_uint64_t)1 << (k + MIN_RTNOBJ_SIZE_BITS)));
+ for (j = 0; j < NUM_RTNOBJ_SIZE_BITS; j++)
+ {
+ if (j != k)
+ {
+ assert(NULL_RTNOBJ_SM_OFF_T
+ == rtnobj_shm_hdr->freeList[j].fl);
+ assert(NULL_RTNOBJ_SM_OFF_T
+ == rtnobj_shm_hdr->freeList[j].bl);
+ } else
+ {
+ assert(OFFSETOF(rtnobj_hdr_t, userStorage)
+ == rtnobj_shm_hdr->freeList[j].fl);
+ assert(OFFSETOF(rtnobj_hdr_t, userStorage)
+ == rtnobj_shm_hdr->freeList[j].bl);
+ }
+ }
+ }
+# endif
+ shm_rmid(shmid); /* If error removing shmid, not much we can do. Just move on */
+ }
+ }
+ SHMDT(shm_hdr); /* If error detaching, not much we can do. Just move on */
+ shmid = hdr->relinkctl_shmid;
+ shm_rmid(shmid); /* If error removing shmid, not much we can do. Just move on */
+ relinkctl_delete(linkctl);
+ if (is_mu_rndwn_rlnkctl)
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_RLNKCTLRNDWNSUC, 2,
+ RTS_ERROR_MSTR(&linkctl->zro_entry_name));
+ } else
{
- relinkctl_lock_exclu(linkctl);
- if (0 == linkctl->hdr->nattached)
- relinkctl_delete(linkctl);
+ SHMDT(shm_hdr); /* If error detaching, not much we can do. Just move on */
}
+ linkctl->rec_base = NULL;
+ linkctl->shm_hashbase = NULL;
+ relinkctl_unlock_exclu(linkctl);
}
- CLOSEFILE_RESET(linkctl->fd, rc);
- linkctl->hdr = NULL;
- linkctl->rec_base = NULL;
+ relinkctl_unmap(linkctl); /* sets "linkctl->hdr" to NULL */
+ nextctl = linkctl->next;
+ free(linkctl);
}
TREF(open_relinkctl_list) = NULL;
# endif
return;
}
+#ifdef AUTORELINK_SUPPORTED
/*
- * Clean up (i.e. delete) relinkctl file
+ * Clean up (i.e. delete) relinkctl file whose descriptor block is passed in
*/
-#ifdef USHBIN_SUPPORTED
STATICFNDEF void relinkctl_delete(open_relinkctl_sgm *linkctl)
{
- char relinkctl_path[GTM_PATH_MAX + 1];
+ int status;
- relinkctl_get_key(relinkctl_path, &linkctl->zro_entry_name);
- UNLINK(relinkctl_path);
+ DBGARLNK((stderr, "relinkctl_delete : pid = %d : Deleting %s\n", getpid(), linkctl->relinkctl_path));
+ status = UNLINK(linkctl->relinkctl_path);
+ /* If unlink succeeds, then set "hdr->file_deleted" to TRUE to notify other processes in relinkctl_open
+ * about this concurrent delete so they can reattach. If the unlink fails (e.g. due to permission issues)
+ * do not set "hdr->file_deleted".
+ */
+ if (-1 != status)
+ linkctl->hdr->file_deleted = TRUE; /* Notify any other process in relinkctl_open about this so they can reattach */
+ else
+ linkctl->hdr->initialized = FALSE; /* So next process reinitializes hdr->relinkctl_shmid etc. */
return;
}
#endif
diff --git a/sr_unix/relinkctl.h b/sr_unix/relinkctl.h
index 8879242..84a1bf0 100644
--- a/sr_unix/relinkctl.h
+++ b/sr_unix/relinkctl.h
@@ -12,52 +12,148 @@
#ifndef RELINKCTL_H_INCLUDED
#define RELINKCTL_H_INCLUDED
+# include "gtm_limits.h"
-/* For autorelink debugging, uncomment the line below */
-/* #define AUTORELINK_DEBUG */
-#if defined(AUTORELINK_DEBUG)
-# define DBGARLNK(x) DBGFPF(x)
-# define DBGARLNK_ONLY(x) x
-# include "gtm_stdio.h"
-# include "gtmio.h"
+/* Input RTNNAME is derived from an object file name and we need to convert it to a proper routine name.
+ * a) It is possible we got a '_' as the first character in case of a % routine. But the actual routine name stored in
+ * that object file would have '%' as the first character. Fix that.
+ * b) Also limit routine name length to MAX_MIDENT_LEN (internal design max). Ignore the rest of the file name.
+ */
+#define CONVERT_FILENAME_TO_RTNNAME(RTNNAME) \
+{ \
+ if ('_' == RTNNAME.addr[0]) \
+ RTNNAME.addr[0] = '%'; \
+ if (MAX_MIDENT_LEN < RTNNAME.len) \
+ RTNNAME.len = MAX_MIDENT_LEN; \
+}
+
+#define COMPUTE_RELINKCTL_HASH(RTNNAME, RTNHASH) \
+{ \
+ STR_HASH((RTNNAME)->addr, (RTNNAME)->len, RTNHASH, 0); \
+ RTNHASH = RTNHASH % RELINKCTL_HASH_BUCKETS; \
+}
+
+/* One relinkctl file can contain at most this many # of routines */
+#ifdef DEBUG
+# define RELINKCTL_MAX_ENTRIES (WBTEST_ENABLED(WBTEST_RELINKCTL_MAX_ENTRIES) ? 100 : 1000000)
+#else
+# define RELINKCTL_MAX_ENTRIES 1000000
+#endif
+
+/* The first prime # above RELINKCTL_MAX_ENTRIES */
+#ifdef DEBUG
+# define RELINKCTL_HASH_BUCKETS (WBTEST_ENABLED(WBTEST_RELINKCTL_MAX_ENTRIES) ? 101 : 1000003)
#else
-# define DBGARLNK(x)
-# define DBGARLNK_ONLY(x)
+# define RELINKCTL_HASH_BUCKETS 1000003
#endif
-#define MIN_RELINKCTL_MAPSZ 1024 /* bytes */
-#define REC_NOT_FOUND (relinkrec_loc_t)(-1)
+#define RELINKCTL_MMAP_SZ ((size_t)SIZEOF(relinkctl_data))
+#define RELINKSHM_HDR_SIZE ((size_t)SIZEOF(relinkshm_hdr_t))
+/* We are guaranteed RELINKCTL_HASH_BUCKETS is an odd prime number and since we want at least 8-byte alignment between different
+ * sections of shared memory, we add a 4-byte filler to the RELINKSHM_RTNHASH_SIZE macro computation.
+ */
+#define RELINKSHM_RTNHASH_SIZE (((size_t)RELINKCTL_HASH_BUCKETS + 1) * SIZEOF(uint4)) /* see above comment for why "+ 1" */
+#define RELINKSHM_RECARRAY_SIZE ((size_t)RELINKCTL_MAX_ENTRIES * SIZEOF(relinkrec_t))
+#define RELINKCTL_SHM_SIZE (RELINKSHM_HDR_SIZE + RELINKSHM_RTNHASH_SIZE + RELINKSHM_RECARRAY_SIZE)
-/* Macros for dealing with relative and absolute addresses and converting between them */
-#define RCTLABS2REL(ABSADR, BASEADR) ((relinkrec_loc_t)((UINTPTR_T)(ABSADR) - (UINTPTR_T)(BASEADR)))
-#define RCTLREL2ABS(RELADR, BASEADR) ((relinkrec_ptr_abs_t)((UINTPTR_T)(BASEADR) + (UINTPTR_T)(RELADR)))
+#define GET_RELINK_SHM_HDR(LINKCTL) (relinkshm_hdr_t *)((sm_uc_ptr_t)LINKCTL->shm_hashbase - SIZEOF(relinkshm_hdr_t))
-/* Macro to read the cycle# of a given relinkctl record */
-#define RELINKCTL_CYCLE_READ(LINKCTL, RECOFFSET) (((relinkrec_ptr_abs_t)(RCTLREL2ABS((RECOFFSET), (LINKCTL)->rec_base)))->cycle)
-/* Macro to bump the cycle# of a given relinkctl record */
-#define RELINKCTL_CYCLE_INCR(LINKCTL, RECOFFSET) (((relinkrec_ptr_abs_t)(RCTLREL2ABS((RECOFFSET), (LINKCTL)->rec_base)))->cycle++)
+error_def(ERR_RLNKRECLATCH); /* needed for the RELINKCTL_CYCLE_INCR macro */
-/*
- * Possible TODO as it relates to ensuring consistent code state:
- * Along with cycle and rtnname, put MD5 checksum in record. When a process ZLINKs, ensure that checksum of object matches?
- * something like:
- * 1. open() object file, note rhdr->MD5
- * 2. Note rec->MD5
- * 3. Issue error if different (unless it's different because of concurrent ZRUPDATE, in which case repeat from step 1.)
+/* Macro to bump the cycle# of a given relinkctl record. Make sure shared cycle never becomes 0 after the bump since a process
+ * initializes its private cycle to 0 at relinkctl file open time and we want to make sure the private-cycle == shared-cycle
+ * check fails always the first time for a process.
+ */
+#define RELINKCTL_CYCLE_INCR(RELINKREC, LINKCTL) \
+{ \
+ if (!grab_latch(&(RELINKREC)->rtnobj_latch, RLNKREC_LATCH_TIMEOUT_SEC)) \
+ { \
+ assert(FALSE); \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_RLNKRECLATCH, 3, \
+ RELINKREC->rtnname_fixed.c, RTS_ERROR_MSTR(&LINKCTL->zro_entry_name)); \
+ } \
+ if (0 == ++(RELINKREC)->cycle) \
+ ++(RELINKREC)->cycle; \
+ rel_latch(&(RELINKREC)->rtnobj_latch); \
+}
+
+/* A routine buffer is stored a shared memory segment. Since shm sizes are fixed, if ever we cannot fit in a given routine
+ * buffer in a given shm, we create another shm with double the size and keep doing this until we come with a shm that can
+ * fit in the given routine buffer. We allow for a max of MAX_RTNOBJ_SHM_INDEX such shmids to be allocated per relinkctl file.
+ * Since we need 6 bits to represent MAX_RTNOBJ_SHM_INDEX, we treat the array of shmids to be on huge 2**64 sized shmid. Where
+ * the top 6 bits represent the index in the shmid array and the remaining 58 bits correspond to the offset within that shmid
+ * where the routine buffer can be found. Such an offset into a routine buffer in shared memory is typed as rtnobj_sm_off_t.
*/
+#define RTNOBJ_SHMID_INDEX_MAXBITS 6 /* Max # of bits needed to store NUM_RTNOBJ_SHM_INDEX */
+#define MIN_RTNOBJ_SHM_INDEX 20 /* Minimum size of shared memory segment created to store .o (rtnobj) files is 2**20.
+ * Do not change this macro as gtm_autorelink_shm env var is specified in a multiple of
+ * 2**MIN_RTNOBJ_SHM_INDEX bytes and will have user doc implications.
+ */
+#define MAX_RTNOBJ_SHM_INDEX 58 /* Maximum size of shared memory segment created to store .o (rtnobj) files is 2**57 */
+#define NUM_RTNOBJ_SHM_INDEX (MAX_RTNOBJ_SHM_INDEX - MIN_RTNOBJ_SHM_INDEX)
+
+#define NULL_RTNOBJ_SM_OFF_T ((sm_off_t)MAXUINT8) /* Is (2**64 - 1) i.e. 0xFFFF FFFF FFFF FFFF */
+
+#define RTNOBJ_GET_SHM_INDEX(SHM_OFF) (SHM_OFF >> MAX_RTNOBJ_SHM_INDEX)
+#define RTNOBJ_GET_SHM_OFFSET(SHM_OFF) (SHM_OFF & 0x03FFFFFFFFFFFFFFULL)
+#define RTNOBJ_SET_SHM_INDEX_OFF(SHM_INDEX, SHM_OFF) (((rtnobj_sm_off_t)SHM_INDEX << MAX_RTNOBJ_SHM_INDEX) | (SHM_OFF))
+
+#define RLNKSHM_LATCH_TIMEOUT_SEC 60 /* Want to wait 60 seconds max */
+#define RLNKREC_LATCH_TIMEOUT_SEC 60 /* Want to wait 60 seconds max */
+
+#define MIN_RTNOBJ_SIZE_BITS 8 /* Minimum object file size (including SIZEOF(rtnobj_hdr_t)) is 2**8 = 256 */
+#define MAX_RTNOBJ_SIZE_BITS MAX_RTNOBJ_SHM_INDEX /* Maximum object file size (including SIZEOF(rtnobj_hdr_t)) is 2**32
+ * but when we allocate a rtnobj shared memory segment of size
+ * (2**MAX_RTNOBJ_SHM_INDEX) we want to add that as one element to the
+ * "rtnobjshm_hdr_t->freeList[]" array and hence this definition.
+ */
+#define NUM_RTNOBJ_SIZE_BITS (MAX_RTNOBJ_SIZE_BITS + 1 - MIN_RTNOBJ_SIZE_BITS)
-/* Shared structure - relink record in a relinkctl (mmap'd) file */
+#define IS_INSERT 0
+#define IS_DELETE 1
+
+#define ISSUE_RELINKCTLERR_SYSCALL(ZRO_ENTRY_NAME, ERRSTR, ERRNO) \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_RELINKCTLERR, 2, RTS_ERROR_MSTR(ZRO_ENTRY_NAME), \
+ ERR_SYSCALL, 5, LEN_AND_STR(ERRSTR), CALLFROM, DEBUG_ONLY(saved_errno = )ERRNO)
+
+#define ISSUE_RELINKCTLERR_TEXT(ZRO_ENTRY_NAME, ERRORTEXT, ERRNO) \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_RELINKCTLERR, 2, RTS_ERROR_MSTR(ZRO_ENTRY_NAME), \
+ ERR_TEXT, 2, LEN_AND_STR(ERRORTEXT), DEBUG_ONLY(saved_errno = )ERRNO)
+
+typedef gtm_uint64_t rtnobj_sm_off_t;
+
+/* Shared structure - relink record corresponding to a relinkctl file (resides in shared memory) */
typedef struct relinkrec_struct
{
mident_fixed rtnname_fixed;
uint4 cycle;
- /* TODO: Add hash or tree or sorted list lookup for speed */
+ uint4 hashindex_fl; /* Forward link ptr to linked list of relinkrec_t structures that have same rtnhash value */
+ uint4 numvers; /* Number of versions of this .o file currently in this relinkctl shared memory */
+ uint4 filler_8byte_align;
+ gtm_uint64_t objLen; /* Total object file length of various versions of this .o file in shared memory */
+ gtm_uint64_t usedLen; /* Total length used up in shared memory for various versions of this .o file.
+ * Due to rounding up of objLen to nearest 2-power, usedLen >= objLen always.
+ */
+ rtnobj_sm_off_t rtnobj_shm_offset; /* offset into shared memory where this object file can be found for linking.
+ * If object is not loaded, set to NULL_RTNOBJ_SM_OFF_T.
+ */
+ global_latch_t rtnobj_latch; /* Lock used to search/insert/delete entries in the
+ * object file linked list (starting at rtnobj_shm_offset)
+ */
+ gtm_uint64_t objhash; /* Hash of the object file last touched here */
+ CACHELINE_PAD_COND(88, 1) /* Add 40 bytes (on top of 88 bytes) to make this structure 128 bytes to avoid cacheline
+ * interference (between successive relinkrec_t structures in shared memory) on the RS6000
+ * (where the cacheline is 128 bytes currently). Other platforms have smaller
+ * cachelines (i.e. 64 bytes or lesser) and so this structure (88 bytes currently)
+ * taking up more than one cacheline dont require this padding.
+ */
} relinkrec_t;
+#define ZRO_DIR_PATH_MAX 255
+
/* Shared structure - relinkctl file header */
typedef struct relinkctl_data_struct
{
- /* TODO: Add zro_entry_name, so that we can "rundown" or delete desired structs */
uint4 n_records;
int4 nattached; /* Number of processes currently attached. this is approximate, because if a process
* is kill 9'd, nattached is not decrememented.
@@ -66,36 +162,140 @@ typedef struct relinkctl_data_struct
* 1. SYSV semaphore (as with the db). increment in open_relinkctl
* 2. When we want to cleanup (say mupip routine -rundown), execute 'fuser'
*/
- global_latch_t attach_latch;
- relinkrec_t base[1];
+ int4 relinkctl_shmid;/* ID of primary shared memory segment corresponding to the mmaped relinkctl file.
+ * This contains the array of relinkrec_t structures as well as hash buckets to
+ * speed up search of routine names.
+ */
+ uint4 relinkctl_shmlen;/* size of shared memory */
+ int4 file_deleted; /* Way of signaling processes in relinkctl_open about a concurrent delete so they
+ * close their fd and reopen the file.
+ */
+ uint4 initialized; /* relinkctl file has been successfully initialized */
+ char zro_entry_name[ZRO_DIR_PATH_MAX + 1]; /* null-terminated full path of the directory in $zroutines
+ * whose relinkctl file is this. Given a relinkctl file, one can
+ * use this to find the corresponding directory.
+ */
+ int zro_entry_name_len; /* strlen of the null-terminated "zro_entry_name" */
} relinkctl_data;
-typedef off_t relinkrec_ptr_rel_t; /* Relative offset of relinkrec */
-typedef relinkrec_t *relinkrec_ptr_abs_t; /* Absolute pointer to relinkrec */
-/* For now at least, use relative pointers as primary way of referring to shared relink records */
-typedef relinkrec_ptr_rel_t relinkrec_loc_t;
-
/* Process private structure - describes a relinkctl file. Process private so can be linked into a list in $ZROUTINES order */
typedef struct open_relinkctl_struct
{
struct open_relinkctl_struct *next; /* List of open ctl structures, sorted by zro_entry_name */
- mstr zro_entry_name; /* Text resident in stringpool */
- int fd;
+ mstr zro_entry_name; /* object directory name from $zroutines */
+ char *relinkctl_path; /* full path of the relinkctl file corresponding to this objdir */
uint4 n_records; /* Private copy */
+ boolean_t locked; /* TRUE if this process owns exclusive lock */
relinkctl_data *hdr; /* Base of mapped file */
relinkrec_t *rec_base;
- boolean_t locked; /* TRUE if this process owns exclusive lock */
+ sm_uint_ptr_t shm_hashbase; /* base of hash table in shared memory */
+ sm_uc_ptr_t rtnobj_shm_base[NUM_RTNOBJ_SHM_INDEX];
+ int rtnobj_shmid[NUM_RTNOBJ_SHM_INDEX];
+ int fd;
+ int rtnobj_shmid_cycle; /* copied over from relinkshm_hdr->shmid_cycle after
+ * ensuring all relinkshm_hdr->shmid[NUM_RTNOBJ_SHM_INDEX] is
+ * copied over and all those shmids have been successfully
+ * shmat()ed.
+ */
+ int rtnobj_min_shm_index; /* Copied over from relinkshm_hdr->rtnobj_min_shm_index */
+ int rtnobj_max_shm_index; /* Copied over from relinkshm_hdr->rtnobj_max_shm_index */
} open_relinkctl_sgm;
+typedef struct rtnobjshm_hdr_struct
+{
+ que_ent freeList[NUM_RTNOBJ_SIZE_BITS];
+ int rtnobj_min_free_index; /* minimum 'i' where freeList[i] has non-zero fl,bl links */
+ int rtnobj_max_free_index; /* maximum 'i' where freeList[i-1] has non-zero fl,bl links
+ * if no freeList[i] has non-zero fl,bl links, this will be set to 0.
+ */
+ int rtnobj_shmid;
+ gtm_uint64_t real_len; /* sum of realLen of .o files used currently in this rtnobj shared memory segment */
+ gtm_uint64_t used_len; /* sum of space occupied by .o files currently in this rtnobj shared memory segment */
+ gtm_uint64_t shm_len; /* size of shared memory segment */
+} rtnobjshm_hdr_t;
+
+/* Shared memory header structure corresponding to relinkctl file. This is followed by a hash-array for speedy routine name
+ * access.
+ */
+typedef struct relinkshm_hdr
+{
+ char relinkctl_fname[GTM_PATH_MAX]; /* full path of the relinkctl file (mmr hash is in this name) */
+ int min_shm_index;
+ int rtnobj_min_shm_index; /* Minimum 'i' where rtnobj_shmhdr[i].rtnobj_shmid is a valid shmid */
+ int rtnobj_max_shm_index; /* Maximum 'i' where rtnobj_shmhdr[i-1].rtnobj_shmid is a valid shmid.
+ * If no rtnobj_shmhdr[i] has valid shmid, this will be set to 0.
+ */
+ int rtnobj_shmid_cycle; /* bumped when rtnobj_shmhdr[i].rtnobj_shmid gets created for some 'i' */
+ boolean_t rndwn_adjusted_nattch; /* MUPIP RUNDOWN -RELINKCTL did adjust nattached */
+# ifdef DEBUG
+ boolean_t skip_rundown_check; /* TRUE if at least one process with gtm_autorelink_keeprtn=1 opened this */
+# endif
+ rtnobjshm_hdr_t rtnobj_shmhdr[NUM_RTNOBJ_SHM_INDEX];
+ /* CACHELINE_PAD macro usages surrounding the actual latch below provides spacing so updates to the latch do not interfere
+ * with updates to adjoining fields which can happen if they fall in the same data cacheline of a processor. No
+ * CACHELINE_PAD before the latch as adjoining fields before the latch are updated only if we hold the latch so no
+ * interference possible.
+ */
+ global_latch_t relinkctl_latch; /* latch for insertions/deletions of buddy list structurs in any rtnobj shmids */
+ CACHELINE_PAD(SIZEOF(global_latch_t), 1)
+} relinkshm_hdr_t;
+
+#define STATE_FREE 0
+#define STATE_ALLOCATED 1
+
+/* "refcnt" is a signed 4-byte integer so the max it can go to is 2**31-1.
+ * Once it reaches this value, we can no longer accurately maintain refcnt (rollover issues).
+ * So keep it there thereby never removing the corresponding object from shared memory.
+ */
+#define REFCNT_INACCURATE MAXPOSINT4
+
+/* Header structure for each .o file in the "rtnobj" shared memory */
+typedef struct rtnobj_hdr_struct
+{
+ unsigned short queueIndex; /* 2**queueIndex is the size of this element (including this header) */
+ unsigned char state; /* State of this block */
+ unsigned char initialized; /* Has the .o file been read from disk into this slot */
+ int4 refcnt; /* # of processes that are currently using this .o file */
+ gtm_uint64_t objhash; /* 8-byte checksum of object file contents.
+ * Used to differentiate multiple versions of the .o file with the same
+ * routine name; Each gets a different routine buffer in shared memory.
+ */
+ rtnobj_sm_off_t next_rtnobj_shm_offset; /* Offset into shared memory where the routine buffer of the .o file with
+ * the same name as this one can be found but with a different checksum.
+ * Basically a linked list. Null pointer set to NULL_RTNOBJ_SM_OFF_T.
+ */
+ uint4 relinkctl_index; /* Index into reclinkrec_t[] array where the rtnname corresponding to this
+ * .o file can be found; Note multiple versions of .o file with different
+ * <src_cksum_8byte,objLen> values will have different routine buffers in
+ * shared memory each of them pointing back to the same relinkctl_index.
+ */
+ uint4 objLen; /* Size of the allocated .o file. Currently not allowed to go > 4Gb.
+ * <src_cksum_8byte,objLen> together are used to differentiate multiple
+ * versions of the same .o file name; Each of them with a different value
+ * of either src_cksum_8byte or objLen gets a different routine buffer in
+ * shared memory. Note that it is theoretically possible (though rare) that
+ * two different .o files have the same 8-byte src checksum and same objLen.
+ * In that case they will use the same routine buffer. But since we expect
+ * this to be very rare in practice, we consider this acceptable for now.
+ */
+ union
+ {
+ que_ent freePtr; /* Pointer to next and previous storage element on free queue */
+ unsigned char userStart; /* First byte of user useable storage */
+ } userStorage;
+} rtnobj_hdr_t;
+
/*
* Prototypes
*/
open_relinkctl_sgm *relinkctl_attach(mstr *obj_container_name);
-relinkrec_loc_t relinkctl_find_record(open_relinkctl_sgm *linkctl, mstr *rtnname);
-relinkrec_loc_t relinkctl_insert_record(open_relinkctl_sgm *linkctl, mstr *rtnname);
+void relinkctl_incr_nattached(void);
+int relinkctl_get_key(char key[GTM_PATH_MAX], mstr *zro_entry_name);
+relinkrec_t *relinkctl_find_record(open_relinkctl_sgm *linkctl, mstr *rtnname, uint4 hash, uint4 *prev_hash_index);
+relinkrec_t *relinkctl_insert_record(open_relinkctl_sgm *linkctl, mstr *rtnname);
void relinkctl_open(open_relinkctl_sgm *linkctl);
-void relinkctl_ensure_fullmap(open_relinkctl_sgm *linkctl);
void relinkctl_lock_exclu(open_relinkctl_sgm *linkctl);
void relinkctl_unlock_exclu(open_relinkctl_sgm *linkctl);
-void relinkctl_rundown(boolean_t decr_attached);
+void relinkctl_rundown(boolean_t decr_attached, boolean_t do_rtnobj_shm_free);
+
#endif /* RELINKCTL_H_INCLUDED */
diff --git a/sr_unix/repl_inst_dump.c b/sr_unix/repl_inst_dump.c
index 94e7e63..9a5461c 100644
--- a/sr_unix/repl_inst_dump.c
+++ b/sr_unix/repl_inst_dump.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2006, 2013 Fidelity Information Services, Inc *
+ * Copyright 2006, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -821,6 +821,10 @@ void repl_inst_dump_gtmsourcelocal(gtmsource_local_ptr_t gtmsourcelocal_ptr)
string, gtmsourcelocal_ptr->read_state);
}
+ PRINT_OFFSET_PREFIX(offsetof(gtmsource_local_struct, jnlfileonly), SIZEOF(gtmsourcelocal_ptr->jnlfileonly));
+ PRINT_BOOLEAN(PREFIX_SOURCELOCAL "Journal File Only !R12AZ",
+ gtmsourcelocal_ptr->jnlfileonly, idx);
+
PRINT_OFFSET_PREFIX(offsetof(gtmsource_local_struct, read), SIZEOF(gtmsourcelocal_ptr->read));
util_out_print( PREFIX_SOURCELOCAL "Relative Read Offset !10UL [0x!XL]", TRUE, idx,
gtmsourcelocal_ptr->read, gtmsourcelocal_ptr->read);
diff --git a/sr_unix/repl_msg.h b/sr_unix/repl_msg.h
index 5ade5bf..5eb67b8 100644
--- a/sr_unix/repl_msg.h
+++ b/sr_unix/repl_msg.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2006, 2013 Fidelity Information Services, Inc *
+ * Copyright 2006, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -66,10 +66,11 @@ enum
#define REPL_PROTO_VER_MULTISITE_CMP (char)0x2 /* Versions V5.3-003 and above that support multisite replication with
* the ability to compress the logical records in the replication pipe.
*/
-#define REPL_PROTO_VER_SUPPLEMENTARY (char)0x3 /* Versions V5.5-000 and above that support supplementary instances */
-#define REPL_PROTO_VER_REMOTE_LOGPATH (char)0x4 /* Versions V6.0-003 and above that send remote $CWD as part of handshake */
-#define REPL_PROTO_VER_TLS_SUPPORT (char)0x5 /* Versions V6.1-000 and above that supports SSL/TLS communication. */
-#define REPL_PROTO_VER_THIS REPL_PROTO_VER_TLS_SUPPORT
+#define REPL_PROTO_VER_SUPPLEMENTARY (char)0x3 /* Versions >= V5.5-000 that support supplementary instances */
+#define REPL_PROTO_VER_REMOTE_LOGPATH (char)0x4 /* Versions >= V6.0-003 that send remote $CWD as part of handshake */
+#define REPL_PROTO_VER_TLS_SUPPORT (char)0x5 /* Versions >= V6.1-000 that supports SSL/TLS communication. */
+#define REPL_PROTO_VER_XENDIANFIXES (char)0x6 /* Versions >= V6.2-001 support cross-endian replication (GTM-8205) */
+#define REPL_PROTO_VER_THIS REPL_PROTO_VER_XENDIANFIXES
/* The current/latest version of the communication protocol between the
* primary (source server) and secondary (receiver server or rollback)
*/
@@ -225,7 +226,8 @@ typedef struct /* used to send a message of type REPL_NEED_INSTINFO */
* the macros REPL_PROTO_VER_DUALSITE (0) and REPL_PROTO_VER_UNINITIALIZED (-1) */
char is_rootprimary; /* Whether the source server that is sending this message is a root primary or not. */
char is_supplementary; /* TRUE for a supplementary instance; FALSE otherwise */
- char filler_32[5];
+ char jnl_ver; /* jnl format of this side */
+ char filler_32[4];
} repl_needinst_msg_t; /* The first two fields should be as in repl_msg_t */
typedef struct /* used to send a message of type REPL_OLD_INSTANCE_INFO */
diff --git a/sr_unix/rtnhdr.h b/sr_unix/rtnhdr.h
index aa173fb..8b0ac0d 100644
--- a/sr_unix/rtnhdr.h
+++ b/sr_unix/rtnhdr.h
@@ -52,6 +52,35 @@ typedef struct
char_ptr_t ext_ref; /* Address (quadword on alpha) this linkage entry resolves to or NULL */
} lnk_tabent;
+#ifdef AUTORELINK_SUPPORTED
+#include "relinkctl.h" /* Needed for open_relinkctl_sgm type in zro_validation_entry */
+/* Link search history entry - contains information to find the record in the relevant relinkctl file and what
+ * the cycle was when loaded.
+ */
+typedef struct
+{
+ uint4 cycle; /* Copy of relinkctl file cycle when loaded */
+ relinkrec_t *relinkrec; /* Pointer to relinkctl record */
+ open_relinkctl_sgm *relinkctl_bkptr; /* Address of mapped relinkctl file */
+} zro_validation_entry;
+/* Header for search history block */
+typedef struct
+{
+ uint4 zroutines_cycle; /* Value of set_zroutines_cycle when history created */
+ zro_validation_entry *end; /* -> Last record + 1 */
+ zro_validation_entry base[1]; /* First history record (others follow) */
+} zro_hist;
+/* Structure used to queue up a list of validation entries and routine names before finalizing them into a
+ * zro_hist structure.
+ */
+typedef struct
+{
+ zro_validation_entry zro_valent; /* Validation entry data (this record) */
+ mident_fixed rtnname; /* Routine name associated with this validation entry */
+ int4 rtnname_len;
+} zro_search_hist_ent;
+#endif
+
/* rhead_struct is the routine header; it occurs at the beginning of the
* object code part of each module. Since this structure may be resident in
* a shared library, this structure is considered inviolate. Therefore there is
@@ -87,12 +116,15 @@ typedef struct rhead_struct
int4 lnrtab_len; /* Number of linenumber table entries */
unsigned char *literal_text_adr; /* Address of literal text pool (offset in original rtnhdr) */
int4 literal_text_len; /* Length of literal text pool */
+ boolean_t shared_object; /* Linked as a shared object */
mval *literal_adr; /* (#) Address of literal mvals (offset in original rtnhdr) */
int4 literal_len; /* Number of literal mvals */
lnk_tabent *linkage_adr; /* (#) Address of linkage Psect (offset in original rtnhdr) */
int4 linkage_len; /* Number of linkage entries */
int4 rel_table_off; /* Offset to relocation table (not kept) */
int4 sym_table_off; /* Offset to symbol table (not kept) */
+ boolean_t rtn_relinked; /* Routine has been relinked while this version was active. Check on
+ * unwind to see if this routine needs to be cleaned up. */
unsigned char *shared_ptext_adr; /* If shared routine (shared library or object), points to shared copy */
unsigned char *ptext_adr; /* (#) address of start of instructions (offset in original rtnhdr)
* If shared routine, points to shared copy unless breakpoints are active.
@@ -102,6 +134,7 @@ typedef struct rhead_struct
int4 checksum; /* 4-byte source code checksum (for platforms where MD5 is unavailable) */
int4 temp_mvals; /* (#) temp_mvals value of current module version */
int4 temp_size; /* (#) temp_size value of current module version */
+ boolean_t has_ZBREAK; /* This routine has a ZBREAK in it - disable it for autorelink */
struct rhead_struct *current_rhead_adr; /* (#) Address of routine header of current module version */
struct rhead_struct *old_rhead_adr; /* (#) Chain of replaced routine headers */
# ifdef GTM_TRIGGER
@@ -109,14 +142,18 @@ typedef struct rhead_struct
# else
void_ptr_t filler1;
# endif
- unsigned char checksum_md5[16]; /* 16-byte MD5 checksum of routine source code */
+ unsigned char checksum_128[16]; /* 16-byte MurmurHash3 checksum of routine source code */
struct rhead_struct *active_rhead_adr; /* Chain of active old versions, fully reserved for continued use */
routine_source *source_code; /* Source code used by $TEXT */
- void_ptr_t zhist; /* If shared object -> validation list/array (actual type is zro_hist *) */
+ ARLINK_ONLY(zro_hist *zhist;) /* If shared object -> validation list/array */
+ gtm_uint64_t objhash; /* When object file is created, contains hash of object file */
unsigned char *lbltext_ptr; /* Label name text blob if shared object replaced */
- uint4 shared_len; /* Length of mmaped segment (needed for munmap) */
+ uint4 object_len; /* Length of wrapped GT.M object */
uint4 routine_source_offset; /* Offset of M source within literal text pool */
- IA64_ONLY(void_ptr_t filler2;) /* IA64 needs 16 byte alignment */
+ mstr *linkage_names; /* Offset to mstr table of symbol names indexed same as linkage table */
+# ifdef AUTORELINK_SUPPORTED
+ open_relinkctl_sgm *relinkctl_bkptr; /* Back pointer to relinkctl file that loaded this shared rtnobj */
+# endif
} rhdtyp;
/* Routine table entry */
@@ -178,6 +215,20 @@ typedef struct
/* Types that are different depending on shared/unshared unix binaries */
#define LABENT_LNR_OFFSET lnr_adr
+/* When a routine is recursively linked, the old routine hdr/label table are copied and
+ * attached to active_rhead_adr pointer of the replaced routine header. At unwind or goto time,
+ * we check if these copies can be cleaned up with the following macro.
+ */
+#define CLEANUP_COPIED_RECURSIVE_RTN(RTNHDR) \
+{ \
+ /* For USHBIN_SUPPORTED routines, if the rtn_relinked flag is ON in the routine header (which results from not cleaning \
+ * up a routine when it is either explicitly or automatically re-linked), check if the stack contains any more \
+ * references to this routine header. If not, it is ripe for cleanup as it has been replaced so drive zr_unlink_rtn() \
+ * on it. \
+ */ \
+ if ((RTNHDR)->rtn_relinked) \
+ zr_cleanup_recursive_rtn(RTNHDR); \
+}
/* Format of a relocation datum. */
struct relocation_info
{
@@ -221,7 +272,7 @@ struct sym_table
#define NOVERIFY FALSE
/* Prototypes */
-int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_t verifytrig);
+int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, rhdtyp **rtn_vec);
void free_src_tbl(rhdtyp *rtn_vector);
unsigned char *find_line_start(unsigned char *in_addr, rhdtyp *routine);
int4 *find_line_addr(rhdtyp *routine, mstr *label, int4 offset, mident **lent_name);
@@ -239,5 +290,12 @@ char *rtnlaboff2entryref(char *entryref_buff, mident *rtn, mident *lab, int offs
boolean_t on_stack(rhdtyp *rtnhdr, boolean_t *need_duplicate);
rhdtyp *op_rhd_ext(mval *rtname, mval *lblname, rhdtyp *rhd, void *lnr);
void *op_lab_ext(void);
+void zr_cleanup_recursive_rtn(rhdtyp *rtnhdr);
+#ifdef AUTORELINK_SUPPORTED
+#include "zroutinessp.h" /* Needed for zro_ent type for zro_record_zhist declaration */
+boolean_t need_relink(rhdtyp *rtnhdr, zro_hist *zhist);
+zro_hist *zro_zhist_saverecent(zro_search_hist_ent *zhist_valent, zro_search_hist_ent *zhist_valent_base);
+void zro_record_zhist(zro_search_hist_ent *zhist_valent, zro_ent *obj_container, mstr *rtnname);
+#endif /* AUTORELINK_DEFINED */
#endif /* RTNHDR_H_INCLUDED */
diff --git a/sr_unix/rtnobj.c b/sr_unix/rtnobj.c
new file mode 100644
index 0000000..cd10223
--- /dev/null
+++ b/sr_unix/rtnobj.c
@@ -0,0 +1,997 @@
+/****************************************************************
+ * *
+ * Copyright 2014 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <sys/shm.h>
+#include <sys/mman.h>
+
+#include "gtm_ipc.h"
+#include "gtm_string.h"
+#include "gtm_stdio.h"
+
+#include "rtnobj.h"
+#include "gtmio.h"
+#include <rtnhdr.h>
+#include "iosp.h"
+#include "do_shmat.h"
+#include "min_max.h"
+#include "relqop.h"
+#include "ipcrmid.h"
+#include "interlock.h"
+#include "gdsroot.h" /* for CDB_STAGNATE */
+#include "incr_link.h" /* for NATIVE_HDR_LEN */
+#include "hugetlbfs_overrides.h" /* for the ADJUST_SHM_SIZE_FOR_HUGEPAGES macro */
+#include "gtm_permissions.h"
+#include "cachectl.h"
+#include "cacheflush.h"
+
+/* Uncomment below line if you want RTNOBJ_DBG lines to be enabled */
+/* #define RTNOBJ_DEBUG */
+
+#ifdef RTNOBJ_DEBUG
+# define RTNOBJ_DBG(X) X
+#else
+# define RTNOBJ_DBG(X)
+#endif
+
+#define CONTINUE_IF_INDEX_INVALID(MIN_INDEX, MAX_INDEX, HAS_RELINKCTL_LOCK) \
+{ \
+ if (!HAS_RELINKCTL_LOCK) \
+ { /* If we dont have a lock, and MIN_INDEX/MAX_INDEX are invalid, redo loop \
+ * until we find valid values. After a few redos, get a lock before the search. \
+ */ \
+ if ((0 > MIN_INDEX) || (NUM_RTNOBJ_SHM_INDEX < MIN_INDEX) \
+ || (0 > MAX_INDEX) || (NUM_RTNOBJ_SHM_INDEX < MAX_INDEX)) \
+ { \
+ continue; \
+ } \
+ } else \
+ { \
+ assert(0 <= MIN_INDEX); \
+ assert(NUM_RTNOBJ_SHM_INDEX >= MIN_INDEX); \
+ assert(0 <= MAX_INDEX); \
+ assert(NUM_RTNOBJ_SHM_INDEX >= MAX_INDEX); \
+ } \
+}
+
+#define SYNC_RTNOBJ_SHMID_CYCLE_IF_NEEDED(LINKCTL, MIN_INDEX, MAX_INDEX, SHM_HDR, HAS_RELINKCTL_LOCK, RELINKREC) \
+{ \
+ int cycle, i, pvt_shmid, shr_shmid; \
+ int save_errno; \
+ size_t shm_size; \
+ sm_uc_ptr_t shm_base; \
+ char errstr[256]; \
+ \
+ cycle = SHM_HDR->rtnobj_shmid_cycle; \
+ /* NARSTODO: Need memory barrier? Since cycle/MIN_INDEX/MAX_INDEX could be read out-of-order */ \
+ if (LINKCTL->rtnobj_shmid_cycle != cycle) \
+ { \
+ MIN_INDEX = SHM_HDR->rtnobj_min_shm_index; \
+ MAX_INDEX = SHM_HDR->rtnobj_max_shm_index; \
+ /* Check integrity of min_index/max_index */ \
+ CONTINUE_IF_INDEX_INVALID(MIN_INDEX, MAX_INDEX, HAS_RELINKCTL_LOCK); \
+ for (i = MIN_INDEX; i < MAX_INDEX; i++) \
+ { \
+ pvt_shmid = LINKCTL->rtnobj_shmid[i]; \
+ shr_shmid = SHM_HDR->rtnobj_shmhdr[i].rtnobj_shmid; \
+ if (pvt_shmid != shr_shmid) \
+ { \
+ assert(INVALID_SHMID == pvt_shmid); /* currently rtnobj shmids are never deleted */ \
+ shm_size = ((size_t)1 << (i + MIN_RTNOBJ_SHM_INDEX)); \
+ shm_base = (sm_uc_ptr_t)do_shmat_exec_perm(shr_shmid, shm_size, &save_errno); \
+ if (-1 == (sm_long_t)shm_base) \
+ { \
+ if (HAS_RELINKCTL_LOCK) \
+ rel_latch(&SHM_HDR->relinkctl_latch); \
+ rel_latch(&RELINKREC->rtnobj_latch); \
+ SNPRINTF(errstr, SIZEOF(errstr), "rtnobj2 shmat() failed for shmid=%d shmsize=0x%llx", \
+ shr_shmid, shm_size); \
+ ISSUE_RELINKCTLERR_SYSCALL(&LINKCTL->zro_entry_name, errstr, save_errno); \
+ } \
+ assert(0 == ((UINTPTR_T)shm_base % 8)); \
+ LINKCTL->rtnobj_shmid[i] = shr_shmid; \
+ LINKCTL->rtnobj_shm_base[i] = shm_base; \
+ } \
+ } \
+ LINKCTL->rtnobj_min_shm_index = min_index; \
+ LINKCTL->rtnobj_max_shm_index = max_index; \
+ LINKCTL->rtnobj_shmid_cycle = cycle; \
+ } else \
+ { \
+ MIN_INDEX = linkctl->rtnobj_min_shm_index; \
+ MAX_INDEX = linkctl->rtnobj_max_shm_index; \
+ CONTINUE_IF_INDEX_INVALID(MIN_INDEX, MAX_INDEX, HAS_RELINKCTL_LOCK); \
+ } \
+}
+
+#ifdef AUTORELINK_SUPPORTED
+
+error_def(ERR_PERMGENFAIL);
+error_def(ERR_RELINKCTLERR);
+error_def(ERR_RLNKRECLATCH);
+error_def(ERR_RLNKSHMLATCH);
+error_def(ERR_SYSCALL);
+
+DEBUG_ONLY(GBLREF int saved_errno;)
+
+#ifdef DEBUG
+void rtnobj_verify_freelist_fl_bl(rtnobjshm_hdr_t *rtnobj_shm_hdr, sm_uc_ptr_t shm_base)
+{
+ int min_index, max_index, i;
+ que_ent_ptr_t freeList, elem, prev_elem;
+ rtnobj_hdr_t *rtnobj, *rtnobj2;
+ sm_off_t rtnobj_off;
+ gtm_uint64_t elemSize;
+ sm_uc_ptr_t shm_top;
+
+ freeList = &rtnobj_shm_hdr->freeList[0];
+ shm_top = shm_base + rtnobj_shm_hdr->shm_len;
+ for (i = 0; i < NUM_RTNOBJ_SIZE_BITS; i++, freeList++)
+ {
+ if (NULL_RTNOBJ_SM_OFF_T != freeList->fl)
+ {
+ assert(NULL_RTNOBJ_SM_OFF_T != freeList->bl);
+ assert(0 == freeList->fl % 8);
+ prev_elem = NULL;
+ elem = (que_ent_ptr_t)(shm_base + freeList->fl);
+ do
+ {
+ rtnobj = (rtnobj_hdr_t *)((sm_uc_ptr_t)elem - OFFSETOF(rtnobj_hdr_t, userStorage));
+ assert(STATE_FREE == rtnobj->state);
+ assert(i == rtnobj->queueIndex);
+ rtnobj_off = (sm_uc_ptr_t)rtnobj - shm_base;
+ elemSize = ((gtm_uint64_t)1 << (rtnobj->queueIndex + MIN_RTNOBJ_SIZE_BITS));
+ rtnobj2 = (rtnobj_hdr_t *)(shm_base + (rtnobj_off ^ elemSize)); /* address of buddy */
+ assert(((sm_uc_ptr_t)rtnobj2 == shm_top) || (rtnobj2->queueIndex <= rtnobj->queueIndex));
+ if (NULL_RTNOBJ_SM_OFF_T == elem->bl)
+ assert(NULL == prev_elem);
+ else
+ assert(((NULL == prev_elem) && (NULL_RTNOBJ_SM_OFF_T == elem->bl))
+ || (prev_elem->fl == -elem->bl));
+ if (NULL_RTNOBJ_SM_OFF_T == elem->fl)
+ {
+ assert(elem == (que_ent_ptr_t)(shm_base + freeList->bl));
+ break;
+ }
+ assert(0 == elem->fl % 8);
+ prev_elem = elem;
+ elem = (que_ent_ptr_t)((sm_uc_ptr_t)elem + elem->fl);
+ }
+ while (TRUE);
+ } else
+ assert(NULL_RTNOBJ_SM_OFF_T == freeList->bl);
+ }
+}
+
+void rtnobj_verify_min_max_free_index(rtnobjshm_hdr_t *rtnobj_shm_hdr)
+{
+ int min_index, max_index, i;
+ que_ent_ptr_t freeList;
+
+ min_index = NUM_RTNOBJ_SIZE_BITS;
+ max_index = 0;
+ freeList = &rtnobj_shm_hdr->freeList[0];
+ for (i = 0; i < NUM_RTNOBJ_SIZE_BITS; i++, freeList++)
+ {
+ if (NULL_RTNOBJ_SM_OFF_T != freeList->fl)
+ {
+ if (min_index > i)
+ min_index = i;
+ if (max_index < (i + 1))
+ max_index = i + 1;
+ }
+ }
+ assert(min_index == rtnobj_shm_hdr->rtnobj_min_free_index);
+ assert(max_index == rtnobj_shm_hdr->rtnobj_max_free_index);
+}
+#endif
+
+/* Insert an element at the tail of the queue */
+void insqt_rtnobj(que_ent_ptr_t new_tail, que_ent_ptr_t que_base, sm_uc_ptr_t shm_base)
+{
+ que_ent_ptr_t old_tail;
+
+ RTNOBJ_DBG(fprintf(stderr, "insqt_rtnobj : que_base = 0x%llx : shm_base = 0x%llx : elem = 0x%llx\n", \
+ (long long unsigned int)que_base, (long long unsigned int)shm_base, (long long unsigned int)new_tail);)
+ if (NULL_RTNOBJ_SM_OFF_T == que_base->bl)
+ { /* Queue has nothing */
+ assert(NULL_RTNOBJ_SM_OFF_T == que_base->fl);
+ que_base->fl = (uchar_ptr_t)new_tail - (uchar_ptr_t)shm_base;
+ assert(0 == que_base->fl % 8);
+ que_base->bl = que_base->fl;
+ new_tail->fl = NULL_RTNOBJ_SM_OFF_T;
+ new_tail->bl = NULL_RTNOBJ_SM_OFF_T;
+ } else
+ {
+ old_tail = (que_ent_ptr_t)(shm_base + que_base->bl);
+ assert(NULL_RTNOBJ_SM_OFF_T == old_tail->fl);
+ new_tail->fl = NULL_RTNOBJ_SM_OFF_T;
+ new_tail->bl = (uchar_ptr_t)old_tail - (uchar_ptr_t)new_tail;
+ assert(0 == new_tail->bl % 8);
+ old_tail->fl = -new_tail->bl;
+ que_base->bl += old_tail->fl;
+ }
+ return;
+}
+
+/* Remove an element from the head of the queue */
+rtnobj_hdr_t *remqh_rtnobj(que_ent_ptr_t que_base, sm_uc_ptr_t shm_base)
+{
+ que_ent_ptr_t ret, new_head;
+ rtnobj_hdr_t *rtnobj;
+
+ assert(NULL_RTNOBJ_SM_OFF_T != que_base->fl);
+ ret = (que_ent_ptr_t)(shm_base + que_base->fl);
+ RTNOBJ_DBG(fprintf(stderr, "remqh_rtnobj : que_base = 0x%llx : shm_base = 0x%llx : elem = 0x%llx\n", \
+ (long long unsigned int)que_base, (long long unsigned int)shm_base, (long long unsigned int)ret);)
+ assert(0 == (sm_off_t)ret % 8);
+ assert(NULL_RTNOBJ_SM_OFF_T == ret->bl);
+ if (NULL_RTNOBJ_SM_OFF_T == ret->fl)
+ { /* Empty queue after this removal */
+ que_base->fl = NULL_RTNOBJ_SM_OFF_T;
+ que_base->bl = NULL_RTNOBJ_SM_OFF_T;
+ } else
+ {
+ new_head = (que_ent_ptr_t)((uchar_ptr_t)ret + ret->fl);
+ assert(0 == (sm_off_t)new_head % 8);
+ new_head->bl = NULL_RTNOBJ_SM_OFF_T;
+ assert(0 == que_base->fl % 8);
+ que_base->fl += ret->fl;
+ }
+ rtnobj = (rtnobj_hdr_t *)((sm_uc_ptr_t)ret - OFFSETOF(rtnobj_hdr_t, userStorage));
+ return rtnobj;
+}
+
+/* Remove a specific element "rtnobj" from wherever it is in the queue */
+void remq_rtnobj_specific(que_ent_ptr_t que_base, sm_uc_ptr_t shm_base, rtnobj_hdr_t *rtnobj)
+{
+ que_ent_ptr_t elem, new_head, rtnque;
+
+ assert(NULL_RTNOBJ_SM_OFF_T != que_base->fl);
+ rtnque = (que_ent_ptr_t)((sm_uc_ptr_t)rtnobj + OFFSETOF(rtnobj_hdr_t, userStorage));
+ RTNOBJ_DBG(fprintf(stderr, "remqh_rtnobj_specific : que_base = 0x%llx : shm_base = 0x%llx : elem = 0x%llx\n", \
+ (long long unsigned int)que_base, (long long unsigned int)shm_base, (long long unsigned int)rtnque);)
+# ifdef DEBUG
+ /* Verify that "rtnobj" is actually in the queue first */
+ elem = (que_ent_ptr_t)(shm_base + que_base->fl);
+ assert(NULL_RTNOBJ_SM_OFF_T == elem->bl);
+ while (elem != rtnque)
+ {
+ assert(NULL_RTNOBJ_SM_OFF_T != elem->fl);
+ elem = (que_ent_ptr_t)((sm_uc_ptr_t)elem + elem->fl);
+ }
+# endif
+ if (NULL_RTNOBJ_SM_OFF_T == rtnque->bl)
+ { /* rtnobj is at head of queue */
+ if (NULL_RTNOBJ_SM_OFF_T == rtnque->fl)
+ { /* rtnobj is only element in queue */
+ que_base->fl = NULL_RTNOBJ_SM_OFF_T;
+ que_base->bl = NULL_RTNOBJ_SM_OFF_T;
+ } else
+ {
+ elem = (que_ent_ptr_t)((uchar_ptr_t)rtnque + rtnque->fl);
+ assert(0 == (sm_off_t)elem % 8);
+ elem->bl = NULL_RTNOBJ_SM_OFF_T;
+ assert(0 == que_base->fl % 8);
+ assert(0 == rtnque->fl % 8);
+ que_base->fl += rtnque->fl;
+ }
+ } else if (NULL_RTNOBJ_SM_OFF_T == rtnque->fl)
+ { /* rtnobj is at tail of queue with at least one more element in queue */
+ elem = (que_ent_ptr_t)((uchar_ptr_t)rtnque + rtnque->bl);
+ elem->fl = NULL_RTNOBJ_SM_OFF_T;
+ assert(0 == que_base->bl % 8);
+ assert(0 == rtnque->bl % 8);
+ que_base->bl += rtnque->bl;
+ } else
+ { /* rtnobj is in middle of queue with at least one element in queue on either side */
+ elem = (que_ent_ptr_t)((uchar_ptr_t)rtnque + rtnque->bl);
+ assert(0 == (sm_off_t)elem % 8);
+ assert(0 == elem->fl % 8);
+ assert(0 == rtnque->fl % 8);
+ elem->fl += rtnque->fl;
+ assert(0 == (sm_off_t)rtnque % 8);
+ assert(0 == rtnque->fl % 8);
+ elem = (que_ent_ptr_t)((uchar_ptr_t)rtnque + rtnque->fl);
+ assert(0 == elem->bl % 8);
+ assert(0 == rtnque->bl % 8);
+ elem->bl += rtnque->bl;
+ }
+}
+
+sm_uc_ptr_t rtnobj_shm_malloc(zro_hist *zhist, int fd, off_t objSize, gtm_uint64_t objhash)
+{
+ boolean_t has_relinkctl_lock, has_rtnobj_lock;
+ boolean_t initialized, return_NULL;
+ char errstr[256];
+ gtm_uint64_t src_cksum_8byte;
+ int min_index, max_index, min_free_index, max_free_index, shm_index;
+ int objIndex, tSize, sizeIndex, shmSizeIndex, shmid, actualSize;
+ int codelen, loopcnt, save_errno;
+ open_relinkctl_sgm *linkctl;
+ que_ent_ptr_t freeList;
+ relinkrec_t *relinkrec;
+ relinkshm_hdr_t *shm_hdr;
+ sm_uc_ptr_t shm_base;
+ rtnobj_hdr_t *rtnobj, *prev_rtnobj, *rtnobj2;
+ rtnobj_sm_off_t shm_index_off;
+ rtnobjshm_hdr_t *rtnobj_shm_hdr;
+ size_t shm_size;
+ off_t rtnobjSize;
+ sm_off_t shm_off;
+ sm_uc_ptr_t objBuff, codeadr;
+ rhdtyp tmprhd, *rhdr;
+ gtm_uint64_t elemSize;
+ zro_validation_entry *zhent;
+ char zro_entry_str[ZRO_DIR_PATH_MAX + 1];
+ struct stat dir_stat_buf;
+ int stat_res;
+ int user_id;
+ int group_id;
+ int perm;
+ int maxvers, curvers;
+ struct perm_diag_data pdd;
+ struct shmid_ds shmstat;
+# ifdef DEBUG
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+# endif
+ zhent = zhist->end - 1;
+ relinkrec = zhent->relinkrec;
+ linkctl = zhent->relinkctl_bkptr;
+ /* Assert certain design assumptions */
+ assert((MAX_RTNOBJ_SHM_INDEX + RTNOBJ_SHMID_INDEX_MAXBITS) <= (8 * SIZEOF(rtnobj_sm_off_t)));
+ assert(((size_t)1 << RTNOBJ_SHMID_INDEX_MAXBITS) >= MAX_RTNOBJ_SHM_INDEX);
+ /* Check if we are in sync with shared memory. If not attach to requisite shmids first.
+ * Note that the below logic tries to do search outside of any locks (for performance reasons)
+ * but that means we need to be extra careful in validating things read outside of a lock.
+ */
+ shm_hdr = GET_RELINK_SHM_HDR(linkctl);
+ loopcnt = 0;
+ has_relinkctl_lock = FALSE;
+ assert(!linkctl->locked);
+ assert(!linkctl->hdr->file_deleted);
+ if (!grab_latch(&relinkrec->rtnobj_latch, RLNKREC_LATCH_TIMEOUT_SEC))
+ {
+ assert(FALSE);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5)
+ ERR_RLNKRECLATCH, 3, relinkrec->rtnname_fixed.c, RTS_ERROR_MSTR(&linkctl->zro_entry_name));
+ }
+ memcpy(zro_entry_str, linkctl->zro_entry_name.addr, linkctl->zro_entry_name.len);
+ zro_entry_str[linkctl->zro_entry_name.len] = '\0';
+ do
+ {
+ if (CDB_STAGNATE <= loopcnt++)
+ { /* We have tried THRICE to search without a lock but found something inconsistent (due to concurrent
+ * changes to shared memory structures). Get a lock on the entire relinkctl file before searching
+ * for one last time.
+ */
+ assert(!has_relinkctl_lock);
+ if (!grab_latch(&shm_hdr->relinkctl_latch, RLNKSHM_LATCH_TIMEOUT_SEC))
+ {
+ assert(FALSE);
+ rel_latch(&relinkrec->rtnobj_latch);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4)
+ ERR_RLNKSHMLATCH, 2, RTS_ERROR_MSTR(&linkctl->zro_entry_name));
+ }
+ has_relinkctl_lock = TRUE;
+ }
+ SYNC_RTNOBJ_SHMID_CYCLE_IF_NEEDED(linkctl, min_index, max_index, shm_hdr, has_relinkctl_lock, relinkrec);
+ /* note: the above macro could do a "continue" if "has_relinkctl_lock" is FALSE */
+ /* Now that we have attached to the necessary routine buffer shmids, search within shared memory for the
+ * routine buffer whose <objhash,objLen> matches ours.
+ */
+ assert(MAXUINT4 >= objSize);
+ shm_index_off = relinkrec->rtnobj_shm_offset;
+ prev_rtnobj = NULL;
+ maxvers = relinkrec->numvers;
+ curvers = 0;
+ while ((rtnobj_sm_off_t)NULL_RTNOBJ_SM_OFF_T != shm_index_off)
+ {
+ assertpro(maxvers >= curvers++); /* assertpro to avoid infinite loops in PRO (just in case) */
+ shm_index = RTNOBJ_GET_SHM_INDEX(shm_index_off);
+ shm_off = RTNOBJ_GET_SHM_OFFSET(shm_index_off);
+ assert(0 == (shm_off % 8));
+ /* Since we hold the rtnobj_latch we should see valid values of shm_index/shm_off */
+ assert(min_index <= shm_index);
+ assert(max_index > shm_index);
+ assert(INVALID_SHMID != linkctl->rtnobj_shmid[shm_index]);
+ assert(shm_off < ((off_t)1 << (MIN_RTNOBJ_SHM_INDEX + shm_index)));
+ rtnobj = (rtnobj_hdr_t *)(linkctl->rtnobj_shm_base[shm_index] + shm_off);
+ assert((rtnobj->objhash != objhash) || (rtnobj->objLen == objSize));
+ if ((rtnobj->objLen == objSize) && (rtnobj->objhash == objhash))
+ break;
+ prev_rtnobj = rtnobj;
+ shm_index_off = rtnobj->next_rtnobj_shm_offset;
+ }
+ if ((rtnobj_sm_off_t)NULL_RTNOBJ_SM_OFF_T != shm_index_off)
+ { /* If found return */
+ assert(rtnobj->initialized);
+ /* If gtm_autorelink_keeprtn is FALSE (i.e. we maintain reference counts even on process exit),
+ * we do not expect refcnt to go to high values as it is the # of processes concurrently running
+ * and actively using this buffer and that cannot be close to 2**31 which is the max value for refcnt.
+ */
+ assert(TREF(gtm_autorelink_keeprtn) || (REFCNT_INACCURATE != rtnobj->refcnt));
+ if (REFCNT_INACCURATE != rtnobj->refcnt)
+ rtnobj->refcnt++; /* increment refcnt while holding the rtnobj_lock */
+ if (has_relinkctl_lock)
+ rel_latch(&shm_hdr->relinkctl_latch);
+ RTNOBJ_DBG(fprintf(stderr, "rtnobj_shm_malloc : rtnname = %s : objhash = 0x%llx : " \
+ "linkctl = 0x%llx : Found : refcnt = %d : elem = 0x%llx\n", \
+ relinkrec->rtnname_fixed.c, (long long unsigned int)objhash, \
+ (long long unsigned int)linkctl, rtnobj->refcnt, \
+ (long long unsigned int)&rtnobj->userStorage.userStart);)
+ zhent->cycle = relinkrec->cycle; /* Update private cycle to be in sync with shared copy */
+ rel_latch(&relinkrec->rtnobj_latch);
+ objBuff = (sm_uc_ptr_t)&rtnobj->userStorage.userStart;
+ return objBuff; /* object code starts after rtnobj_hdr_t */
+ }
+ assert(MAXUINT4 >= (objSize + OFFSETOF(rtnobj_hdr_t, userStorage)));
+ assert(4 <= SIZEOF(tSize)); /* above assert guarantees 4-bytes is enough for storage */
+ tSize = objSize + OFFSETOF(rtnobj_hdr_t, userStorage);
+ sizeIndex = ceil_log2_32bit(tSize);
+ assert(MAX_RTNOBJ_SIZE_BITS >= sizeIndex);
+ sizeIndex = MAX(sizeIndex, MIN_RTNOBJ_SIZE_BITS); /* Round up to minimum supported obj file size */
+ /* Find the smallest shm index that can possibly contain space for sizeIndex */
+ shm_index = (MIN_RTNOBJ_SHM_INDEX > sizeIndex) ? 0 : sizeIndex - MIN_RTNOBJ_SHM_INDEX;
+ sizeIndex -= MIN_RTNOBJ_SIZE_BITS;
+ shm_index = MAX(shm_index, shm_hdr->min_shm_index);
+ /* If not found, allocate space in shared memory for one and return. Now that we are going to
+ * play with the buddy list structures in shared memory, get an overarching lock on all rtnobj shmids
+ * i.e. a lock on the entire relinkctl file
+ */
+ if (!has_relinkctl_lock)
+ {
+ if (!grab_latch(&shm_hdr->relinkctl_latch, RLNKSHM_LATCH_TIMEOUT_SEC))
+ {
+ assert(FALSE);
+ rel_latch(&relinkrec->rtnobj_latch);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4)
+ ERR_RLNKSHMLATCH, 2, RTS_ERROR_MSTR(&linkctl->zro_entry_name));
+ }
+ has_relinkctl_lock = TRUE;
+ }
+ /* Sync up with rtnobj shmids one final time if needed now that we have the relinkctl file lock */
+ SYNC_RTNOBJ_SHMID_CYCLE_IF_NEEDED(linkctl, min_index, max_index, shm_hdr, has_relinkctl_lock, relinkrec);
+ /* note: the above macro is guaranteed not to do a "continue" since "has_relinkctl_lock" is TRUE */
+ /* Find a shared memory buffer to hold the routine object */
+ rtnobj = NULL;
+ for ( ; shm_index < max_index; shm_index++)
+ {
+ rtnobj_shm_hdr = &shm_hdr->rtnobj_shmhdr[shm_index];
+ if (INVALID_SHMID == rtnobj_shm_hdr->rtnobj_shmid)
+ continue;
+ min_free_index = rtnobj_shm_hdr->rtnobj_min_free_index;
+ max_free_index = rtnobj_shm_hdr->rtnobj_max_free_index;
+ shm_base = linkctl->rtnobj_shm_base[shm_index];
+ objIndex = MAX(sizeIndex, min_free_index);
+ freeList = &rtnobj_shm_hdr->freeList[objIndex];
+ for ( ; objIndex < max_free_index; objIndex++, freeList++)
+ {
+ assert(objIndex < NUM_RTNOBJ_SIZE_BITS);
+ if (NULL_RTNOBJ_SM_OFF_T == freeList->fl)
+ {
+ assert(NULL_RTNOBJ_SM_OFF_T == freeList->bl);
+ continue;
+ }
+ rtnobj = remqh_rtnobj(freeList, shm_base);
+ if (NULL_RTNOBJ_SM_OFF_T == freeList->fl)
+ {
+ assert(NULL_RTNOBJ_SM_OFF_T == freeList->bl);
+ /* This was the only element in the freeList.
+ * Set min_free_index/max_free_index to impossible values
+ * if the new minimums/maximums need to be recomputed.
+ */
+ if (objIndex == min_free_index)
+ min_free_index = NUM_RTNOBJ_SIZE_BITS;
+ if (max_free_index == (objIndex + 1))
+ max_free_index = 0;
+ } else if (min_free_index > sizeIndex)
+ {
+ assert(NUM_RTNOBJ_SIZE_BITS > min_free_index);
+ min_free_index = NUM_RTNOBJ_SIZE_BITS;
+ }
+ break;
+ }
+ if (NULL != rtnobj)
+ break;
+ }
+ if (NULL == rtnobj)
+ { /* Need to allocate rtnobj buffer in a new shared memory segment */
+ assert(shm_index >= max_index);
+ shm_size = ((size_t)1 << (shm_index + MIN_RTNOBJ_SHM_INDEX));
+ ADJUST_SHM_SIZE_FOR_HUGEPAGES(shm_size, shm_size); /* second parameter "shm_size" is adjusted size */
+ /* If minimum huge page size is much higher than requested shm size, adjust "shm_index"
+ * accordingly so we use the allocated (bigger-than-requested) shm completely.
+ */
+ shmSizeIndex = ceil_log2_64bit(shm_size);
+ assert(((size_t)1 << shmSizeIndex) == shm_size);
+ assert(shmSizeIndex >= (shm_index + MIN_RTNOBJ_SHM_INDEX));
+ shm_index = shmSizeIndex - MIN_RTNOBJ_SHM_INDEX;
+ shmid = shmget(IPC_PRIVATE, shm_size, RWDALL | IPC_CREAT);
+ if (-1 == shmid)
+ {
+ save_errno = errno;
+ rel_latch(&shm_hdr->relinkctl_latch);
+ rel_latch(&relinkrec->rtnobj_latch);
+ SNPRINTF(errstr, SIZEOF(errstr), "rtnobj shmget() failed for shmsize=0x%llx", shm_size);
+ ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, save_errno);
+ }
+ STAT_FILE(zro_entry_str, &dir_stat_buf, stat_res);
+ if (-1 == stat_res)
+ {
+ save_errno = errno;
+ rel_latch(&shm_hdr->relinkctl_latch);
+ rel_latch(&relinkrec->rtnobj_latch);
+ shm_rmid(shmid); /* if error removing shmid we created, just move on */
+ SNPRINTF(errstr, SIZEOF(errstr), "rtnobj stat() of file %s failed", zro_entry_str);
+ ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, save_errno);
+ }
+ if (gtm_permissions(&dir_stat_buf, &user_id, &group_id, &perm, PERM_IPC|PERM_EXEC, &pdd) < 0)
+ {
+ save_errno = errno;
+ rel_latch(&shm_hdr->relinkctl_latch);
+ rel_latch(&relinkrec->rtnobj_latch);
+ shm_rmid(shmid); /* if error removing shmid we created, just move on */
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(10)
+ ERR_RELINKCTLERR, 2, RTS_ERROR_MSTR(&linkctl->zro_entry_name),
+ ERR_PERMGENFAIL, 4, RTS_ERROR_STRING("rtnobj"),
+ RTS_ERROR_MSTR(&linkctl->zro_entry_name));
+ }
+ if (-1 == shmctl(shmid, IPC_STAT, &shmstat))
+ {
+ save_errno = errno;
+ rel_latch(&shm_hdr->relinkctl_latch);
+ rel_latch(&relinkrec->rtnobj_latch);
+ shm_rmid(shmid); /* if error removing shmid we created, just move on */
+ SNPRINTF(errstr, SIZEOF(errstr), "rtnobj shmctl(IPC_STAT) failed for shmid=%d shmsize=0x%llx",
+ shmid, shm_size);
+ ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, save_errno);
+ }
+ /* change group and permissions */
+ if ((-1 != user_id) && (user_id != shmstat.shm_perm.uid))
+ shmstat.shm_perm.uid = user_id;
+ if ((-1 != group_id) && (group_id != shmstat.shm_perm.gid))
+ shmstat.shm_perm.gid = group_id;
+ shmstat.shm_perm.mode = perm;
+ if (-1 == shmctl(shmid, IPC_SET, &shmstat))
+ {
+ save_errno = errno;
+ rel_latch(&shm_hdr->relinkctl_latch);
+ rel_latch(&relinkrec->rtnobj_latch);
+ shm_rmid(shmid); /* if error removing shmid we created, just move on */
+ SNPRINTF(errstr, SIZEOF(errstr), "rtnobj shmctl(IPC_SET) failed for shmid=%d shmsize=0x%llx",
+ shmid, shm_size);
+ ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, save_errno);
+ }
+ shm_base = (sm_uc_ptr_t)do_shmat_exec_perm(shmid, shm_size, &save_errno);
+ if (-1 == (sm_long_t)shm_base)
+ {
+ save_errno = errno;
+ rel_latch(&shm_hdr->relinkctl_latch);
+ rel_latch(&relinkrec->rtnobj_latch);
+ shm_rmid(shmid); /* if error removing shmid we created, just move on */
+ SNPRINTF(errstr, SIZEOF(errstr), "rtnobj shmat() failed for shmid=%d shmsize=0x%llx",
+ shmid, shm_size);
+ ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, save_errno);
+ }
+ assert(shm_index < NUM_RTNOBJ_SHM_INDEX);
+ rtnobj_shm_hdr = &shm_hdr->rtnobj_shmhdr[shm_index];
+ objIndex = (shm_index + MIN_RTNOBJ_SHM_INDEX - MIN_RTNOBJ_SIZE_BITS);
+ assert(objIndex < NUM_RTNOBJ_SIZE_BITS);
+ freeList = &rtnobj_shm_hdr->freeList[objIndex];
+ rtnobj = (rtnobj_hdr_t *)shm_base;
+ assert(NULL_RTNOBJ_SM_OFF_T == freeList->fl);
+ assert(NULL_RTNOBJ_SM_OFF_T == freeList->bl);
+ assert(sizeIndex <= objIndex);
+ if (sizeIndex < objIndex)
+ { /* rtnobj_shm_hdr->rtnobj_min_free_index and ->rtnobj_min_free_index will be set a little later */
+ min_free_index = NUM_RTNOBJ_SIZE_BITS;
+ max_free_index = 0;
+ } else
+ { /* rtnobj_shm_hdr->rtnobj_min_free_index and ->rtnobj_min_free_index are already set correctly.
+ * set min_free_index/max_free_index such that the above two dont get set again (a little later).
+ */
+ assert(NUM_RTNOBJ_SIZE_BITS == rtnobj_shm_hdr->rtnobj_min_free_index);
+ assert(0 == rtnobj_shm_hdr->rtnobj_max_free_index);
+ assert(NUM_RTNOBJ_SIZE_BITS != objIndex);
+ min_free_index = objIndex;
+ assert(0 != NUM_RTNOBJ_SIZE_BITS);
+ max_free_index = NUM_RTNOBJ_SIZE_BITS;
+ }
+ rtnobj_shm_hdr->rtnobj_shmid = shmid;
+ assert(0 == rtnobj_shm_hdr->real_len);
+ rtnobj_shm_hdr->shm_len = shm_size;
+ if (shm_hdr->rtnobj_min_shm_index > shm_index)
+ {
+ assert(0 == shm_hdr->rtnobj_shmid_cycle); /* our shm expansion logic must not reach this codepath */
+ shm_hdr->rtnobj_min_shm_index = shm_index;
+ }
+ if (shm_hdr->rtnobj_max_shm_index < (shm_index + 1))
+ shm_hdr->rtnobj_max_shm_index = (shm_index + 1);
+ /* Sync shared memory with private contents for this process to avoid duplicate shmget/shmat */
+ assert(linkctl->rtnobj_shmid_cycle == shm_hdr->rtnobj_shmid_cycle); /* due to SYNC_* done above */
+ shm_hdr->rtnobj_shmid_cycle++;
+ linkctl->rtnobj_shmid_cycle = shm_hdr->rtnobj_shmid_cycle;
+ linkctl->rtnobj_min_shm_index = shm_hdr->rtnobj_min_shm_index;
+ linkctl->rtnobj_max_shm_index = shm_hdr->rtnobj_max_shm_index;
+ linkctl->rtnobj_shm_base[shm_index] = shm_base;
+ linkctl->rtnobj_shmid[shm_index] = shmid;
+ }
+ /* At this point, we have a non-null rtnobj but it could be bigger than we want.
+ * Split it into half until we reach the desired size. Insert into free queues along the way.
+ */
+ assert(objIndex >= sizeIndex);
+ if (objIndex > sizeIndex)
+ {
+ if (0 == max_free_index)
+ {
+ rtnobj_shm_hdr->rtnobj_max_free_index = objIndex;
+ max_free_index = objIndex;
+ }
+ rtnobjSize = ((off_t)1 << (objIndex + MIN_RTNOBJ_SIZE_BITS));
+ freeList = &rtnobj_shm_hdr->freeList[objIndex];
+ do
+ {
+ rtnobjSize /= 2;
+ objIndex--;
+ freeList--;
+ rtnobj2 = (rtnobj_hdr_t *)((sm_uc_ptr_t)rtnobj + rtnobjSize);
+ rtnobj2->state = STATE_FREE;
+ rtnobj2->queueIndex = objIndex;
+ DEBUG_ONLY(shm_off = (sm_uc_ptr_t)rtnobj2 - shm_base);
+ assert(0 == (shm_off % ((sm_off_t)1 << (objIndex + MIN_RTNOBJ_SIZE_BITS))));
+ /* rtnobj2->initialized needs initialization only when state becomes STATE_ALLOCATED */
+ /* rtnobj2->refcnt needs initialization only when state becomes STATE_ALLOCATED */
+ /* rtnobj2->src_cksum_8byte needs initialization only when state becomes STATE_ALLOCATED */
+ /* rtnobj2->next_rtnobj_shm_offset needs initialization only when state becomes STATE_ALLOCATED */
+ /* rtnobj2->relinkctl_index needs initialization only when state becomes STATE_ALLOCATED */
+ /* rtnobj2->objLen needs initialization only when state becomes STATE_ALLOCATED */
+ insqt_rtnobj(&rtnobj2->userStorage.freePtr, freeList, shm_base);
+ } while (objIndex > sizeIndex);
+ if (NUM_RTNOBJ_SIZE_BITS == min_free_index)
+ rtnobj_shm_hdr->rtnobj_min_free_index = sizeIndex;
+ } else
+ {
+ if (NUM_RTNOBJ_SIZE_BITS == min_free_index)
+ {
+ assert(objIndex == rtnobj_shm_hdr->rtnobj_min_free_index);
+ if (0 == max_free_index)
+ { /* Need to recompute BOTH rtnobj_shm_hdr->rtnobj_min_free_index
+ * AND rtnobj_shm_hdr->rtnobj_max_free_index. But the fact that
+ * min and max are the same implies there are NO more free buffers
+ * in this entire shared memory so the recomputation is easy.
+ */
+ assert((objIndex + 1) == rtnobj_shm_hdr->rtnobj_max_free_index);
+ rtnobj_shm_hdr->rtnobj_max_free_index = 0;
+ rtnobj_shm_hdr->rtnobj_min_free_index = NUM_RTNOBJ_SIZE_BITS;
+ } else
+ { /* Need to ONLY recompute rtnobj_shm_hdr->rtnobj_min_free_index */
+ max_free_index = rtnobj_shm_hdr->rtnobj_max_free_index;
+ freeList = &rtnobj_shm_hdr->freeList[objIndex];
+ for ( ; objIndex < max_free_index; objIndex++, freeList++)
+ {
+ assert(objIndex < NUM_RTNOBJ_SIZE_BITS);
+ if (NULL_RTNOBJ_SM_OFF_T != freeList->fl)
+ {
+ rtnobj_shm_hdr->rtnobj_min_free_index = objIndex;
+ break;
+ }
+ }
+ assert(objIndex < max_free_index);
+ }
+ } else if (0 == max_free_index)
+ { /* Need to ONLY recompute rtnobj_shm_hdr->rtnobj_min_free_index */
+ assert((objIndex + 1) == rtnobj_shm_hdr->rtnobj_max_free_index);
+ min_free_index = rtnobj_shm_hdr->rtnobj_min_free_index;
+ freeList = &rtnobj_shm_hdr->freeList[objIndex];
+ for ( ; objIndex >= min_free_index; objIndex--, freeList--)
+ {
+ assert(objIndex < NUM_RTNOBJ_SIZE_BITS);
+ if (NULL_RTNOBJ_SM_OFF_T != freeList->fl)
+ {
+ rtnobj_shm_hdr->rtnobj_max_free_index = objIndex + 1;
+ break;
+ }
+ }
+ assert(objIndex >= min_free_index);
+ }
+ }
+ rtnobj->state = STATE_ALLOCATED;
+ rtnobj->queueIndex = sizeIndex;
+ rtnobj_shm_hdr->real_len += objSize;
+ elemSize = ((gtm_uint64_t)1 << (sizeIndex + MIN_RTNOBJ_SIZE_BITS));
+ rtnobj_shm_hdr->used_len += elemSize;
+ DEBUG_ONLY(rtnobj_verify_min_max_free_index(rtnobj_shm_hdr));
+ DEBUG_ONLY(rtnobj_verify_freelist_fl_bl(rtnobj_shm_hdr, shm_base);)
+ /* Now that we have gotten a "rtnobj" pointer, we can release the relinkctl latch on shared memory.
+ * We still need to hold on to the lower-granular relinkrec->rtnobj_latch to read the object file
+ * into shared memory.
+ */
+ rel_latch(&shm_hdr->relinkctl_latch);
+ assert(((off_t)1 << (sizeIndex + MIN_RTNOBJ_SIZE_BITS)) >= (objSize + OFFSETOF(rtnobj_hdr_t, userStorage)));
+ assert(((off_t)1 << (sizeIndex + MIN_RTNOBJ_SIZE_BITS - 1)) < (objSize + OFFSETOF(rtnobj_hdr_t, userStorage)));
+ shm_off = (sm_uc_ptr_t)rtnobj - shm_base;
+ assert(0 == (shm_off % ((sm_off_t)1 << (sizeIndex + MIN_RTNOBJ_SIZE_BITS))));
+ rtnobj->initialized = TRUE;
+ rtnobj->refcnt = 1;
+ assert(0 <= shm_off);
+ assert(shm_off < rtnobj_shm_hdr->shm_len);
+ shm_index_off = RTNOBJ_SET_SHM_INDEX_OFF(shm_index, shm_off);
+ if (NULL != prev_rtnobj)
+ prev_rtnobj->next_rtnobj_shm_offset = shm_index_off;
+ else
+ relinkrec->rtnobj_shm_offset = shm_index_off;
+ rtnobj->next_rtnobj_shm_offset = (rtnobj_sm_off_t)NULL_RTNOBJ_SM_OFF_T;
+ rtnobj->relinkctl_index = relinkrec - linkctl->rec_base;
+ rtnobj->objLen = objSize;
+ rtnobj->objhash = objhash;
+ relinkrec->objLen += objSize;
+ relinkrec->usedLen += elemSize;
+ relinkrec->numvers++;
+ /* Fill the shared memory buffer with the object code */
+ objBuff = (sm_uc_ptr_t)&rtnobj->userStorage.userStart;
+ if (-1 == lseek(fd, NATIVE_HDR_LEN, SEEK_SET))
+ return_NULL = TRUE;
+ else
+ {
+ DOREADRL(fd, objBuff, objSize, actualSize);
+ return_NULL = (actualSize != objSize);
+ }
+ if (return_NULL)
+ {
+ /* Free allocated object in shared memory using rtnobj_shm_free. Set up a dummy rtnhdr
+ * with just the necessary fields initialized since rtnobj_shm_free requires it.
+ */
+ rhdr = &tmprhd;
+ rhdr->shared_ptext_adr = objBuff + SIZEOF(rhdtyp);
+ rhdr->zhist = zhist;
+ DEBUG_ONLY(rhdr->shared_object = TRUE); /* for an assert inside rtnobj_shm_free */
+ DEBUG_ONLY(rhdr->relinkctl_bkptr = linkctl); /* for an assert inside rtnobj_shm_free */
+ /* We already hold the relinkrec->rtnobj_latch. Free up the shared object before releasing this
+ * lock to avoid other processes from seeing the allocated shared object and assuming it is
+ * properly initialized when actually it is not. rtnobj_shm_free obtains the relinkrec->rtnobj_latch
+ * which would fail an assert since we already hold that latch so add a dbg-flag to avoid an assert.
+ */
+ rtnobj_shm_free(rhdr, LATCH_GRABBED_TRUE); /* Note: this will release relinkrec->rtnobj_latch for us */
+ return NULL; /* caller will issue error */
+ }
+ rhdr = (rhdtyp *)objBuff;
+ codelen = rhdr->ptext_end_adr - rhdr->ptext_adr; /* Length of object code */
+ assert(0 < codelen);
+ codeadr = objBuff + (UINTPTR_T)rhdr->ptext_adr; /* Pointer to object code */
+ cacheflush(codeadr, codelen, BCACHE); /* Cacheflush executable part from instruction cache */
+ RTNOBJ_DBG(fprintf(stderr, "rtnobj_shm_malloc : rtnname = %s : objhash = 0x%llx : " \
+ "linkctl = 0x%llx : Inserted : refcnt = %d : elem = 0x%llx : numvers = %d\n", \
+ relinkrec->rtnname_fixed.c, (long long unsigned int)objhash, \
+ (long long unsigned int)linkctl, rtnobj->refcnt, \
+ (long long unsigned int)objBuff, relinkrec->numvers);)
+ relinkrec->objhash = objhash;
+ ++relinkrec->cycle; /* cycle bump is because of the implicit ZRUPDATE that linking a routine does */
+ if (0 == relinkrec->cycle)
+ relinkrec->cycle = 1; /* cycle value of 0 has special meaning, so bump to 1 in case we roll over */
+ zhent->cycle = relinkrec->cycle; /* Update private cycle to be in sync with shared copy */
+ rel_latch(&relinkrec->rtnobj_latch);
+ return objBuff;
+ } while (TRUE);
+}
+
+void rtnobj_shm_free(rhdtyp *rhead, boolean_t latch_grabbed)
+{
+ relinkrec_t *relinkrec;
+ open_relinkctl_sgm *linkctl;
+ relinkshm_hdr_t *shm_hdr;
+ int maxObjIndex, sizeIndex;
+ int min_index, max_index, min_free_index, max_free_index, shm_index;
+ gtm_uint64_t elemSize, origElemSize, objLen;
+ rtnobj_hdr_t *rtnobj, *prev_rtnobj, *rtnobj2;
+ rtnobj_sm_off_t shm_index_off;
+ rtnobjshm_hdr_t *rtnobj_shm_hdr;
+ sm_uc_ptr_t shm_base;
+ sm_off_t shm_off, rtnobj_off;
+ que_ent_ptr_t freeList;
+ zro_validation_entry *zhent;
+ sm_uc_ptr_t objBuff;
+ int maxvers, curvers;
+ DEBUG_ONLY(size_t shm_size;)
+ DEBUG_ONLY(int dbg_shm_index;)
+# ifdef DEBUG
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+# endif
+ assert(rhead->shared_object);
+ assert(NULL != rhead->shared_ptext_adr);
+ if (NULL == rhead->shared_ptext_adr)
+ return; /* in pro, be safe */
+ /* Note that if breakpoints are in effect, rhead->shared_ptext_adr will not be equal to rhead->ptext_adr.
+ * This is because we would have taken a private copy of the code (for breakpoints) into ptext_adr and kept
+ * shared_ptext_adr untouched. We will still need to free-up/decrement-refcnt the shared copy (shared_ptext_adr).
+ */
+ objBuff = rhead->shared_ptext_adr - SIZEOF(rhdtyp);
+ rtnobj = (rtnobj_hdr_t *)(objBuff - OFFSETOF(rtnobj_hdr_t, userStorage));
+ assert(STATE_ALLOCATED == rtnobj->state);
+ assert(rtnobj->initialized);
+ assert(0 < rtnobj->refcnt);
+ assert(NULL != rhead->zhist);
+ zhent = rhead->zhist->end - 1;
+ relinkrec = zhent->relinkrec;
+ linkctl = zhent->relinkctl_bkptr;
+ assert(rhead->relinkctl_bkptr == linkctl);
+ shm_hdr = GET_RELINK_SHM_HDR(linkctl);
+ assert(!linkctl->locked);
+ assert(!linkctl->hdr->file_deleted);
+ sizeIndex = rtnobj->queueIndex;
+# ifdef DEBUG
+ /* Find shm_index corresponding to this routine buffer to cross check later */
+ min_index = linkctl->rtnobj_min_shm_index;
+ max_index = linkctl->rtnobj_max_shm_index;
+ for (dbg_shm_index = min_index; dbg_shm_index < max_index; dbg_shm_index++)
+ {
+ rtnobj_shm_hdr = &shm_hdr->rtnobj_shmhdr[dbg_shm_index];
+ if (INVALID_SHMID == rtnobj_shm_hdr->rtnobj_shmid)
+ continue;
+ shm_base = linkctl->rtnobj_shm_base[dbg_shm_index];
+ assert(NULL != shm_base);
+ shm_size = ((size_t)1 << (dbg_shm_index + MIN_RTNOBJ_SHM_INDEX));
+ if (((gtm_uint64_t)shm_base <= (gtm_uint64_t)rtnobj)
+ && (((gtm_uint64_t)shm_base + shm_size) > (gtm_uint64_t)rtnobj))
+ break; /* shared memory corresponding to rtnobj is found */
+ }
+ assert(dbg_shm_index < max_index);
+# endif
+ if (!latch_grabbed && !grab_latch(&relinkrec->rtnobj_latch, RLNKREC_LATCH_TIMEOUT_SEC))
+ {
+ assert(FALSE);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5)
+ ERR_RLNKRECLATCH, 3, relinkrec->rtnname_fixed.c, RTS_ERROR_MSTR(&linkctl->zro_entry_name));
+ }
+ assert(0 < rtnobj->refcnt);
+ assert(TREF(gtm_autorelink_keeprtn) || (REFCNT_INACCURATE != rtnobj->refcnt));
+ if (REFCNT_INACCURATE != rtnobj->refcnt)
+ rtnobj->refcnt--; /* decrement refcnt while holding the rtnobj_lock */
+ if (rtnobj->refcnt)
+ { /* The loaded object cannot be freed until refcnt becomes 0. But caller's job done. Return. */
+ RTNOBJ_DBG(fprintf(stderr, \
+ "rtnobj_shm_free : rtnname = %s : objhash = 0x%llx : Decremented : refcnt = %d : elem = 0x%llx\n", \
+ relinkrec->rtnname_fixed.c, (long long unsigned int)rtnobj->objhash, rtnobj->refcnt, \
+ (long long unsigned int)objBuff);)
+ rel_latch(&relinkrec->rtnobj_latch);
+ return;
+ }
+ assert(sizeIndex == rtnobj->queueIndex); /* since this pid has not freed it yet, queueIndex must not change concurrently */
+ /* Note: Although we hold the rtnobj_latch, it is possible that new rtnobj_shmids get created concurrently
+ * and an addition happens to the rtnobj->next_rtnobj_shm_offset linked list pointing to the new shmids.
+ * But since additions to the linked list happen only at the end, we are guaranteed that the element of
+ * interest (rtnobj which we want to free and have already located in rtnobj_shm_malloc) would be found
+ * without reaching the tail portion of that linked list (which would require attaching to the new shmid).
+ * So no concurrency issues to worry about like we had to in rtnobj_shm_malloc (see use of
+ * SYNC_RTNOBJ_SHMID_CYCLE_IF_NEEDED macro and how it could do a "continue").
+ */
+ shm_index_off = relinkrec->rtnobj_shm_offset;
+ prev_rtnobj = NULL;
+ maxvers = relinkrec->numvers;
+ curvers = 0;
+ while ((rtnobj_sm_off_t)NULL_RTNOBJ_SM_OFF_T != shm_index_off)
+ {
+ assertpro(maxvers >= curvers++); /* assertpro to avoid infinite loops in PRO (just in case) */
+ shm_index = RTNOBJ_GET_SHM_INDEX(shm_index_off);
+ shm_off = RTNOBJ_GET_SHM_OFFSET(shm_index_off);
+ assert(0 == (shm_off % 8));
+ /* Since we hold the rtnobj_latch we should see valid values of shm_index/shm_off */
+ assert(min_index <= shm_index);
+ assert(max_index > shm_index);
+ assert(INVALID_SHMID != linkctl->rtnobj_shmid[shm_index]);
+ assert(shm_off < ((off_t)1 << (MIN_RTNOBJ_SHM_INDEX + shm_index)));
+ rtnobj2 = (rtnobj_hdr_t *)(linkctl->rtnobj_shm_base[shm_index] + shm_off);
+ if (rtnobj2 == rtnobj)
+ break;
+ prev_rtnobj = rtnobj2;
+ shm_index_off = rtnobj2->next_rtnobj_shm_offset;
+ }
+ assertpro((rtnobj_sm_off_t)NULL_RTNOBJ_SM_OFF_T != shm_index_off);
+ shm_index_off = rtnobj->next_rtnobj_shm_offset;
+ assert(dbg_shm_index == shm_index);
+ rtnobj_shm_hdr = &shm_hdr->rtnobj_shmhdr[shm_index];
+ shm_base = linkctl->rtnobj_shm_base[shm_index];
+ maxObjIndex = (shm_index + MIN_RTNOBJ_SHM_INDEX - MIN_RTNOBJ_SIZE_BITS);
+ assert(sizeIndex <= maxObjIndex);
+ elemSize = origElemSize = ((gtm_uint64_t)1 << (sizeIndex + MIN_RTNOBJ_SIZE_BITS));
+ /* Now that we need to unload the object from shared memory, get a shared memory lock */
+ if (!grab_latch(&shm_hdr->relinkctl_latch, RLNKSHM_LATCH_TIMEOUT_SEC))
+ {
+ assert(FALSE);
+ rel_latch(&relinkrec->rtnobj_latch);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_RLNKSHMLATCH, 2, RTS_ERROR_MSTR(&linkctl->zro_entry_name));
+ }
+ assert(rtnobj->objLen <= rtnobj_shm_hdr->real_len);
+ assert(elemSize <= rtnobj_shm_hdr->used_len);
+ objLen = rtnobj->objLen;
+ rtnobj_shm_hdr->real_len -= objLen;
+ rtnobj_shm_hdr->used_len -= elemSize;
+ /* Check if buddy of "rtnobj" is free and if so free the two together. Merge the two into a bigger chunk
+ * and redo the free-buddy-check/merge as much as possible.
+ */
+ min_free_index = rtnobj_shm_hdr->rtnobj_min_free_index;
+ if (sizeIndex < min_free_index)
+ {
+ min_free_index = sizeIndex;
+ rtnobj_shm_hdr->rtnobj_min_free_index = sizeIndex; /* we are about to do a insqt_rtnobj at freeList[sizeIndex] */
+ }
+ freeList = &rtnobj_shm_hdr->freeList[sizeIndex];
+ rtnobj_off = (sm_uc_ptr_t)rtnobj - shm_base;
+ while (sizeIndex < maxObjIndex)
+ {
+ rtnobj2 = (rtnobj_hdr_t *)(shm_base + (rtnobj_off ^ elemSize)); /* address of buddy */
+ assert(rtnobj2->queueIndex <= sizeIndex);
+ assert((STATE_ALLOCATED == rtnobj2->state) || (STATE_FREE == rtnobj2->state));
+ if (STATE_ALLOCATED == rtnobj2->state)
+ break;
+ if (rtnobj2->queueIndex != sizeIndex)
+ break;
+ remq_rtnobj_specific(freeList, shm_base, rtnobj2);
+ if ((NULL_RTNOBJ_SM_OFF_T == freeList->fl) && (sizeIndex == min_free_index))
+ min_free_index = NUM_RTNOBJ_SIZE_BITS;
+ if (rtnobj2 < rtnobj)
+ {
+ assert(elemSize == ((sm_off_t)rtnobj - (sm_off_t)rtnobj2));
+ rtnobj = rtnobj2; /* Pick lower address buddy for top of new bigger block */
+ assert(rtnobj_off >= (sm_off_t)elemSize);
+ rtnobj_off -= elemSize;
+ }
+ freeList++;
+ sizeIndex++;
+ elemSize *= 2;
+ }
+ rtnobj->state = STATE_FREE;
+ rtnobj->queueIndex = sizeIndex;
+ assert(rtnobj_off == ((sm_uc_ptr_t)rtnobj - shm_base));
+ assert(0 == (rtnobj_off % ((sm_off_t)1 << (sizeIndex + MIN_RTNOBJ_SIZE_BITS))));
+ insqt_rtnobj(&rtnobj->userStorage.freePtr, freeList, shm_base);
+ max_free_index = rtnobj_shm_hdr->rtnobj_max_free_index;
+ if (sizeIndex >= max_free_index)
+ rtnobj_shm_hdr->rtnobj_max_free_index = sizeIndex + 1; /* Recompute max_free_index */
+ if (NUM_RTNOBJ_SIZE_BITS == min_free_index)
+ { /* Recompute min_free_index */
+ max_free_index = sizeIndex + 1;
+ sizeIndex = rtnobj_shm_hdr->rtnobj_min_free_index;
+ freeList = &rtnobj_shm_hdr->freeList[sizeIndex];
+ for ( ; sizeIndex < max_free_index; sizeIndex++, freeList++)
+ {
+ assert(sizeIndex < NUM_RTNOBJ_SIZE_BITS);
+ if (NULL_RTNOBJ_SM_OFF_T != freeList->fl)
+ break;
+ }
+ rtnobj_shm_hdr->rtnobj_min_free_index = sizeIndex;
+ }
+ DEBUG_ONLY(rtnobj_verify_min_max_free_index(rtnobj_shm_hdr));
+ DEBUG_ONLY(rtnobj_verify_freelist_fl_bl(rtnobj_shm_hdr, shm_base);)
+ rel_latch(&shm_hdr->relinkctl_latch);
+ if (NULL != prev_rtnobj)
+ prev_rtnobj->next_rtnobj_shm_offset = shm_index_off;
+ else
+ relinkrec->rtnobj_shm_offset = shm_index_off;
+ assert(objLen <= relinkrec->objLen);
+ relinkrec->objLen -= objLen;
+ assert(origElemSize <= relinkrec->usedLen);
+ relinkrec->usedLen -= origElemSize;
+ assert(0 < relinkrec->numvers);
+ relinkrec->numvers--;
+ RTNOBJ_DBG(fprintf(stderr, \
+ "rtnobj_shm_free : rtnname = %s : objhash = 0x%llx : Freed : refcnt = %d : elem = 0x%llx : numvers = %d\n", \
+ relinkrec->rtnname_fixed.c, (long long unsigned int)rtnobj->objhash, rtnobj->refcnt, \
+ (long long unsigned int)objBuff, relinkrec->numvers);)
+ rel_latch(&relinkrec->rtnobj_latch);
+ return;
+}
+#endif
diff --git a/sr_unix/rtnobj.h b/sr_unix/rtnobj.h
new file mode 100644
index 0000000..71dc1cd
--- /dev/null
+++ b/sr_unix/rtnobj.h
@@ -0,0 +1,34 @@
+/****************************************************************
+ * *
+ * Copyright 2014 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef RTNOBJ_H_INCLUDED
+#define RTNOBJ_H_INCLUDED
+
+#ifdef AUTORELINK_SUPPORTED
+
+#include <rtnhdr.h>
+
+#define LATCH_GRABBED_FALSE FALSE
+#define LATCH_GRABBED_TRUE TRUE
+
+#ifdef DEBUG
+void rtnobj_verify_freelist_fl_bl(rtnobjshm_hdr_t *rtnobj_shm_hdr, sm_uc_ptr_t shm_base);
+void rtnobj_verify_min_max_free_index(rtnobjshm_hdr_t *rtnobj_shm_hdr);
+#endif
+void insqt_rtnobj(que_ent_ptr_t new, que_ent_ptr_t que_base, sm_uc_ptr_t shm_base);
+rtnobj_hdr_t *remqh_rtnobj(que_ent_ptr_t base, sm_uc_ptr_t shm_base);
+void remq_rtnobj_specific(que_ent_ptr_t que_base, sm_uc_ptr_t shm_base, rtnobj_hdr_t *rtnobj);
+sm_uc_ptr_t rtnobj_shm_malloc(zro_hist *zhist, int fd, off_t obj_size, gtm_uint64_t objhash);
+void rtnobj_shm_free(rhdtyp *rhead, boolean_t latch_grabbed);
+
+#endif
+
+#endif /* RTNOBJ_H_INCLUDED */
diff --git a/sr_unix/runall.csh b/sr_unix/runall.csh
index 712e2c1..1772fd8 100644
--- a/sr_unix/runall.csh
+++ b/sr_unix/runall.csh
@@ -260,7 +260,7 @@ else
echo "...... Searching for --------> out-of-date PCT ROUTINEs ...... "
pushd $gtm_pct >& /dev/null
ln -s $gtm_exe/${latest_exe_with_rel_path} __temp_runall_${latest_exe}
- ls -1Lat | sed -n '1,/__temp_runall_'${latest_exe}'/p' | grep -E '\.m$' >>&! ${TMP_DIR}_pct_files
+ ls -1Lat | sed -n '1,/__temp_runall_'${latest_exe}'/p' | grep -E '\.(m|hlp)$' >>&! ${TMP_DIR}_pct_files
rm -f __temp_runall_${latest_exe} >& /dev/null
popd >& /dev/null
else
@@ -571,6 +571,13 @@ else
if (0 != $status) @ runall_status = $status
endif
+# Create the GT.M/GDE/MUPIP/DSE/LKE help databases
+$gtm_tools/generate_help.csh $gtm_pct $gtm_log/error.${RUNALL_IMAGE}.log
+if ($status) then
+ @ runall_status++
+ echo "runall-E-hlp, Error generating hlp databases"
+endif
+
echo ""
if ( -f $gtm_log/error.${RUNALL_IMAGE}.log ) then
echo "Error summary:"
diff --git a/sr_unix/secshr_client.c b/sr_unix/secshr_client.c
index 516f1e0..fddf7fd 100644
--- a/sr_unix/secshr_client.c
+++ b/sr_unix/secshr_client.c
@@ -19,6 +19,7 @@
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/param.h>
+
#include "gtm_ctype.h"
#include "gtm_stdlib.h" /* for exit() */
#include "gtm_string.h"
@@ -27,10 +28,11 @@
#include "gtm_unistd.h"
#include "gtm_stdio.h"
#include "gtm_stat.h"
-#include "gt_timer.h"
#include "gtm_limits.h"
#include "gtm_syslog.h"
+#include "gtm_ipc.h"
+#include "gt_timer.h"
#include "gtmio.h"
#include "io.h"
#include "gtmsecshr.h"
@@ -52,9 +54,9 @@
#include "filestruct.h"
#include "gtm_logicals.h"
#include "secshr_client.h"
-#include "gtm_semutils.h"
#include "hashtab.h" /* for STR_HASH macro */
#include "fork_init.h"
+#include "wbox_test_init.h"
GBLREF struct sockaddr_un gtmsecshr_sock_name;
GBLREF key_t gtmsecshr_key;
@@ -92,7 +94,7 @@ const static char readonly *secshrstart_error_code[] = {
"",
"gtmsecshr unable to set-uid to root",
"The environmental variable gtm_dist is pointing to an invalid path",
- "Unable to exec gtmsecshr",
+ "Unable to start gtmsecshr executable",
"gtmsecshr unable to create a child process",
"Error with gtmsecshr semaphore",
"gtmsecshr already running - invalid invocation",
@@ -210,8 +212,9 @@ int send_mesg2gtmsecshr(unsigned int code, unsigned int id, char *path, int path
if (-1 == Stat(gtmsecshr_pathname.addr, &stat_buf))
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5,
LEN_AND_LIT("stat"), CALLFROM, errno);
- if ((ROOTUID != stat_buf.st_uid) ||
- !(stat_buf.st_mode & S_ISUID))
+ if ((ROOTUID != stat_buf.st_uid)
+ || !(stat_buf.st_mode & S_ISUID)
+ || (0 != ACCESS(gtmsecshr_pathname.addr, (X_OK))))
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_GTMSECSHRPERM);
gtmsecshr_file_check_done = TRUE;
}
@@ -442,12 +445,14 @@ int create_server(void)
{
process_id = getpid();
/* Do exec using gtmsecshr_path, which was initialize in file check code - send_mesg2gtmsecshr */
+ if (WBTEST_ENABLED(WBTEST_BADEXEC_SECSHR_PROCESS))
+ STRCPY(gtmsecshr_path, "");
status = EXECL(gtmsecshr_path, gtmsecshr_path, 0);
if (-1 == status)
{
- send_msg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_GTMSECSHRSTART, 3, RTS_ERROR_TEXT("Client"), process_id,
- ERR_TEXT, 2, RTS_ERROR_STRING(secshrstart_error_code[INVTRANSGTMSECSHR]));
- exit(UNABLETOEXECGTMSECSHR);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_GTMSECSHRSTART, 3, RTS_ERROR_TEXT("Client"), process_id,
+ ERR_TEXT, 2, RTS_ERROR_STRING(secshrstart_error_code[UNABLETOEXECGTMSECSHR]));
+ _exit(UNABLETOEXECGTMSECSHR);
}
} else
{
diff --git a/sr_unix/sleep.c b/sr_unix/sleep.c
index 5372e72..5ca33da 100644
--- a/sr_unix/sleep.c
+++ b/sr_unix/sleep.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2002 Sanchez Computer Associates, Inc. *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -10,61 +10,17 @@
****************************************************************/
#include "mdef.h"
-#include <time.h>
+#include "gtm_time.h"
+#include <sys/time.h>
+#include <errno.h>
#include "sleep.h"
-#ifndef __MVS__
-
-int m_sleep(int seconds)
-{
- m_time_t rqtp, rmtp;
-
- rqtp.tv_sec=seconds;
- rqtp.tv_nsec=0;
-
- return nanosleep_func(&rqtp,&rmtp);
-}
-
-int m_usleep(int useconds)
-{
- m_time_t rqtp, rmtp;
-
- rqtp.tv_sec=0;
- rqtp.tv_nsec=useconds*1000;
-
- return nanosleep_func(&rqtp,&rmtp);
-}
-
-int m_nsleep(int nseconds)
-{
- m_time_t rqtp, rmtp;
-
- rqtp.tv_sec=0;
- rqtp.tv_nsec=nseconds;
-
- return nanosleep_func(&rqtp,&rmtp);
-}
-
-#else
-
-/* OS390 versions must use usleep, which doesn't use m_time_t struct */
-
-#include "gtm_unistd.h"
-
-int m_sleep(int seconds)
-{
- return nanosleep_func((useconds_t)(1000 * seconds));
-}
-
-int m_usleep(int useconds)
-{
- return nanosleep_func((useconds_t)useconds);
-}
+#ifdef __MVS__
+/* OS390 versions must use usleep */
+# include "gtm_unistd.h"
+#endif
-/* Note: this functions is not called by anyone */
-int m_nsleep(int nseconds) /* On OS390, this will sleep for one microsecond */
+void m_usleep(int useconds)
{
- return nanosleep_func((useconds_t)1);
+ SLEEP_USEC(useconds, FALSE);
}
-
-#endif
diff --git a/sr_unix/sleep.h b/sr_unix/sleep.h
index e6ec0b3..775db8d 100644
--- a/sr_unix/sleep.h
+++ b/sr_unix/sleep.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -18,11 +18,7 @@
* through the LONG_SLEEP macro defined in mdef.h.
*/
-int m_sleep(int seconds);
-int m_usleep(int useconds);
-int m_nsleep(int nseconds);
-
-#ifdef UNIX
+void m_usleep(int useconds);
# if !defined(_AIX) && !defined(__osf__) && !defined(__hpux) && !defined(__sparc) && !defined(_UWIN) && !defined(__linux__)
# if !defined(__MVS__) && !defined(__CYGWIN__)
@@ -33,156 +29,109 @@ int m_nsleep(int nseconds);
#define E_6 1000000
#define E_9 1000000000
-#define SET_EXPIR_TIME(NOW_TIMEVAL, EXPIR_TIMEVAL, SECS, USECS) \
-{ \
- gettimeofday(&(NOW_TIMEVAL), NULL); \
- if (E_6 <= ((NOW_TIMEVAL).tv_usec + USECS)) \
- { \
- (EXPIR_TIMEVAL).tv_sec = (NOW_TIMEVAL).tv_sec + (SECS) + 1; \
- (EXPIR_TIMEVAL).tv_usec = (NOW_TIMEVAL).tv_usec + (USECS) - E_6; \
- } else \
- { \
- (EXPIR_TIMEVAL).tv_sec = (NOW_TIMEVAL).tv_sec + (SECS); \
- (EXPIR_TIMEVAL).tv_usec = (NOW_TIMEVAL).tv_usec + (USECS); \
- } \
-}
-
-#define EVAL_REM_TIME(NOW_TIMEVAL, EXPIR_TIMEVAL, SECS, USECS) \
-{ \
- gettimeofday(&(NOW_TIMEVAL), NULL); \
- if (((NOW_TIMEVAL).tv_sec > (EXPIR_TIMEVAL).tv_sec) \
- || (((NOW_TIMEVAL).tv_sec == (EXPIR_TIMEVAL).tv_sec) \
- && ((NOW_TIMEVAL).tv_usec >= (EXPIR_TIMEVAL).tv_usec))) \
- return; \
- if ((EXPIR_TIMEVAL).tv_usec < (NOW_TIMEVAL).tv_usec) \
- { \
- SECS = (time_t)((EXPIR_TIMEVAL).tv_sec - (NOW_TIMEVAL).tv_sec - 1); \
- USECS = (int)(E_6 + (EXPIR_TIMEVAL).tv_usec - (NOW_TIMEVAL).tv_usec); \
- } else \
- { \
- SECS = (time_t)((EXPIR_TIMEVAL).tv_sec - (NOW_TIMEVAL).tv_sec); \
- USECS = (int)((EXPIR_TIMEVAL).tv_usec - (NOW_TIMEVAL).tv_usec); \
- } \
-}
-
-#if defined(__osf__) || defined(__hpux)
-/* The above platforms do not support clock_nanosleep, so use nanosleep. To avoid sleeping for much
- * longer than requested in case of pathologically many interrupts, recalculate the remaining duration
- * with gettimeofday.
+#define SET_EXPIR_TIME(NOW_TIMEVAL, EXPIR_TIMEVAL, SECS, USECS) \
+MBSTART { \
+ gettimeofday(&(NOW_TIMEVAL), NULL); \
+ if (E_6 <= ((NOW_TIMEVAL).tv_usec + USECS)) \
+ { \
+ (EXPIR_TIMEVAL).tv_sec = (NOW_TIMEVAL).tv_sec + (SECS) + 1; \
+ (EXPIR_TIMEVAL).tv_usec = (NOW_TIMEVAL).tv_usec + (USECS) - E_6; \
+ } else \
+ { \
+ (EXPIR_TIMEVAL).tv_sec = (NOW_TIMEVAL).tv_sec + (SECS); \
+ (EXPIR_TIMEVAL).tv_usec = (NOW_TIMEVAL).tv_usec + (USECS); \
+ } \
+} MBEND
+
+/* This macro *does not* have surrounding braces and *will break* out of the block it is in on non-positive remaining time. */
+#define UPDATE_REM_TIME_OR_BREAK(NOW_TIMEVAL, EXPIR_TIMEVAL, SECS, USECS) \
+ gettimeofday(&(NOW_TIMEVAL), NULL); \
+ if (((NOW_TIMEVAL).tv_sec > (EXPIR_TIMEVAL).tv_sec) \
+ || (((NOW_TIMEVAL).tv_sec == (EXPIR_TIMEVAL).tv_sec) \
+ && ((NOW_TIMEVAL).tv_usec >= (EXPIR_TIMEVAL).tv_usec))) \
+ break; \
+ if ((EXPIR_TIMEVAL).tv_usec < (NOW_TIMEVAL).tv_usec) \
+ { \
+ SECS = (time_t)((EXPIR_TIMEVAL).tv_sec - (NOW_TIMEVAL).tv_sec - 1); \
+ USECS = (int)(E_6 + (EXPIR_TIMEVAL).tv_usec - (NOW_TIMEVAL).tv_usec); \
+ } else \
+ { \
+ SECS = (time_t)((EXPIR_TIMEVAL).tv_sec - (NOW_TIMEVAL).tv_sec); \
+ USECS = (int)((EXPIR_TIMEVAL).tv_usec - (NOW_TIMEVAL).tv_usec); \
+ } \
+
+#ifdef __MVS__
+/* On z/OS neither clock_nanosleep nor nanosleep is available, so use a combination of sleep, usleep, and gettimeofday instead.
+ * Since we do not have a z/OS box presently, this implementation has not been tested, and so it likely needs some casts at the very
+ * least. Another note is that sleep is unsafe to mix with timers on other platforms, but on z/OS the documentation does not mention
+ * any fallouts, so this should be verified. If it turns out that sleep is unsafe, we might have to use pthread_cond_timewait or
+ * call usleep (which, given that we have used it on z/OS before, should be safe) in a loop.
*/
-# define NANOSLEEP(MS) \
-{ \
- int status, usecs; \
- struct timespec req; \
- struct timeval now, expir; \
- \
- assert(0 < MS); \
- req.tv_sec = (time_t)(MS / 1000); \
- usecs = (MS % 1000) * 1000; \
- req.tv_nsec = (long)(usecs * 1000); \
- assert(E_9 > req.tv_nsec); \
- SET_EXPIR_TIME(now, expir, req.tv_sec, usecs) \
- while ((-1 == (status = nanosleep(&req, NULL))) && (EINTR == errno)) \
- { \
- EVAL_REM_TIME(now, expir, req.tv_sec, usecs); \
- req.tv_nsec = (long)(usecs * 1000); \
- } \
-}
-#elif defined(__MVS__)
-/* On z/OS neither clock_nanosleep nor nanosleep is available, so use a combination of sleep, usleep,
- * and gettimeofday instead. Since we do not have a z/OS box presently, this implementation has not
- * been tested, and so it likely needs some casts at the very least. Another note is that sleep is
- * unsafe to mix with timers on other platforms, but on z/OS the documentation does not mention any
- * fallouts, so this should be verified. If it turns out that sleep is unsafe, we might have to use
- * pthread_cond_timewait or call usleep (which, given that we have used it on z/OS before, should be
- * safe) in a loop.
- */
-# define NANOSLEEP(MS) \
-{ \
- int secs; \
- useconds_t usecs; \
- struct timeval now, expir; \
- \
- assert(0 < MS); \
- secs = MS / 1000; \
- usecs = MS % 1000; \
- SET_EXPIR_TIME(now, expir, secs, usecs) \
- while (0 < secs) \
- { \
- sleep(secs); /* BYPASSOK: */ \
- EVAL_REM_TIME(now, expir, secs, usecs); \
- } \
- while (0 < usecs) \
- { \
- usleep(usecs); \
- EVAL_REM_TIME(now, expir, secs, usecs); \
- } \
-}
+# define SLEEP_USEC(MICROSECONDS, RESTART) \
+MBSTART { \
+ int secs, interrupted; \
+ useconds_t usecs; \
+ struct timeval now, expir; \
+ \
+ assert(0 < MICROSECONDS); \
+ secs = (MICROSECONDS) / 1000; \
+ usecs = (MICROSECONDS) % E_6; \
+ SET_EXPIR_TIME(now, expir, secs, usecs); \
+ if (RESTART) \
+ { \
+ while (0 < secs) \
+ { \
+ sleep(secs); /* BYPASSOK */ \
+ /* This macro will break the loop when it is time. */ \
+ UPDATE_REM_TIME_OR_BREAK(now, expir, secs, usecs); \
+ } \
+ while (0 < usecs) \
+ { \
+ usleep(usecs); \
+ /* This macro will break the loop when it is time. */ \
+ UPDATE_REM_TIME_OR_BREAK(now, expir, secs, usecs); \
+ } \
+ } else \
+ { \
+ interrupted = sleep(secs); /* BYPASSOK */ \
+ if (!interrupted) \
+ { /* This macro will break the loop when it is time. */ \
+ UPDATE_REM_TIME_OR_BREAK(now, expir, secs, usecs); \
+ usleep(usecs); \
+ } \
+ } \
+} MBEND
#else
-/* The major supported platforms should have clock_nanosleep implementation, so to avoid extending the
- * actual sleep times, we use clock_gettime to first obtain the point of reference, and then specify
- * the TIMER_ABSTIME flag when invoking clock_nanosleep for absolute offsets. In case CLOCK_REALTIME
- * type of clock is not supported on some platform, we fall back on nanosleep.
+/* On most UNIX platforms a combination of nanosleep() and gettimeofday() proved to be the most supported, accurate, and
+ * operationally sound approach. Alternatives for implementing high-resolution sleeps include clock_nanosleep() and nsleep()
+ * (AIX only); however, neither of those provide better accuracy or speed. Additionally, the clock_gettime() function does not
+ * prove to be any faster than gettimeofday(), and since we do not (yet) operate at sub-millisecond levels, it is not utilized.
+ *
+ * On Linux boxes be sure to define USER_HZ macro (in gt_timers.c) appropriately to mitigate the timer clustering imposed by
+ * the OS. Historically, the USER_HZ value has defaulted to 100 (same as HZ), thus resulting in at most 10ms accuracy when
+ * delivering timed events.
*/
-# define NANOSLEEP(MS) \
-{ \
- int status, usecs; \
- struct timespec req, cur; \
- struct timeval now, expir; \
- \
- req.tv_sec = (time_t)(MS / 1000); \
- usecs = (MS % 1000) * 1000; \
- req.tv_nsec = (long)(usecs * 1000); \
- assert(E_9 > req.tv_nsec); \
- if ((-1 == (status = clock_gettime(CLOCK_REALTIME, &cur))) && (EINVAL == errno)) \
- { \
- SET_EXPIR_TIME(now, expir, req.tv_sec, usecs) \
- while ((-1 == (status = nanosleep(&req, NULL))) && (EINTR == errno)) \
- { \
- EVAL_REM_TIME(now, expir, req.tv_sec, usecs); \
- req.tv_nsec = (long)(usecs * 1000); \
- } \
- } else \
- { \
- if (E_9 <= cur.tv_nsec + req.tv_nsec) \
- { \
- req.tv_sec += (cur.tv_sec + 1); \
- req.tv_nsec = cur.tv_nsec + req.tv_nsec - E_9; \
- } else \
- { \
- req.tv_sec += cur.tv_sec; \
- req.tv_nsec += cur.tv_nsec; \
- } \
- while ((-1 == (status = clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &req, NULL))) \
- && (EINTR == errno)); \
- } \
-}
-#endif
-
-# ifdef _AIX
- typedef struct timestruc_t m_time_t;
-# define nanosleep_func nsleep
-# endif
-
-# if defined(__sparc) || defined(__hpux) || defined(__osf__) || defined (__linux__) || defined (__CYGWIN__)
- typedef struct timespec m_time_t;
-# define nanosleep_func nanosleep
-# endif
-
-# ifdef _UWIN
-# include "gtm_select.h"
-# define usleep_func gtm_usleep
-# endif
-
-# ifdef __MVS__
- typedef struct timespec m_time_t;
-# define nanosleep_func usleep /* m_nsleep will not work on OS390, but it is not used */
-# endif
-
-#else
-
-# error "Unsure of support for sleep functions on this non-UNIX platform"
-
+# define SLEEP_USEC(MICROSECONDS, RESTART) \
+MBSTART { \
+ int status, usecs; \
+ struct timespec req; \
+ struct timeval now, expir; \
+ \
+ assert(0 < MICROSECONDS); \
+ req.tv_sec = (time_t)((MICROSECONDS) / E_6); \
+ req.tv_nsec = (long)((usecs = (MICROSECONDS) % E_6) * 1000); /* Assignment! */ \
+ assert(E_9 > req.tv_nsec); \
+ if (RESTART) \
+ { \
+ SET_EXPIR_TIME(now, expir, req.tv_sec, usecs); \
+ while ((-1 == (status = nanosleep(&req, NULL))) && (EINTR == errno)) \
+ { /* This macro will break the loop when it is time. */ \
+ UPDATE_REM_TIME_OR_BREAK(now, expir, req.tv_sec, usecs); \
+ req.tv_nsec = (long)(usecs * 1000); \
+ } \
+ } else \
+ nanosleep(&req, NULL); \
+} MBEND
#endif
#endif /* SLEEP_H */
diff --git a/sr_unix/ss_context_mgr.c b/sr_unix/ss_context_mgr.c
index 9dc425f..de62378 100644
--- a/sr_unix/ss_context_mgr.c
+++ b/sr_unix/ss_context_mgr.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2009, 2010 Fidelity Information Services, Inc *
+ * Copyright 2009, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -21,6 +21,9 @@
#include "gtm_stdlib.h"
#include "gtm_tempnam.h"
#include "gtm_time.h"
+#ifdef DEBUG
+#include "gtm_ipc.h"
+#endif
#include "gdsroot.h"
#include "gdskill.h"
@@ -64,6 +67,8 @@ GBLREF sgmnt_addrs *cs_addrs;
GBLREF enum gtmImageTypes image_type;
GBLREF uint4 process_id;
+error_def(ERR_SYSCALL);
+
boolean_t ss_create_context(snapshot_context_ptr_t lcl_ss_ctx, int ss_shmcycle)
{
shm_snapshot_ptr_t ss_shm_ptr;
@@ -73,7 +78,6 @@ boolean_t ss_create_context(snapshot_context_ptr_t lcl_ss_ctx, int ss_shmcycle)
void *ss_shmaddr;
ZOS_ONLY(int realfiletag;)
- error_def(ERR_SYSCALL);
ZOS_ONLY(error_def(ERR_BADTAG);)
ZOS_ONLY(error_def(ERR_TEXT);)
@@ -107,7 +111,7 @@ boolean_t ss_create_context(snapshot_context_ptr_t lcl_ss_ctx, int ss_shmcycle)
/* It's possible that by the time we attach to the shared memory, the identifier has been removed from the
* system by INTEG which completed it's processing.
*/
- assert((EIDRM == status) || (EINVAL == status));
+ assert(SHM_REMOVED(status));
assert(INVALID_SHMID == lcl_ss_ctx->attach_shmid);
lcl_ss_ctx->cur_state = SNAPSHOT_SHM_ATTACH_FAIL;
lcl_ss_ctx->failure_errno = status;
@@ -135,7 +139,7 @@ boolean_t ss_create_context(snapshot_context_ptr_t lcl_ss_ctx, int ss_shmcycle)
{
status = errno;
assert(FALSE);
- rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("Error with shmdt"), CALLFROM, status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("Error with shmdt"), CALLFROM, status);
}
lcl_ss_ctx->attach_shmid = lcl_ss_ctx->nl_shmid = INVALID_SHMID; /* reset shmid since we failed */
lcl_ss_ctx->cur_state = SHADOW_FIL_OPEN_FAIL;
@@ -154,8 +158,6 @@ boolean_t ss_destroy_context(snapshot_context_ptr_t lcl_ss_ctx)
{
int status;
- error_def(ERR_SYSCALL);
-
assert(NULL != lcl_ss_ctx);
if (FD_INVALID != lcl_ss_ctx->shdw_fd)
{
@@ -167,7 +169,7 @@ boolean_t ss_destroy_context(snapshot_context_ptr_t lcl_ss_ctx)
{
status = errno;
assert(FALSE);
- rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("Error with shmdt"), CALLFROM, status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("Error with shmdt"), CALLFROM, status);
}
}
/* Invalidate the context */
diff --git a/sr_unix/tab_probecrit_rec.h b/sr_unix/tab_probecrit_rec.h
new file mode 100644
index 0000000..60db612
--- /dev/null
+++ b/sr_unix/tab_probecrit_rec.h
@@ -0,0 +1,23 @@
+/****************************************************************
+ * *
+ * Copyright 2008, 2014 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* Note that each TAB_PROBECRIT_REC entry corresponds to a field in cs_addrs
+ * Therefore, avoid any operation that changes the offset of any of these entries in the cs_addrs.
+ * Additions are to be done at the END of the structures.
+ * Replacing existing fields with new fields is allowed (provided their implications are thoroughly analyzed).
+ */
+TAB_PROBECRIT_REC(t_get_crit , "CPT", "nanoseconds for the probe to get crit ")
+TAB_PROBECRIT_REC(p_crit_failed , "CFN", "# of failures of the probe to get crit ")
+TAB_PROBECRIT_REC(p_crit_que_slps , "CQN", "# of queue sleeps by the probe ")
+TAB_PROBECRIT_REC(p_crit_yields , "CYN", "# of process yields by the probe ")
+TAB_PROBECRIT_REC(p_crit_que_full , "CQF", "# of queue fulls encountered by the probe ")
+TAB_PROBECRIT_REC(p_crit_que_slots , "CQE", "# of empty queue slots found by the probe ")
+TAB_PROBECRIT_REC(p_crit_success , "CAT", "# of crit acquired total successes ")
diff --git a/sr_unix/trigger.h b/sr_unix/trigger.h
index ba431ab..27b1e1a 100644
--- a/sr_unix/trigger.h
+++ b/sr_unix/trigger.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2013 Fidelity Information Services, Inc *
+ * Copyright 2010, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -13,22 +13,26 @@
#define MUPIP_TRIGGER_INCLUDED
/* The order of these must match trigger_subs defined in mtables.c */
-#define TRIGGER_SUBDEF(SUBNAME) SUBNAME##_SUB
typedef enum
{
+#define TRIGGER_SUBSDEF(SUBSTYPE, SUBSNAME, LITMVALNAME, TRIGFILEQUAL, PARTOFHASH) SUBSTYPE,
#include "trigger_subs_def.h"
-#undef TRIGGER_SUBDEF
- ,NUM_TOTAL_SUBS
+#undef TRIGGER_SUBSDEF
+ NUM_TOTAL_SUBS
} trig_subs_t;
-#define NUM_SUBS NUM_TOTAL_SUBS - 2 /* Number of subscripts users deal with - hash values not included */
-
+#define NUM_SUBS NUM_TOTAL_SUBS - 2 /* Number of subscripts users deal with.
+ * Hash related subscripts BHASH/LHASH not included.
+ * This assumes BHASH and LHASH are last two entires and is asserted
+ * in "trigger_delete"/"write_out_trigger"/"trigger_update" function entry.
+ */
typedef enum
{
STATS_ADDED = 0,
STATS_DELETED,
- STATS_UNCHANGED,
STATS_MODIFIED,
- STATS_ERROR,
+ STATS_ERROR_TRIGFILE,
+ STATS_UNCHANGED_TRIGFILE,
+ STATS_NOERROR_TRIGFILE,
NUM_STATS
} trig_stats_t;
@@ -52,16 +56,15 @@ typedef enum
#define MAX_USER_TRIGNAME_LEN MAX_MIDENT_LEN - 3 /* 3 -- 2 for run time chars and 1 for delimiter */
#define MAX_AUTO_TRIGNAME_LEN (MAX_MIDENT_LEN - 4 - NUM_TRIGNAME_SEQ_CHARS) /* 4 -- 2 for runtime characters, 2 for delims */
-#define LITERAL_BHASH "BHASH"
-#define LITERAL_LHASH "LHASH"
#define LITERAL_MAXHASHVAL "$" /* '$' collates between '#' and '%' */
#define LITERAL_HASHSEQNUM "#SEQNUM"
#define LITERAL_HASHTNAME "#TNAME"
#define LITERAL_HASHTNCOUNT "#TNCOUNT"
#define LITERAL_HASHTRHASH "#TRHASH"
-#define LITERAL_BHASH_LEN STR_LIT_LEN(LITERAL_BHASH)
-#define LITERAL_LHASH_LEN STR_LIT_LEN(LITERAL_LHASH)
+#define TRSBS_IN_NONE 0
+#define TRSBS_IN_BHASH 1
+#define TRSBS_IN_LHASH 2
#define INITIAL_CYCLE "1"
@@ -70,18 +73,17 @@ typedef enum
#define XTENDED_START_LEN STR_LIT_LEN(XTENDED_START)
#define XTENDED_STOP_LEN STR_LIT_LEN(XTENDED_STOP)
-#define CMDS_PRESENT 0
-#define OPTIONS_PRESENT 0
-#define OPTION_CONFLICT 0
-#define NO_NAME_CHANGE 0
#define PUT_SUCCESS 0
-#define SEQ_SUCCESS 0
-#define ADD_NEW_TRIGGER -1
-#define INVALID_LABEL -2
-#define K_ZTK_CONFLICT -3
-#define VAL_TOO_LONG -4
-#define KEY_TOO_LONG -5
-#define TOO_MANY_TRIGGERS -6
+
+#define INVALID_LABEL -1
+#define K_ZTK_CONFLICT -2
+#define VAL_TOO_LONG -3
+#define KEY_TOO_LONG -4
+#define TOO_MANY_TRIGGERS -5
+#define ADD_SET_MODIFY_KILL_TRIG -6
+#define ADD_SET_NOCHNG_KILL_TRIG -7
+#define OPTIONS_CMDS_CONFLICT -8
+#define NAME_CMDS_CONFLICT -9
#define CONV_TO_ZWR(LEN, PTR, OUT_LEN, OUT_STR) \
{ \
@@ -226,6 +228,27 @@ typedef enum
TREF(gv_some_subsc_null) = was_null; \
}
+#define BUILD_HASHT_SUB_SUB_MSUB_MSUB_CURRKEY_T(TRIG_VAL, SUB0, LEN0, SUB1, LEN1, SUB2, SUB3) \
+{ \
+ boolean_t was_null = FALSE, is_null = FALSE; \
+ mval *subsc_ptr; \
+ DCL_THREADGBL_ACCESS; \
+ \
+ SETUP_THREADGBL_ACCESS; \
+ BUILD_HASHT_CURRKEY_NAME; \
+ subsc_ptr = &TRIG_VAL; \
+ STR2MVAL(TRIG_VAL, SUB0, LEN0); \
+ COPY_SUBS_TO_GVCURRKEY(subsc_ptr, gv_cur_region, gv_currkey, was_null, is_null); \
+ STR2MVAL(TRIG_VAL, SUB1, LEN1); \
+ COPY_SUBS_TO_GVCURRKEY(subsc_ptr, gv_cur_region, gv_currkey, was_null, is_null); \
+ subsc_ptr = &SUB2; \
+ COPY_SUBS_TO_GVCURRKEY(subsc_ptr, gv_cur_region, gv_currkey, was_null, is_null); \
+ subsc_ptr = &SUB3; \
+ COPY_SUBS_TO_GVCURRKEY(subsc_ptr, gv_cur_region, gv_currkey, was_null, is_null); \
+ TREF(gv_last_subsc_null) = is_null; \
+ TREF(gv_some_subsc_null) = was_null; \
+}
+
#define BUILD_HASHT_SUB_MSUB_SUB_CURRKEY_T(TRIG_VAL, SUB1, LEN1, SUB2, SUB3, LEN3) \
{ \
boolean_t was_null = FALSE, is_null = FALSE; \
@@ -246,6 +269,28 @@ typedef enum
TREF(gv_some_subsc_null) = was_null; \
}
+#define BUILD_HASHT_SUB_SUB_MSUB_SUB_CURRKEY_T(TRIG_VAL, SUB0, LEN0, SUB1, LEN1, SUB2, SUB3, LEN3) \
+{ \
+ boolean_t was_null = FALSE, is_null = FALSE; \
+ mval *subsc_ptr; \
+ DCL_THREADGBL_ACCESS; \
+ \
+ SETUP_THREADGBL_ACCESS; \
+ BUILD_HASHT_CURRKEY_NAME; \
+ subsc_ptr = &TRIG_VAL; \
+ STR2MVAL(TRIG_VAL, SUB0, LEN0); \
+ COPY_SUBS_TO_GVCURRKEY(subsc_ptr, gv_cur_region, gv_currkey, was_null, is_null); \
+ STR2MVAL(TRIG_VAL, SUB1, LEN1); \
+ COPY_SUBS_TO_GVCURRKEY(subsc_ptr, gv_cur_region, gv_currkey, was_null, is_null); \
+ subsc_ptr = &SUB2; \
+ COPY_SUBS_TO_GVCURRKEY(subsc_ptr, gv_cur_region, gv_currkey, was_null, is_null); \
+ subsc_ptr = &TRIG_VAL; \
+ STR2MVAL(TRIG_VAL, SUB3, LEN3); \
+ COPY_SUBS_TO_GVCURRKEY(subsc_ptr, gv_cur_region, gv_currkey, was_null, is_null); \
+ TREF(gv_last_subsc_null) = is_null; \
+ TREF(gv_some_subsc_null) = was_null; \
+}
+
#define BUILD_HASHT_SUB_SUB_SUB_CURRKEY_T(TRIG_VAL, SUB1, LEN1, SUB2, LEN2, SUB3, LEN3) \
{ \
boolean_t was_null = FALSE, is_null = FALSE; \
@@ -288,35 +333,35 @@ typedef enum
TREF(gv_some_subsc_null) = was_null; \
}
-#define TRIGGER_GLOBAL_ASSIGNMENT_STR(TRIG_VAL, VALUE, LEN, RES) \
-{ \
- STR2MVAL(trig_val, VALUE, LEN); \
- if (gv_currkey->end + 1 + TRIG_VAL.str.len + SIZEOF(rec_hdr) > gv_cur_region->max_rec_size) \
- RES = VAL_TOO_LONG; \
- else if (gv_currkey->end + 1 > gv_cur_region->max_key_size) \
- RES = KEY_TOO_LONG; \
- else \
- { \
- gvcst_put(&TRIG_VAL); \
- RES = PUT_SUCCESS; \
- } \
-}
-
-#define TRIGGER_GLOBAL_ASSIGNMENT_MVAL(TRIG_VAL, VALUE, RES) \
-{ \
- mval *lcl_mv_ptr; \
- \
- lcl_mv_ptr = &VALUE; \
- MV_FORCE_STR(lcl_mv_ptr); \
- if (gv_currkey->end + 1 + TRIG_VAL.str.len + SIZEOF(rec_hdr) > gv_cur_region->max_rec_size) \
- RES = VAL_TOO_LONG; \
- else if (gv_currkey->end + 1 > gv_cur_region->max_key_size) \
- RES = KEY_TOO_LONG; \
- else \
- { \
- gvcst_put(lcl_mv_ptr); \
- RES = PUT_SUCCESS; \
- } \
+#define TRIGGER_GLOBAL_ASSIGNMENT_STR(TRIG_VAL, VALUE, LEN, RES) \
+{ \
+ STR2MVAL(TRIG_VAL, VALUE, LEN); \
+ if (LEN > gv_cur_region->max_rec_size) \
+ RES = VAL_TOO_LONG; \
+ else if (gv_currkey->end + 1 > gv_cur_region->max_key_size) \
+ RES = KEY_TOO_LONG; \
+ else \
+ { \
+ gvcst_put(&TRIG_VAL); \
+ RES = PUT_SUCCESS; \
+ } \
+}
+
+#define TRIGGER_GLOBAL_ASSIGNMENT_MVAL(VALUE, RES) \
+{ \
+ mval *lcl_mv_ptr; \
+ \
+ lcl_mv_ptr = &VALUE; \
+ MV_FORCE_STR(lcl_mv_ptr); \
+ if (lcl_mv_ptr->str.len > gv_cur_region->max_rec_size) \
+ RES = VAL_TOO_LONG; \
+ else if (gv_currkey->end + 1 > gv_cur_region->max_key_size) \
+ RES = KEY_TOO_LONG; \
+ else \
+ { \
+ gvcst_put(lcl_mv_ptr); \
+ RES = PUT_SUCCESS; \
+ } \
}
#define BUILD_HASHT_SUB_CURRKEY(SUB, LEN) \
@@ -354,6 +399,20 @@ typedef enum
BUILD_HASHT_SUB_MSUB_SUB_CURRKEY_T(trig_val, SUB1, LEN1, SUB2, SUB3, LEN3); \
}
+#define BUILD_HASHT_SUB_SUB_MSUB_SUB_CURRKEY(SUB0, LEN0, SUB1, LEN1, SUB2, SUB3, LEN3) \
+{ \
+ mval trig_val; \
+ \
+ BUILD_HASHT_SUB_SUB_MSUB_SUB_CURRKEY_T(trig_val, SUB0, LEN0, SUB1, LEN1, SUB2, SUB3, LEN3); \
+}
+
+#define BUILD_HASHT_SUB_SUB_MSUB_MSUB_CURRKEY(SUB0, LEN0, SUB1, LEN1, SUB2, SUB3) \
+{ \
+ mval trig_val; \
+ \
+ BUILD_HASHT_SUB_SUB_MSUB_MSUB_CURRKEY_T(trig_val, SUB0, LEN0, SUB1, LEN1, SUB2, SUB3); \
+}
+
#define BUILD_HASHT_SUB_SUB_SUB_CURRKEY(SUB1, LEN1, SUB2, LEN2, SUB3, LEN3) \
{ \
mval trig_val; \
@@ -384,12 +443,20 @@ typedef enum
TRIGGER_GLOBAL_ASSIGNMENT_STR(trig_val, VALUE, LEN, RES); \
}
+#define SET_TRIGGER_GLOBAL_SUB_MVAL(SUB1, LEN1, VALUE, RES) \
+{ \
+ mval trig_val; \
+ \
+ BUILD_HASHT_SUB_CURRKEY_T(trig_val, SUB1, LEN1); \
+ TRIGGER_GLOBAL_ASSIGNMENT_MVAL(VALUE, RES); \
+}
+
#define SET_TRIGGER_GLOBAL_SUB_SUB_MVAL(SUB1, LEN1, SUB2, LEN2, VALUE, RES) \
{ \
mval trig_val; \
\
BUILD_HASHT_SUB_SUB_CURRKEY_T(trig_val, SUB1, LEN1, SUB2, LEN2); \
- TRIGGER_GLOBAL_ASSIGNMENT_MVAL(trig_val, VALUE, RES); \
+ TRIGGER_GLOBAL_ASSIGNMENT_MVAL(VALUE, RES); \
}
#define SET_TRIGGER_GLOBAL_SUB_MSUB_SUB_STR(SUB1, LEN1, SUB2, SUB3, LEN3, VALUE, LEN, RES) \
@@ -404,7 +471,15 @@ typedef enum
{ \
mval trig_val; \
\
- BUILD_HASHT_SUB_MSUB_MSUB_CURRKEY_T(trig_val, SUB1, LEN1, SUB2, SUB3); \
+ BUILD_HASHT_SUB_MSUB_MSUB_CURRKEY_T(trig_val, SUB1, LEN1, SUB2, SUB3); \
+ TRIGGER_GLOBAL_ASSIGNMENT_STR(trig_val, VALUE, LEN, RES); \
+}
+
+#define SET_TRIGGER_GLOBAL_SUB_SUB_MSUB_MSUB_STR(SUB0, LEN0, SUB1, LEN1, SUB2, SUB3, VALUE, LEN, RES) \
+{ \
+ mval trig_val; \
+ \
+ BUILD_HASHT_SUB_SUB_MSUB_MSUB_CURRKEY_T(trig_val, SUB0, LEN0, SUB1, LEN1, SUB2, SUB3); \
TRIGGER_GLOBAL_ASSIGNMENT_STR(trig_val, VALUE, LEN, RES); \
}
@@ -413,7 +488,7 @@ typedef enum
mval trig_val; \
\
BUILD_HASHT_SUB_MSUB_SUB_CURRKEY_T(trig_val, SUB1, LEN1, SUB2, SUB3, LEN3); \
- TRIGGER_GLOBAL_ASSIGNMENT_MVAL(trig_val, VALUE, RES); \
+ TRIGGER_GLOBAL_ASSIGNMENT_MVAL(VALUE, RES); \
}
#define SET_TRIGGER_GLOBAL_SUB_SUB_SUB_STR(SUB1, LEN1, SUB2, LEN2, SUB3, LEN3, VALUE, LEN, RES) \
@@ -429,7 +504,7 @@ typedef enum
mval trig_val; \
\
BUILD_HASHT_SUB_SUB_SUB_CURRKEY_T(trig_val, SUB1, LEN1, SUB2, LEN2, SUB3, LEN3); \
- TRIGGER_GLOBAL_ASSIGNMENT_MVAL(trig_val, VALUE, RES); \
+ TRIGGER_GLOBAL_ASSIGNMENT_MVAL(VALUE, RES); \
}
#define SET_TRIGGER_GLOBAL_SUB_MSUB_SUB_MSUB_MVAL(SUB1, LEN1, SUB2, SUB3, LEN3, SUB4, VALUE, RES) \
@@ -437,7 +512,7 @@ typedef enum
mval trig_val; \
\
BUILD_HASHT_SUB_MSUB_SUB_MSUB_CURRKEY_T(trig_val, SUB1, LEN1, SUB2, SUB3, LEN3, SUB4); \
- TRIGGER_GLOBAL_ASSIGNMENT_MVAL(trig_val, VALUE, RES); \
+ TRIGGER_GLOBAL_ASSIGNMENT_MVAL(VALUE, RES); \
}
#define SET_TRIGGER_GLOBAL_SUB_MSUB_SUB_MSUB_STR(SUB1, LEN1, SUB2, SUB3, LEN3, SUB4, VALUE, LEN, RES) \
@@ -487,4 +562,40 @@ typedef enum
} \
}
+/* If this is the first call of this macro inside a function, then note down whatever is in the util_output buffer.
+ * This is the prefix that is already printed for the first "util_out_print_gtmio" call. For the second and future
+ * calls of the "util_out_print_gtmio" function inside the current function, print the noted down prefix first.
+ * This gives more user-friendly output (e.g. deleting wildcard triggers by name prints same Line # in each trigger
+ * that gets deleted).
+ */
+#define UTIL_PRINT_PREFIX_IF_NEEDED(FIRST_GTMIO, UTILPREFIX, UTILPREFIXLEN) \
+{ \
+ boolean_t ret; \
+ \
+ if (FIRST_GTMIO) \
+ { \
+ ret = util_out_save(UTILPREFIX, UTILPREFIXLEN); \
+ assert(ret); /* assert we have space to save prefix in UTILPREFIX */ \
+ /* If there was no space to save the prefix, print second and later calls of \
+ * "util_out_print_gtmio" without the prefix in pro. \
+ */ \
+ if (ret) \
+ FIRST_GTMIO = FALSE; \
+ } else \
+ util_out_print_gtmio("!AD", NOFLUSH, *UTILPREFIXLEN, UTILPREFIX); \
+}
+
+#define SET_DISP_TRIGVN(REG, DISP_TRIGVN, DISP_TRIGVN_LEN, TRIGVN, TRIGVN_LEN) \
+{ \
+ memcpy(DISP_TRIGVN, TRIGVN, TRIGVN_LEN); \
+ DISP_TRIGVN_LEN = TRIGVN_LEN; \
+ MEMCPY_LIT(&DISP_TRIGVN[DISP_TRIGVN_LEN], SPANREG_REGION_LIT); \
+ DISP_TRIGVN_LEN += SPANREG_REGION_LITLEN; \
+ memcpy(&DISP_TRIGVN[DISP_TRIGVN_LEN], REG->rname, REG->rname_len); \
+ DISP_TRIGVN_LEN += REG->rname_len; \
+ DISP_TRIGVN[DISP_TRIGVN_LEN++] = ')'; \
+ assert(DISP_TRIGVN_LEN < ARRAYSIZE(DISP_TRIGVN)); \
+ DISP_TRIGVN[DISP_TRIGVN_LEN] = '\0'; /* null terminate just in case */ \
+}
+
#endif /* MUPIP_TRIGGER_INCLUDED */
diff --git a/sr_unix/trigger_compare.c b/sr_unix/trigger_compare.c
index cad5cc1..1d80891 100644
--- a/sr_unix/trigger_compare.c
+++ b/sr_unix/trigger_compare.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2013 Fidelity Information Services, Inc *
+ * Copyright 2010, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -26,7 +26,7 @@
#include "trigger.h"
#include "trigger_compare_protos.h"
#include "trigger_gbl_fill_xecute_buffer.h"
-#include "mvalconv.h" /* Needed for MV_FORCE_MVAL and MV_FORCE_UMVAL */
+#include "mvalconv.h" /* Needed for MV_FORCE_UMVAL, MV_FORCE_* variants */
#include "op.h"
#include "nametabtyp.h"
#include "targ_alloc.h" /* for SET_GVTARGET_TO_HASHT_GBL & SWITCH_TO_DEFAULT_REGION */
@@ -38,29 +38,36 @@
#include "jnl.h" /* needed for tp.h */
#include "tp.h"
#include "hashtab_mname.h"
+#include "t_retry.h"
GBLREF sgmnt_data_ptr_t cs_data;
-GBLREF gd_addr *gd_header;
GBLREF gd_region *gv_cur_region;
GBLREF gv_key *gv_currkey;
GBLREF gv_namehead *gv_target;
+GBLREF unsigned int t_tries;
-LITREF mval literal_hasht;
LITREF mval literal_one;
LITREF mval literal_ten;
LITREF char *trigger_subs[];
-#define NON_HASH -1
-LITDEF int trig_subsc_xlate_tbl[11] =
+LITDEF int trig_subsc_partofhash[] =
{
- NON_HASH, 1, NON_HASH, NON_HASH, 4, 5, 6, 7, NON_HASH, NON_HASH, NON_HASH
+#define TRIGGER_SUBSDEF(SUBSTYPE, SUBSNAME, LITMVALNAME, TRIGFILEQUAL, PARTOFHASH) PARTOFHASH,
+#include "trigger_subs_def.h"
+#undef TRIGGER_SUBSDEF
};
-#define COPY_VAL_TO_INDEX_STR(SUB, PTR) \
-{ \
- memcpy(PTR, values[SUB], value_len[SUB]); \
- PTR += value_len[SUB]; \
- *PTR++ = '\0'; \
+#define COPY_VAL_TO_INDEX_STR(SUB, PTR) \
+{ \
+ int len; \
+ \
+ len = value_len[SUB]; \
+ if (len) \
+ { \
+ memcpy(PTR, values[SUB], len); \
+ PTR += len; \
+ *PTR++ = '\0'; \
+ } \
}
error_def(ERR_TRIGDEFBAD);
@@ -131,14 +138,15 @@ boolean_t search_trigger_hash(char *trigvn, int trigvn_len, stringkey *trigger_h
int4 len;
mval mv_hash;
boolean_t match, multi_record;
- char *ptr;
+ char *ptr, *ptr2;
int trig_index;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
collision_indx_ptr = &collision_indx;
MV_FORCE_UMVAL(&mv_hash, trigger_hash->hash_code);
- BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(LITERAL_HASHTRHASH, STR_LIT_LEN(LITERAL_HASHTRHASH), mv_hash, "", 0);
+ BUILD_HASHT_SUB_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len,
+ LITERAL_HASHTRHASH, STR_LIT_LEN(LITERAL_HASHTRHASH), mv_hash, "", 0);
while (TRUE)
{
op_gvorder(collision_indx_ptr);
@@ -148,30 +156,38 @@ boolean_t search_trigger_hash(char *trigvn, int trigvn_len, stringkey *trigger_h
match = FALSE;
break;
}
- BUILD_HASHT_SUB_MSUB_MSUB_CURRKEY(LITERAL_HASHTRHASH, STR_LIT_LEN(LITERAL_HASHTRHASH), mv_hash, collision_indx);
+ BUILD_HASHT_SUB_SUB_MSUB_MSUB_CURRKEY(trigvn, trigvn_len,
+ LITERAL_HASHTRHASH, STR_LIT_LEN(LITERAL_HASHTRHASH), mv_hash, collision_indx);
if (!gvcst_get(&key_val))
- { /* There has to be a #TRHASH entry */
- assert(FALSE);
+ { /* There has to be a #TRHASH entry or else it is a retry situation (due to concurrent updates) */
+ 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(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn,
LEN_AND_LIT("\"#TRHASH\""), mv_hash.str.len, mv_hash.str.addr);
}
ptr = key_val.str.addr;
- len = STRLEN(ptr);
- if ((len != trigvn_len) || (0 != memcmp(trigvn, ptr, len)))
- {
- hash_index = 0;
- match = FALSE;
- break;
+ ptr2 = memchr(ptr, '\0', key_val.str.len);
+ if (NULL == ptr2)
+ { /* We expect $c(0) in the middle of ptr. If we dont find it, this is a restartable situation */
+ 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(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn,
+ LEN_AND_LIT("\"#TRHASH\""), mv_hash.str.len, mv_hash.str.addr);
}
- ptr += len;
- assert(('\0' == *ptr) && (key_val.str.len > len));
- ptr++;
- A2I(ptr, key_val.str.addr + key_val.str.len, trig_index);
+ len = ptr2 - ptr;
+ if ((len != trigvn_len) || (0 != memcmp(trigvn, ptr, len)))
+ continue;
+ assert(0 != match_index);
+ assert(('\0' == *ptr2) && (key_val.str.len > len));
+ ptr2++;
+ A2I(ptr2, key_val.str.addr + key_val.str.len, trig_index);
assert(-1 != trig_index);
- if ((0 == match_index) || (match_index == trig_index))
+ match = (match_index == trig_index);
+ if (match)
{
- hash_index = MV_FORCE_INT(collision_indx_ptr);
- match = TRUE;
+ hash_index = MV_FORCE_UINT(collision_indx_ptr);
break;
}
}
@@ -180,21 +196,20 @@ boolean_t search_trigger_hash(char *trigvn, int trigvn_len, stringkey *trigger_h
}
boolean_t search_triggers(char *trigvn, int trigvn_len, char **values, uint4 *value_len, stringkey *trigger_hash, int *hash_indx,
- int *trig_indx, int match_index, boolean_t doing_set)
+ int *trig_indx, boolean_t doing_set)
{
mval collision_indx;
mval *collision_indx_ptr;
mval data_val;
- mname_entry gvname;
boolean_t have_value;
mval key_val;
int4 len;
- boolean_t multi_record;
+ boolean_t multi_record, kill_cmp, first_match_kill_cmp;
mval mv_hash;
mval mv_trig_indx;
- boolean_t match;
+ boolean_t match, first_match;
int4 num;
- char *ptr;
+ char *ptr, *ptr2;
int4 rec_len;
int sub_indx;
mval sub_val;
@@ -203,68 +218,93 @@ boolean_t search_triggers(char *trigvn, int trigvn_len, char **values, uint4 *va
int trig_index;
char *xecute_buff;
int4 xecute_len;
- gvnh_reg_t *gvnh_reg;
+ unsigned char util_buff[MAX_TRIG_UTIL_LEN]; /* needed for HASHT_GVN_DEFINITION_RETRY_OR_ERROR macro */
+ int4 util_len;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
+ assert(cs_addrs->hasht_tree == gv_target); /* should have been set up by caller */
+ assert(gv_target->root); /* should have been ensured by caller */
collision_indx_ptr = &collision_indx;
MV_FORCE_UMVAL(&mv_hash, trigger_hash->hash_code);
- BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(LITERAL_HASHTRHASH, STR_LIT_LEN(LITERAL_HASHTRHASH), mv_hash, "", 0);
- xecute_buff = NULL;
+ BUILD_HASHT_SUB_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len,
+ LITERAL_HASHTRHASH, STR_LIT_LEN(LITERAL_HASHTRHASH), mv_hash, "", 0);
+ DEBUG_ONLY(xecute_buff = NULL;)
+ first_match = TRUE;
while (TRUE)
{
match = TRUE;
op_gvorder(collision_indx_ptr);
if (0 == collision_indx_ptr->str.len)
{
- trig_hash_index = trig_index = 0;
match = FALSE;
break;
}
- BUILD_HASHT_SUB_MSUB_MSUB_CURRKEY(LITERAL_HASHTRHASH, STR_LIT_LEN(LITERAL_HASHTRHASH), mv_hash, collision_indx);
+ BUILD_HASHT_SUB_SUB_MSUB_MSUB_CURRKEY(trigvn, trigvn_len,
+ LITERAL_HASHTRHASH, STR_LIT_LEN(LITERAL_HASHTRHASH), mv_hash, collision_indx);
if (!gvcst_get(&key_val))
- { /* There has to be a #TRHASH entry */
- assert(FALSE);
+ { /* There has to be a #TRHASH entry or else it is a retry situation (due to concurrent updates) */
+ 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(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn,
LEN_AND_LIT("\"#TRHASH\""), mv_hash.str.len, mv_hash.str.addr);
}
ptr = key_val.str.addr;
- len = STRLEN(ptr);
+ ptr2 = memchr(ptr, '\0', key_val.str.len);
+ if (NULL == ptr2)
+ { /* We expect $c(0) in the middle of ptr. If we dont find it, this is a restartable situation */
+ 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(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn,
+ LEN_AND_LIT("\"#TRHASH\""), mv_hash.str.len, mv_hash.str.addr);
+ }
+ len = ptr2 - ptr;
if ((len != trigvn_len) || (0 != memcmp(trigvn, ptr, len)))
- {
- trig_hash_index = trig_index = 0;
- match = FALSE;
- break;
+ { /* We expect all hashes under ^#t(<gbl>,"#TRHASH",...) to correspond to <gbl> in their value.
+ * If not this is a TRIGDEFBAD situation.
+ */
+ 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(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn,
+ LEN_AND_LIT("\"#TRHASH\""), mv_hash.str.len, mv_hash.str.addr);
}
ptr += len;
assert(('\0' == *ptr) && (key_val.str.len > len));
ptr++;
A2I(ptr, key_val.str.addr + key_val.str.len, trig_index);
assert(-1 != trig_index);
- gvname.var_name.addr = trigvn;
- gvname.var_name.len = trigvn_len;
- COMPUTE_HASH_MNAME(&gvname);
- GV_BIND_NAME_ONLY(gd_header, &gvname, gvnh_reg);
- assert(cs_addrs == gv_target->gd_csa);
- SET_GVTARGET_TO_HASHT_GBL(cs_addrs);
- INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
- MV_FORCE_MVAL(&mv_trig_indx, trig_index);
+ MV_FORCE_UMVAL(&mv_trig_indx, trig_index);
for (sub_indx = 0; sub_indx < NUM_TOTAL_SUBS; sub_indx++)
{
- if (NON_HASH == trig_subsc_xlate_tbl[sub_indx])
- continue;
- if (!doing_set && ((DELIM_SUB == sub_indx) || (ZDELIM_SUB == sub_indx) || (PIECES_SUB == sub_indx)))
+ if (((TRSBS_IN_NONE == trig_subsc_partofhash[sub_indx]) && (CMD_SUB != sub_indx))
+ || (!doing_set && (TRSBS_IN_BHASH == trig_subsc_partofhash[sub_indx])))
continue;
+ assert((CMD_SUB == sub_indx) || ((TRSBS_IN_LHASH | TRSBS_IN_BHASH) == trig_subsc_partofhash[sub_indx])
+ || (doing_set && (TRSBS_IN_BHASH == trig_subsc_partofhash[sub_indx])));
BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, mv_trig_indx, trigger_subs[sub_indx],
STRLEN(trigger_subs[sub_indx]));
multi_record = FALSE;
have_value = gvcst_get(&key_val);
+ if (CMD_SUB == sub_indx)
+ {
+ if (!have_value || !key_val.str.len)
+ { /* No CMD node. Retry situation (due to concurrent updates) */
+ HASHT_GVN_DEFINITION_RETRY_OR_ERROR(trig_index, ",\"CMD\"", cs_addrs);
+ }
+ kill_cmp = ((NULL != memchr(key_val.str.addr, 'K', key_val.str.len))
+ || (NULL != memchr(key_val.str.addr, 'R', key_val.str.len)));
+ continue;
+ }
if (!have_value && (XECUTE_SUB == sub_indx))
{
op_gvdata(&data_val);
multi_record = (literal_ten.m[0] == data_val.m[0]) && (literal_ten.m[1] == data_val.m[1]);
+ have_value = multi_record;
}
- if ((0 == value_len[sub_indx]) && !have_value && !multi_record)
+ if ((0 == value_len[sub_indx]) && !have_value)
continue;
if (XECUTE_SUB == sub_indx)
{
@@ -272,45 +312,75 @@ boolean_t search_triggers(char *trigvn, int trigvn_len, char **values, uint4 *va
xecute_buff = trigger_gbl_fill_xecute_buffer(trigvn, trigvn_len, &mv_trig_indx,
multi_record ? NULL : &key_val, &xecute_len);
if ((value_len[sub_indx] == xecute_len)
- && (0 == memcmp(values[sub_indx], xecute_buff, value_len[sub_indx])))
+ && (0 == memcmp(values[sub_indx], xecute_buff, value_len[sub_indx])))
{
free(xecute_buff);
- xecute_buff = NULL;
+ DEBUG_ONLY(xecute_buff = NULL;)
continue;
} else
{
free(xecute_buff);
- xecute_buff = NULL;
- trig_hash_index = trig_index = 0;
+ DEBUG_ONLY(xecute_buff = NULL;)
match = FALSE;
break;
}
} else
{
if (have_value && (value_len[sub_indx] == key_val.str.len)
- && (0 == memcmp(values[sub_indx], key_val.str.addr, value_len[sub_indx])))
+ && (0 == memcmp(values[sub_indx], key_val.str.addr, value_len[sub_indx])))
continue;
else
{
- trig_hash_index = trig_index = 0;
match = FALSE;
break;
}
}
}
- SWITCH_TO_DEFAULT_REGION;
- if (!match || ((0 != match_index) && (match_index != trig_index)))
+ if (match)
{
- BUILD_HASHT_SUB_MSUB_MSUB_CURRKEY(LITERAL_HASHTRHASH, STR_LIT_LEN(LITERAL_HASHTRHASH), mv_hash,
- collision_indx);
- continue;
+ trig_hash_index = MV_FORCE_UINT(collision_indx_ptr);
+ assert(trig_index);
+ /* It is possible for 2 triggers to match (in case a KILL and SET trigger for same gvn/subs/xecute string
+ * exists separately). In this case, based on "doing_set", we match the appropriate trigger. If 2 triggers
+ * dont match, we use the only matching trigger even if the trigger type (set/kill) does not match.
+ */
+ if (first_match)
+ {
+ *trig_indx = trig_index;
+ *hash_indx = trig_hash_index;
+ if (!doing_set && kill_cmp)
+ break; /* KILL type trigger sought and found one. Stop at first. */
+ first_match = FALSE; /* search once more */
+ first_match_kill_cmp = kill_cmp;
+ /* Assume this is the only matching trigger for now. Later match if found will override */
+ } else
+ {
+ assert((first_match_kill_cmp != kill_cmp) || !kill_cmp);
+ /* We have TWO matches. Pick the more appropriate one. */
+ if (doing_set != kill_cmp)
+ { /* Current trigger matches input trigger type. Overwrite first_match */
+ *trig_indx = trig_index;
+ *hash_indx = trig_hash_index;
+ }
+ /* else current trigger does not match input trigger type. Use first_match as is (already done) */
+ break;
+ }
}
- trig_hash_index = MV_FORCE_INT(collision_indx_ptr);
- match = TRUE;
- break;
+ /* We did a BUILD_HASHT_SUB_SUB_MSUB_MSUB_CURRKEY at the beginning of this for loop but gv_currkey would have been
+ * overwritten in various places since then so reinitialize it before doing op_gvorder of next iteration.
+ */
+ BUILD_HASHT_SUB_SUB_MSUB_MSUB_CURRKEY(trigvn, trigvn_len,
+ LITERAL_HASHTRHASH, STR_LIT_LEN(LITERAL_HASHTRHASH), mv_hash, collision_indx);
+ }
+ if (!match)
+ {
+ if (first_match)
+ {
+ *trig_indx = 0;
+ *hash_indx = 0;
+ } else
+ match = TRUE;
}
- *trig_indx = trig_index;
- *hash_indx = trig_hash_index;
return match;
}
#endif /* GTM_TRIGGER */
diff --git a/sr_unix/trigger_compare_protos.h b/sr_unix/trigger_compare_protos.h
index 3c2c092..7dbba8f 100644
--- a/sr_unix/trigger_compare_protos.h
+++ b/sr_unix/trigger_compare_protos.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010 Fidelity Information Services, Inc *
+ * Copyright 2010, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -19,5 +19,5 @@ void build_set_cmp_str(char *trigvn, int trigvn_len, char **values, uint4 *value
boolean_t search_trigger_hash(char *trigvn, int trigvn_len, stringkey *trigger_hash, int trig_indx, int *hash_indx);
boolean_t search_triggers(char *trigvn, int trigvn_len, char **values, uint4 *value_len, stringkey *trigger_hash, int *hash_indx,
- int *trig_indx, int match_index, boolean_t doing_set);
+ int *trig_indx, boolean_t doing_set);
#endif
diff --git a/sr_unix/trigger_delete.c b/sr_unix/trigger_delete.c
index 5ce31ba..f03c832 100644
--- a/sr_unix/trigger_delete.c
+++ b/sr_unix/trigger_delete.c
@@ -30,7 +30,7 @@
#include "mv_stent.h" /* for COPY_SUBS_TO_GVCURRKEY macro */
#include "gvsub2str.h" /* for COPY_SUBS_TO_GVCURRKEY */
#include "format_targ_key.h" /* for COPY_SUBS_TO_GVCURRKEY */
-#include "targ_alloc.h" /* for SET_GVTARGET_TO_HASHT_GBL & SWITCH_TO_DEFAULT_REGION */
+#include "targ_alloc.h" /* for SET_GVTARGET_TO_HASHT_GBL */
#include "hashtab_str.h"
#include "wbox_test_init.h"
#include "trigger_delete_protos.h"
@@ -55,19 +55,15 @@ GBLREF gd_addr *gd_header;
GBLREF gd_region *gv_cur_region;
GBLREF gv_key *gv_currkey;
GBLREF gv_namehead *gv_target;
-GBLREF gv_namehead *gv_target_list;
GBLREF sgm_info *sgm_info_ptr;
GBLREF sgmnt_data_ptr_t cs_data;
-GBLREF trans_num local_tn;
GBLREF uint4 dollar_tlevel;
-LITREF mval literal_hasht;
LITREF char *trigger_subs[];
error_def(ERR_TEXT);
error_def(ERR_TRIGDEFBAD);
error_def(ERR_TRIGLOADFAIL);
-error_def(ERR_TRIGMODINTP);
error_def(ERR_TRIGMODREGNOTRW);
error_def(ERR_TRIGNAMBAD);
@@ -78,71 +74,52 @@ error_def(ERR_TRIGNAMBAD);
{ \
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(CSA) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, \
- trigvn, LEN_AND_LIT("\"#TRHASH\""),HASH->str.len, \
- HASH->str.addr); \
- } \
+ assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number); \
+ rts_error_csa(CSA_ARG(CSA) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, \
+ trigvn, LEN_AND_LIT("\"#TRHASH\""),HASH->str.len, \
+ HASH->str.addr); \
}
-#define SEARCH_AND_KILL_BY_HASH(TRIGVN, TRIGVN_LEN, HASH, TRIG_INDEX, CSA) \
-{ \
- mval mv_hash_indx; \
- mval mv_hash_val; \
- int hash_index; \
- \
- if (search_trigger_hash(TRIGVN, TRIGVN_LEN, HASH, TRIG_INDEX, &hash_index)) \
- { \
- MV_FORCE_UMVAL(&mv_hash_val, HASH->hash_code); \
- MV_FORCE_MVAL(&mv_hash_indx, hash_index); \
- BUILD_HASHT_SUB_MSUB_MSUB_CURRKEY(LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash_val, mv_hash_indx); \
- gvcst_kill(FALSE); \
- } else \
- { /* There has to be a #TRHASH entry */ \
- TRHASH_DEFINITION_RETRY_OR_ERROR(HASH, CSA); \
- } \
+#define SEARCH_AND_KILL_BY_HASH(TRIGVN, TRIGVN_LEN, HASH, TRIG_INDEX, CSA) \
+{ \
+ mval mv_hash_indx; \
+ mval mv_hash_val; \
+ int hash_index; \
+ \
+ if (search_trigger_hash(TRIGVN, TRIGVN_LEN, HASH, TRIG_INDEX, &hash_index)) \
+ { \
+ MV_FORCE_UMVAL(&mv_hash_val, HASH->hash_code); \
+ MV_FORCE_UMVAL(&mv_hash_indx, hash_index); \
+ BUILD_HASHT_SUB_SUB_MSUB_MSUB_CURRKEY(TRIGVN, TRIGVN_LEN, \
+ LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash_val, mv_hash_indx); \
+ gvcst_kill(FALSE); \
+ } else \
+ { /* There has to be a #TRHASH entry */ \
+ TRHASH_DEFINITION_RETRY_OR_ERROR(HASH, CSA); \
+ } \
}
-STATICFNDEF void cleanup_trigger_hash(char *trigvn, int trigvn_len, char **values, uint4 *value_len, stringkey *set_hash,
+void cleanup_trigger_hash(char *trigvn, int trigvn_len, char **values, uint4 *value_len, stringkey *set_hash,
stringkey *kill_hash, boolean_t del_kill_hash, int match_index)
{
sgmnt_addrs *csa;
uint4 len;
- gv_key save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
- gd_region *save_gv_cur_region;
- gv_namehead *save_gv_target;
- sgm_info *save_sgm_info_ptr;
- mstr trigger_key;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
- SAVE_TRIGGER_REGION_INFO(save_currkey);
- SWITCH_TO_DEFAULT_REGION;
csa = cs_addrs;
- assert(0 != gv_target->root);
- if (gv_cur_region->read_only)
- rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(gv_cur_region));
- if (NULL != strchr(values[CMD_SUB], 'S'))
- {
+ 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 */
+ if ((NULL != strchr(values[CMD_SUB], 'S')) && (set_hash->hash_code != kill_hash->hash_code))
SEARCH_AND_KILL_BY_HASH(trigvn, trigvn_len, set_hash, match_index, csa)
- }
if (del_kill_hash)
- {
SEARCH_AND_KILL_BY_HASH(trigvn, trigvn_len, kill_hash, match_index, csa);
- }
- RESTORE_TRIGGER_REGION_INFO(save_currkey);
}
-STATICFNDEF void cleanup_trigger_name(char *trigvn, int trigvn_len, char *trigger_name, int trigger_name_len)
+void cleanup_trigger_name(char *trigvn, int trigvn_len, char *trigger_name, int trigger_name_len)
{
int4 result;
- gv_key save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
- gd_region *save_gv_cur_region;
- gv_namehead *save_gv_target;
- gv_namehead *save_gvtarget;
- sgm_info *save_sgm_info_ptr;
char trunc_name[MAX_TRIGNAME_LEN + 1];
uint4 used_trigvn_len;
mval val;
@@ -153,29 +130,24 @@ STATICFNDEF void cleanup_trigger_name(char *trigvn, int trigvn_len, char *trigge
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 */
/* assume user defined name or auto gen name whose GVN < 21 chars */
- is_auto_name = FALSE;
if (!trigger_user_name(trigger_name, trigger_name_len))
{ /* auto gen name uses #TNCOUNT and #SEQNO under #TNAME */
is_auto_name = TRUE;
used_trigvn_len = MIN(trigvn_len, MAX_AUTO_TRIGNAME_LEN);
memcpy(trunc_name, trigvn, used_trigvn_len);
- }
- SAVE_TRIGGER_REGION_INFO(save_currkey);
- SWITCH_TO_DEFAULT_REGION;
- if (0 != gv_target->root)
- {
- if (gv_cur_region->read_only)
- rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(gv_cur_region));
if (is_auto_name)
{
/* $get(^#t("#TNAME",<trunc_name>,"#TNCOUNT")) */
BUILD_HASHT_SUB_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trunc_name,
used_trigvn_len, LITERAL_HASHTNCOUNT, STRLEN(LITERAL_HASHTNCOUNT));
if (gvcst_get(&val))
- { /* only long autogenerated names have a #TNCOUNT entry */
+ { /* each autogenerated name has a #TNCOUNT entry */
val_ptr = &val;
- var_count = MV_FORCE_INT(val_ptr);
+ var_count = MV_FORCE_UINT(val_ptr);
if (1 == var_count)
{
/* kill ^#t("#TNAME",<trunc_name>) to kill #TNCOUNT and #SEQNO */
@@ -185,7 +157,7 @@ STATICFNDEF void cleanup_trigger_name(char *trigvn, int trigvn_len, char *trigge
} else
{
var_count--;
- MV_FORCE_MVAL(&val, var_count);
+ MV_FORCE_UMVAL(&val, var_count);
/* set ^#t("#TNAME",GVN,"#TNCOUNT")=var_count */
SET_TRIGGER_GLOBAL_SUB_SUB_SUB_MVAL(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME),
trunc_name, used_trigvn_len, LITERAL_HASHTNCOUNT,
@@ -194,61 +166,59 @@ STATICFNDEF void cleanup_trigger_name(char *trigvn, int trigvn_len, char *trigge
}
}
}
- /* kill ^#t("#TNAME",<trigger_name>,:) or zkill ^#t("#TNAME",<trigger_name>) if is_auto_name==FALSE */
- BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trigger_name,
- trigger_name_len - 1);
- gvcst_kill(is_auto_name);
- }
- RESTORE_TRIGGER_REGION_INFO(save_currkey);
+ } else
+ is_auto_name = FALSE;
+ /* kill ^#t("#TNAME",<trigger_name>,:) or zkill ^#t("#TNAME",<trigger_name>) if is_auto_name==FALSE */
+ BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trigger_name,
+ trigger_name_len - 1);
+ gvcst_kill(is_auto_name);
}
-STATICFNDEF int4 update_trigger_name_value(int trigvn_len, char *trig_name, int trig_name_len, int new_trig_index)
+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];
char new_trig_name[MAX_TRIGNAME_LEN + 1];
int num_len;
- char *ptr;
+ char *ptr, *ptr2;
int4 result;
- gv_key save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
- 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(save_currkey);
- SWITCH_TO_DEFAULT_REGION;
- if (gv_cur_region->read_only)
- rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(gv_cur_region));
- assert(0 != gv_target->root);
+ 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);
- 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);
- }
+ 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;
+ ptr = trig_gbl.str.addr;
+ ptr2 = memchr(ptr, '\0', trig_gbl.str.len);
+ if (NULL == ptr2)
+ { /* We expect $c(0) in the middle of ptr. If we dont find it, this is a restartable situation */
+ 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);
+ }
+ len = (ptr2 - ptr) + 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 ^#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);
- RESTORE_TRIGGER_REGION_INFO(save_currkey);
return result;
}
@@ -262,79 +232,86 @@ STATICFNDEF int4 update_trigger_hash_value(char *trigvn, int trigvn_len, char **
mval mv_hash;
mval mv_hash_indx;
int num_len;
- char *ptr;
+ char *ptr, *ptr2;
int4 result;
- gv_key save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
- gd_region *save_gv_cur_region;
- gv_namehead *save_gv_target;
- sgm_info *save_sgm_info_ptr;
char tmp_str[MAX_MIDENT_LEN + 1 + MAX_DIGITS_IN_INT];
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
- SAVE_TRIGGER_REGION_INFO(save_currkey);
- SWITCH_TO_DEFAULT_REGION;
+ 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 */
csa = cs_addrs;
- 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);
- if (NULL != strchr(values[CMD_SUB], 'S'))
+ if ((NULL != strchr(values[CMD_SUB], 'S')) && (set_hash->hash_code != kill_hash->hash_code))
{
if (!search_trigger_hash(trigvn, trigvn_len, set_hash, old_trig_index, &hash_index))
{ /* There has to be an entry with the old hash value, we just looked it up */
TRHASH_DEFINITION_RETRY_OR_ERROR(set_hash, csa);
}
MV_FORCE_UMVAL(&mv_hash, set_hash->hash_code);
- MV_FORCE_MVAL(&mv_hash_indx, hash_index);
- BUILD_HASHT_SUB_MSUB_MSUB_CURRKEY(LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, mv_hash_indx);
+ MV_FORCE_UMVAL(&mv_hash_indx, hash_index);
+ BUILD_HASHT_SUB_SUB_MSUB_MSUB_CURRKEY(trigvn, trigvn_len,
+ LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, mv_hash_indx);
if (!gvcst_get(&key_val))
{ /* There has to be a #TRHASH entry */
TRHASH_DEFINITION_RETRY_OR_ERROR(set_hash, csa);
}
assert((MAX_MIDENT_LEN + 1 + MAX_DIGITS_IN_INT) >= key_val.str.len);
- len = STRLEN(key_val.str.addr);
+ ptr = key_val.str.addr;
+ ptr2 = memchr(ptr, '\0', key_val.str.len);
+ if (NULL == ptr2)
+ { /* We expect $c(0) in the middle of ptr. If we dont find it, this is a restartable situation */
+ 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(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn,
+ LEN_AND_LIT("\"#BHASH\""), mv_hash.str.len, mv_hash.str.addr);
+ }
+ len = ptr2 - ptr;
memcpy(tmp_str, key_val.str.addr, len);
ptr = tmp_str + len;
*ptr++ = '\0';
num_len = 0;
I2A(ptr, num_len, new_trig_index);
len += num_len + 1;
- SET_TRIGGER_GLOBAL_SUB_MSUB_MSUB_STR(LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, mv_hash_indx,
- tmp_str, len, result);
+ SET_TRIGGER_GLOBAL_SUB_SUB_MSUB_MSUB_STR(trigvn, trigvn_len,
+ LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, mv_hash_indx, tmp_str, len, result);
if (PUT_SUCCESS != result)
- {
- RESTORE_TRIGGER_REGION_INFO(save_currkey);
return result;
- }
}
if (!search_trigger_hash(trigvn, trigvn_len, kill_hash, old_trig_index, &hash_index))
{ /* There has to be an entry with the old hash value, we just looked it up */
TRHASH_DEFINITION_RETRY_OR_ERROR(kill_hash, csa);
}
MV_FORCE_UMVAL(&mv_hash, kill_hash->hash_code);
- MV_FORCE_MVAL(&mv_hash_indx, hash_index);
- BUILD_HASHT_SUB_MSUB_MSUB_CURRKEY(LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, mv_hash_indx);
+ MV_FORCE_UMVAL(&mv_hash_indx, hash_index);
+ BUILD_HASHT_SUB_SUB_MSUB_MSUB_CURRKEY(trigvn, trigvn_len,
+ LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, mv_hash_indx);
if (!gvcst_get(&key_val))
{ /* There has to be a #TRHASH entry */
TRHASH_DEFINITION_RETRY_OR_ERROR(kill_hash, csa);
}
assert((MAX_MIDENT_LEN + 1 + MAX_DIGITS_IN_INT) >= key_val.str.len);
- len = STRLEN(key_val.str.addr);
+ ptr = key_val.str.addr;
+ ptr2 = memchr(ptr, '\0', key_val.str.len);
+ if (NULL == ptr2)
+ { /* We expect $c(0) in the middle of ptr. If we dont find it, this is a restartable situation */
+ 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(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn,
+ LEN_AND_LIT("\"#LHASH\""), mv_hash.str.len, mv_hash.str.addr);
+ }
+ len = ptr2 - ptr;
memcpy(tmp_str, key_val.str.addr, len);
ptr = tmp_str + len;
*ptr++ = '\0';
num_len = 0;
I2A(ptr, num_len, new_trig_index);
len += num_len + 1;
- SET_TRIGGER_GLOBAL_SUB_MSUB_MSUB_STR(LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, mv_hash_indx,
- tmp_str, len, result);
- if (PUT_SUCCESS != result)
- {
- RESTORE_TRIGGER_REGION_INFO(save_currkey);
- return result;
- }
- RESTORE_TRIGGER_REGION_INFO(save_currkey);
- return PUT_SUCCESS;
+ SET_TRIGGER_GLOBAL_SUB_SUB_MSUB_MSUB_STR(trigvn, trigvn_len,
+ LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, mv_hash_indx, tmp_str, len, result);
+ return result;
}
boolean_t trigger_delete_name(char *trigger_name, uint4 trigger_name_len, uint4 *trig_stats)
@@ -342,15 +319,13 @@ boolean_t trigger_delete_name(char *trigger_name, uint4 trigger_name_len, uint4
sgmnt_addrs *csa;
char curr_name[MAX_MIDENT_LEN + 1];
uint4 curr_name_len, orig_name_len;
- mname_entry gvname;
mval mv_curr_nam;
- boolean_t name_found;
- char *ptr;
+ char *ptr, *ptr2;
char *name_tail_ptr;
+ char save_name[MAX_MIDENT_LEN + 1];
gv_key save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
- gd_region *save_gv_cur_region;
+ gd_region *save_gv_cur_region, *lgtrig_reg;
gv_namehead *save_gv_target;
- char save_name[MAX_MIDENT_LEN + 1];
sgm_info *save_sgm_info_ptr;
mval trig_gbl;
mval trig_value;
@@ -360,9 +335,18 @@ boolean_t trigger_delete_name(char *trigger_name, uint4 trigger_name_len, uint4
int trig_indx;
int badpos;
boolean_t wildcard;
- gvnh_reg_t *gvnh_reg;
+ char utilprefix[1024];
+ int utilprefixlen;
+ boolean_t first_gtmio;
+ uint4 triggers_deleted;
mval trigjrec;
boolean_t jnl_format_done;
+ gd_region *reg, *reg_top;
+ char disp_trigvn[MAX_MIDENT_LEN + SPANREG_REGION_LITLEN + MAX_RN_LEN + 1 + 1];
+ /* SPANREG_REGION_LITLEN for " (region ", MAX_RN_LEN for region name,
+ * 1 for ")" and 1 for trailing '\0'.
+ */
+ int disp_trigvn_len;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
@@ -371,144 +355,168 @@ boolean_t trigger_delete_name(char *trigger_name, uint4 trigger_name_len, uint4
trigjrec.str.len = trigger_name_len--;
trigjrec.str.addr = trigger_name++;
orig_name_len = trigger_name_len;
- if ((0 == trigger_name_len) || (trigger_name_len !=
- (badpos = validate_input_trigger_name(trigger_name, trigger_name_len, &wildcard))))
+ if ((0 == trigger_name_len)
+ || (trigger_name_len != (badpos = validate_input_trigger_name(trigger_name, trigger_name_len, &wildcard))))
{ /* is the input name valid */
CONV_STR_AND_PRINT("Invalid trigger NAME string: ", orig_name_len, trigger_name);
/* badpos is the string position where the bad character was found, pretty print it */
+ trig_stats[STATS_ERROR_TRIGFILE]++;
return TRIG_FAILURE;
}
name_tail_ptr = trigger_name + trigger_name_len - 1;
- if (TRIGNAME_SEQ_DELIM == *name_tail_ptr || wildcard )
- /* drop the trailing # sign or wildcard */
- trigger_name_len--;
- /* $data(^#t) */
- SWITCH_TO_DEFAULT_REGION;
- if (gv_cur_region->read_only)
- rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(gv_cur_region));
- INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
- if (0 == gv_target->root)
- {
- util_out_print_gtmio("Trigger named !AD does not exist", FLUSH, orig_name_len, trigger_name);
- trig_stats[STATS_UNCHANGED]++;
- return TRIG_SUCCESS;
- }
- /* To write the LGTRIG logical jnl record, choose the first region that has journaling enabled */
+ if ((TRIGNAME_SEQ_DELIM == *name_tail_ptr) || wildcard)
+ trigger_name_len--; /* drop the trailing # sign for wildcard */
jnl_format_done = FALSE;
- csa = cs_addrs;
- if (JNL_WRITE_LOGICAL_RECS(csa))
+ lgtrig_reg = NULL;
+ first_gtmio = TRUE;
+ triggers_deleted = 0;
+ assert(trigger_name_len < MAX_MIDENT_LEN);
+ memcpy(save_name, trigger_name, trigger_name_len);
+ save_name[trigger_name_len] = '\0';
+ utilprefixlen = ARRAYSIZE(utilprefix);
+ for (reg = gd_header->regions, reg_top = reg + gd_header->n_regions; reg < reg_top; reg++)
{
- assert(!gv_cur_region->read_only);
- /* Attach to jnlpool. Normally SET or KILL of the ^#t records take care of this but in case this is a NO-OP
- * trigger operation that wont happen and we still want to write a TLGTRIG/ULGTRIG journal record. Hence
- * the need to do this.
+ GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(reg);
+ csa = cs_addrs;
+ if (NULL == csa) /* not BG or MM access method */
+ continue;
+ /* gv_target now points to ^#t in region "reg" */
+ /* To write the LGTRIG logical jnl record, choose some region that has journaling enabled */
+ if (!reg->read_only && !jnl_format_done && JNL_WRITE_LOGICAL_RECS(csa))
+ lgtrig_reg = reg;
+ if (!gv_target->root)
+ continue;
+ memcpy(curr_name, save_name, trigger_name_len);
+ curr_name_len = trigger_name_len;
+ do {
+ /* GVN = $get(^#t("#TNAME",curr_name) */
+ BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), curr_name, curr_name_len);
+ if (gvcst_get(&trig_gbl))
+ {
+ if (reg->read_only)
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(reg));
+ SAVE_TRIGGER_REGION_INFO(save_currkey);
+ ptr = trig_gbl.str.addr;
+ ptr2 = memchr(ptr, '\0', trig_gbl.str.len);
+ if (NULL == ptr2)
+ { /* We expect $c(0) in the middle of ptr. If not found, this is a restartable situation */
+ 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\""),
+ curr_name_len, curr_name);
+ }
+ trigvn_len = ptr2 - ptr;
+ assert(MAX_MIDENT_LEN >= trigvn_len);
+ memcpy(trigvn, ptr, trigvn_len);
+ ptr += trigvn_len + 1;
+ /* the index is just beyond the length of the GVN string */
+ A2I(ptr, trig_gbl.str.addr + trig_gbl.str.len, trig_indx);
+ SET_DISP_TRIGVN(reg, disp_trigvn, disp_trigvn_len, trigvn, trigvn_len);
+ /* $get(^#t(GVN,"COUNT") */
+ BUILD_HASHT_SUB_SUB_CURRKEY(trigvn, trigvn_len, LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT));
+ if (!gvcst_get(&trigger_count))
+ {
+ UTIL_PRINT_PREFIX_IF_NEEDED(first_gtmio, utilprefix, &utilprefixlen);
+ util_out_print_gtmio("Trigger named !AD exists in the lookup table, "
+ "but global ^!AD has no triggers",
+ FLUSH, curr_name_len, curr_name, disp_trigvn_len, disp_trigvn);
+ trig_stats[STATS_ERROR_TRIGFILE]++;
+ return TRIG_FAILURE;
+ }
+ if (!jnl_format_done && JNL_WRITE_LOGICAL_RECS(csa))
+ {
+ jnl_format(JNL_LGTRIG, NULL, &trigjrec, 0);
+ jnl_format_done = TRUE;
+ }
+ /* kill the target trigger for GVN at index trig_indx */
+ if (PUT_SUCCESS != (trigger_delete(trigvn, trigvn_len, &trigger_count, trig_indx)))
+ {
+ UTIL_PRINT_PREFIX_IF_NEEDED(first_gtmio, utilprefix, &utilprefixlen);
+ util_out_print_gtmio("Trigger named !AD exists in the lookup table for global ^!AD," \
+ " but was not deleted!", FLUSH, orig_name_len, trigger_name,
+ disp_trigvn_len, disp_trigvn);
+ trig_stats[STATS_ERROR_TRIGFILE]++;
+ return TRIG_FAILURE;
+ } else
+ {
+ csa->incr_db_trigger_cycle = TRUE;
+ trigger_incr_cycle(trigvn, trigvn_len); /* ^#t records changed, increment cycle */
+ if (dollar_ztrigger_invoked)
+ { /* Increment db_dztrigger_cycle so that next gvcst_put/gvcst_kill in this
+ * transaction, on this region, will re-read triggers. See trigger_update.c
+ * for a comment on why it is okay for db_dztrigger_cycle to be incremented
+ * more than once in the same transaction.
+ */
+ csa->db_dztrigger_cycle++;
+ }
+ trig_stats[STATS_DELETED]++;
+ if (0 == trig_stats[STATS_ERROR_TRIGFILE])
+ {
+ UTIL_PRINT_PREFIX_IF_NEEDED(first_gtmio, utilprefix, &utilprefixlen);
+ util_out_print_gtmio("Deleted trigger named '!AD' for global ^!AD",
+ FLUSH, curr_name_len, curr_name, disp_trigvn_len, disp_trigvn);
+ }
+ }
+ RESTORE_TRIGGER_REGION_INFO(save_currkey);
+ triggers_deleted++;
+ }
+ if (!wildcard)
+ /* not a wild card, don't $order for the next match */
+ break;
+ op_gvorder(&mv_curr_nam);
+ if (0 == mv_curr_nam.str.len)
+ break;
+ assert(mv_curr_nam.str.len < MAX_MIDENT_LEN);
+ memcpy(curr_name, mv_curr_nam.str.addr, mv_curr_nam.str.len);
+ curr_name_len = mv_curr_nam.str.len;
+ if (0 != memcmp(curr_name, save_name, trigger_name_len))
+ /* stop when gv_order returns a string that no longer starts save_name */
+ break;
+ } while (TRUE);
+ }
+ if (!jnl_format_done && (NULL != lgtrig_reg))
+ { /* There was no journaled region that had a ^#t update, but found at least one journaled region
+ * so write a LGTRIG logical jnl record there.
+ */
+ GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(lgtrig_reg);
+ csa = cs_addrs;
+ /* Attach to jnlpool. Normally SET or KILL of the ^#t records take care of this but in
+ * case this is a NO-OP trigger operation that wont update any ^#t records and we still
+ * want to write a TLGTRIG/ULGTRIG journal record. Hence the need to do this.
*/
JNLPOOL_INIT_IF_NEEDED(csa, csa->hdr, csa->nl);
assert(dollar_tlevel);
- T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_TRIGLOADFAIL); /* needed to set update_trans TRUE on this region
- * even if NO db updates happen to ^#t nodes. */
+ /* below is needed to set update_trans TRUE on this region even if NO db updates happen to ^#t nodes */
+ T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_TRIGLOADFAIL);
jnl_format(JNL_LGTRIG, NULL, &trigjrec, 0);
jnl_format_done = TRUE;
}
- name_found = FALSE;
- assert(trigger_name_len < MAX_MIDENT_LEN);
- memcpy(save_name, trigger_name, trigger_name_len);
- save_name[trigger_name_len] = '\0';
- memcpy(curr_name, save_name, trigger_name_len);
- curr_name_len = trigger_name_len;
- STR2MVAL(mv_curr_nam, trigger_name, trigger_name_len);
- do {
- /* GVN = $get(^#t("#TNAME",curr_name) */
- BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), curr_name, curr_name_len);
- if (gvcst_get(&trig_gbl))
- {
- SAVE_TRIGGER_REGION_INFO(save_currkey);
- ptr = trig_gbl.str.addr;
- trigvn_len = STRLEN(trig_gbl.str.addr);
- assert(MAX_MIDENT_LEN >= trigvn_len);
- memcpy(trigvn, ptr, trigvn_len);
- ptr += trigvn_len + 1;
- /* the index is just beyon the length of the GVN string */
- A2I(ptr, trig_gbl.str.addr + trig_gbl.str.len, trig_indx);
- gvname.var_name.addr = trigvn;
- gvname.var_name.len = trigvn_len;
- COMPUTE_HASH_MNAME(&gvname);
- GV_BIND_NAME_ONLY(gd_header, &gvname, gvnh_reg);
- assert(cs_addrs == gv_target->gd_csa);
- csa = cs_addrs;
- if (gv_cur_region->read_only)
- rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(gv_cur_region));
- /* To write the LGTRIG logical jnl record, choose the first region that has journaling enabled */
- if (!jnl_format_done && JNL_WRITE_LOGICAL_RECS(csa))
- {
- assert(!gv_cur_region->read_only);
- JNLPOOL_INIT_IF_NEEDED(csa, csa->hdr, csa->nl); /* see previous usage for why it is needed */
- assert(dollar_tlevel);
- T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_TRIGLOADFAIL); /* needed to set update_trans TRUE on this region
- * even if NO db updates happen to ^#t nodes. */
- jnl_format(JNL_LGTRIG, NULL, &trigjrec, 0);
- jnl_format_done = TRUE;
- }
- SET_GVTARGET_TO_HASHT_GBL(csa);
- INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
- /* $get(^#t(GVN,"COUNT") */
- BUILD_HASHT_SUB_SUB_CURRKEY(trigvn, trigvn_len, LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT));
- if (!gvcst_get(&trigger_count))
- {
- util_out_print_gtmio("Trigger named !AD exists in the lookup table, "
- "but global ^!AD has no triggers",
- FLUSH, curr_name_len, curr_name, trigvn_len, trigvn);
- return TRIG_FAILURE;
- }
- /* kill the target trigger for GVN at index trig_indx */
- if (PUT_SUCCESS != (trigger_delete(trigvn, trigvn_len, &trigger_count, trig_indx)))
- {
- util_out_print_gtmio("Trigger named !AD exists in the lookup table, but was not deleted!",
- FLUSH, orig_name_len, trigger_name);
- } else
- {
- csa->incr_db_trigger_cycle = TRUE;
- if (dollar_ztrigger_invoked)
- { /* increment db_dztrigger_cycle so that next gvcst_put/gvcst_kill in this transaction,
- * on this region, will re-read triggers. See trigger_update.c for a comment on why
- * it is okay for db_dztrigger_cycle to be incremented more than once in the same
- * transaction
- */
- csa->db_dztrigger_cycle++;
- }
- trig_stats[STATS_DELETED]++;
- if (0 == trig_stats[STATS_ERROR])
- util_out_print_gtmio("Deleted trigger named '!AD' for global ^!AD",
- FLUSH, curr_name_len, curr_name, trigvn_len, trigvn);
- }
- RESTORE_TRIGGER_REGION_INFO(save_currkey);
- name_found = TRUE;
- }
- if (!wildcard)
- /* not a wild card, don't $order for the next match */
- break;
- op_gvorder(&mv_curr_nam);
- if (0 == mv_curr_nam.str.len)
- break;
- assert(mv_curr_nam.str.len < MAX_MIDENT_LEN);
- memcpy(curr_name, mv_curr_nam.str.addr, mv_curr_nam.str.len);
- curr_name_len = mv_curr_nam.str.len;
- if (0 != memcmp(curr_name, save_name, trigger_name_len))
- /* stop when gv_order returns a string that no longer starts save_name */
- break;
- } while (wildcard);
- if (!name_found)
+ if (wildcard)
{
- util_out_print_gtmio("Trigger named !AD does not exist", FLUSH, orig_name_len, trigger_name);
- if (wildcard)
- return TRIG_FAILURE;
- else
+ UTIL_PRINT_PREFIX_IF_NEEDED(first_gtmio, utilprefix, &utilprefixlen);
+ if (triggers_deleted)
{
- trig_stats[STATS_UNCHANGED]++;
- return TRIG_SUCCESS;
+ trig_stats[STATS_NOERROR_TRIGFILE]++;
+ util_out_print_gtmio("All existing triggers named !AD (count = !UL) now deleted",
+ FLUSH, orig_name_len, trigger_name, triggers_deleted);
+ } else
+ {
+ trig_stats[STATS_UNCHANGED_TRIGFILE]++;
+ util_out_print_gtmio("No matching triggers of the form !AD found for deletion",
+ FLUSH, orig_name_len, trigger_name);
}
+ } else if (triggers_deleted)
+ {
+ /* util_out_print_gtmio of "Deleted trigger named ..." already done so no need to do it again */
+ trig_stats[STATS_NOERROR_TRIGFILE]++;
} else
- return TRIG_SUCCESS;
+ { /* No names match. But treat it as a no-op (i.e. success). */
+ UTIL_PRINT_PREFIX_IF_NEEDED(first_gtmio, utilprefix, &utilprefixlen);
+ util_out_print_gtmio("Trigger named !AD does not exist", FLUSH, orig_name_len, trigger_name);
+ trig_stats[STATS_UNCHANGED_TRIGFILE]++;
+ }
+ return TRIG_SUCCESS;
}
int4 trigger_delete(char *trigvn, int trigvn_len, mval *trigger_count, int index)
@@ -540,15 +548,21 @@ int4 trigger_delete(char *trigvn, int trigvn_len, mval *trigger_count, int index
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 */
mv_val_ptr = &mv_val;
- MV_FORCE_MVAL(&trigger_index, index);
- count = MV_FORCE_INT(trigger_count);
+ MV_FORCE_UMVAL(&trigger_index, index);
+ count = MV_FORCE_UINT(trigger_count);
/* build up array of values - needed for comparison in hash stuff */
ptr1 = tmp_trig_str;
memcpy(ptr1, trigvn, trigvn_len);
ptr1 += trigvn_len;
*ptr1++ = '\0';
tmp_len = trigvn_len + 1;
+ /* Assert that BHASH and LHASH are not part of NUM_SUBS calculation (confirms the -2 done in the #define of NUM_SUBS) */
+ assert(BHASH_SUB == NUM_SUBS);
+ assert(LHASH_SUB == (NUM_SUBS + 1));
for (sub_indx = 0; sub_indx < NUM_SUBS; sub_indx++)
{
BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigger_index, trigger_subs[sub_indx],
@@ -556,6 +570,14 @@ int4 trigger_delete(char *trigvn, int trigvn_len, mval *trigger_count, int index
trig_len = gvcst_get(&trigger_value) ? trigger_value.str.len : 0;
if (0 == trig_len)
{
+ if (((TRIGNAME_SUB == sub_indx) || (CMD_SUB == sub_indx) || (CHSET_SUB == sub_indx)))
+ { /* CMD, NAME and CHSET cannot be zero length */
+ 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(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn,
+ trigvn_len, trigvn, STRLEN(trigger_subs[sub_indx]), trigger_subs[sub_indx]);
+ }
tt_val[sub_indx] = NULL;
tt_val_len[sub_indx] = 0;
continue;
@@ -585,21 +607,23 @@ int4 trigger_delete(char *trigvn, int trigvn_len, mval *trigger_count, int index
/* Get trigger name, set hash value, and kill hash values from trigger before we delete it.
* The values will be used in clean ups associated with the deletion
*/
- /* $get(^#t(GVN,trigger_index,"LHASH") for deletion in cleanup_trigger_hash */
+ /* $get(^#t(GVN,trigger_index,"LHASH") for deletion in cleanup_trigger_hash */
BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigger_index, trigger_subs[LHASH_SUB],
STRLEN(trigger_subs[LHASH_SUB]));
if (gvcst_get(mv_val_ptr))
- kill_hash.hash_code = (uint4)MV_FORCE_INT(mv_val_ptr);
- else {
+ kill_hash.hash_code = (uint4)MV_FORCE_UINT(mv_val_ptr);
+ else
+ {
util_out_print_gtmio("The LHASH for global ^!AD does not exist", FLUSH, trigvn_len, trigvn);
kill_hash.hash_code = 0;
}
- /* $get(^#t(GVN,trigger_index,"BHASH") for deletion in cleanup_trigger_hash */
+ /* $get(^#t(GVN,trigger_index,"BHASH") for deletion in cleanup_trigger_hash */
BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigger_index, trigger_subs[BHASH_SUB],
STRLEN(trigger_subs[BHASH_SUB]));
if (gvcst_get(mv_val_ptr))
- set_hash.hash_code = (uint4)MV_FORCE_INT(mv_val_ptr);
- else {
+ set_hash.hash_code = (uint4)MV_FORCE_UINT(mv_val_ptr);
+ else
+ {
util_out_print_gtmio("The BHASH for global ^!AD does not exist", FLUSH, trigvn_len, trigvn);
set_hash.hash_code = 0;
}
@@ -615,7 +639,7 @@ int4 trigger_delete(char *trigvn, int trigvn_len, mval *trigger_count, int index
BUILD_HASHT_SUB_SUB_CURRKEY(trigvn, trigvn_len, LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT));
gvcst_kill(TRUE);
cleanup_trigger_name(trigvn, trigvn_len, trig_name, trig_name_len);
- cleanup_trigger_hash(trigvn, trigvn_len, tt_val, tt_val_len, &set_hash, &kill_hash, TRUE, 0);
+ cleanup_trigger_hash(trigvn, trigvn_len, tt_val, tt_val_len, &set_hash, &kill_hash, TRUE, index);
} else
{
cleanup_trigger_hash(trigvn, trigvn_len, tt_val, tt_val_len, &set_hash, &kill_hash, TRUE, index);
@@ -642,7 +666,7 @@ int4 trigger_delete(char *trigvn, int trigvn_len, mval *trigger_count, int index
trigger_subs[sub_indx], STRLEN(trigger_subs[sub_indx]), trigger_value, result);
assert(PUT_SUCCESS == result);
} else if (XECUTE_SUB == sub_indx)
- { /* multi line trigger broken up because it exceeds record size */
+ { /* multi line trigger broken up because it exceeds record size */
for (xecute_idx = 0; ; xecute_idx++)
{
i2mval(&xecute_index, xecute_idx);
@@ -663,13 +687,10 @@ int4 trigger_delete(char *trigvn, int trigvn_len, mval *trigger_count, int index
{ /* CMD, NAME and CHSET cannot be zero length */
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(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD,
- 6, trigvn_len, trigvn, trigvn_len, trigvn,
- STRLEN(trigger_subs[sub_indx]), trigger_subs[sub_indx]);
- }
+ assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
+ rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD,
+ 6, trigvn_len, trigvn, trigvn_len, trigvn,
+ STRLEN(trigger_subs[sub_indx]), trigger_subs[sub_indx]);
}
/* OPTIONS, PIECES and DELIM can be zero */
trig_len = 0;
@@ -691,19 +712,19 @@ int4 trigger_delete(char *trigvn, int trigvn_len, mval *trigger_count, int index
STRLEN(trigger_subs[LHASH_SUB]));
if (!gvcst_get(mv_val_ptr))
return PUT_SUCCESS;
- kill_hash.hash_code = (uint4)MV_FORCE_INT(mv_val_ptr);
+ kill_hash.hash_code = (uint4)MV_FORCE_UINT(mv_val_ptr);
/* $get(^#t(GVN,trigger_count,"BHASH") for update_trigger_hash_value */
BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, *trigger_count, trigger_subs[BHASH_SUB],
STRLEN(trigger_subs[BHASH_SUB]));
if (!gvcst_get(mv_val_ptr))
return PUT_SUCCESS;
- set_hash.hash_code = (uint4)MV_FORCE_INT(mv_val_ptr);
+ set_hash.hash_code = (uint4)MV_FORCE_UINT(mv_val_ptr);
/* update hash values from above */
if (VAL_TOO_LONG == (retval = update_trigger_hash_value(trigvn, trigvn_len, tt_val, tt_val_len,
&set_hash, &kill_hash, count, index)))
return VAL_TOO_LONG;
/* fix the value ^#t("#TNAME",^#t(GVN,index,"#TRIGNAME")) to point to the correct "index" */
- if (VAL_TOO_LONG == (retval = update_trigger_name_value(trigvn_len, tt_val[TRIGNAME_SUB],
+ if (VAL_TOO_LONG == (retval = update_trigger_name_value(tt_val[TRIGNAME_SUB],
tt_val_len[TRIGNAME_SUB], index)))
return VAL_TOO_LONG;
/* kill ^#t(GVN,COUNT) which was just shifted to trigger_index */
@@ -712,158 +733,125 @@ int4 trigger_delete(char *trigvn, int trigvn_len, mval *trigger_count, int index
}
/* Update #COUNT */
count--;
- MV_FORCE_MVAL(trigger_count, count);
+ MV_FORCE_UMVAL(trigger_count, count);
SET_TRIGGER_GLOBAL_SUB_SUB_MVAL(trigvn, trigvn_len, LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT), *trigger_count,
result);
assert(PUT_SUCCESS == result); /* Size of count can only get shorter or stay the same */
}
- trigger_incr_cycle(trigvn, trigvn_len);
return PUT_SUCCESS;
}
-void trigger_delete_all(char *trigger_rec, uint4 len)
+void trigger_delete_all(char *trigger_rec, uint4 len, uint4 *trig_stats)
{
int count;
char count_str[MAX_DIGITS_IN_INT + 1];
sgmnt_addrs *csa;
mval curr_gbl_name;
int cycle;
- gv_namehead *gvt;
mval *mv_count_ptr;
mval *mv_cycle_ptr;
mval mv_indx;
- gd_region *reg;
- int reg_indx;
+ gd_region *reg, *reg_top;
int4 result;
- gd_region *save_gv_cur_region;
- gv_namehead *save_gv_target;
- sgm_info *save_sgm_info_ptr;
+ gd_region *lgtrig_reg;
int trig_indx;
mval trigger_cycle;
mval trigger_count;
mval val;
+ boolean_t this_db_updated;
+ uint4 triggers_deleted;
mval trigjrec;
boolean_t jnl_format_done;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
assert(0 < dollar_tlevel);
- /* Before we delete any triggers, verify that none of the triggers have been fired in this transaction. If they have,
- * this creates an un-commitable transaction that will end in a TPFAIL error. Since that error indicates database
- * damage, we'd rather detect this avoidable condition and give a descriptive error instead (TRIGMODINTP).
- */
- for (gvt = gv_target_list; NULL != gvt; gvt = gvt->next_gvnh)
- {
- if (gvt->trig_local_tn == local_tn)
- rts_error_csa(CSA_ARG(gvt->gd_csa) VARLSTCNT(1) ERR_TRIGMODINTP);
- }
- SWITCH_TO_DEFAULT_REGION;
- if (gv_cur_region->read_only)
- rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(gv_cur_region));
- INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
jnl_format_done = FALSE;
+ lgtrig_reg = NULL;
trigjrec.mvtype = MV_STR;
trigjrec.str.len = len;
trigjrec.str.addr = trigger_rec;
- if (0 != gv_target->root)
+ triggers_deleted = 0;
+ for (reg = gd_header->regions, reg_top = reg + gd_header->n_regions; reg < reg_top; reg++)
{
+ GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(reg);
csa = cs_addrs;
- /* To write the LGTRIG logical jnl record, choose the first region that has journaling enabled */
- if (!jnl_format_done && JNL_WRITE_LOGICAL_RECS(csa))
- {
- JNLPOOL_INIT_IF_NEEDED(csa, csa->hdr, csa->nl); /* see previous usage for comment on why it is needed */
- assert(dollar_tlevel);
- T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_TRIGLOADFAIL); /* needed to set update_trans TRUE on this region
- * even if NO db updates happen to ^#t nodes. */
- jnl_format(JNL_LGTRIG, NULL, &trigjrec, 0);
- jnl_format_done = TRUE;
- }
- /* kill ^#t("#TRHASH") */
- BUILD_HASHT_SUB_CURRKEY(LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH));
- if (0 != gvcst_data())
- gvcst_kill(TRUE);
+ if (NULL == csa) /* not BG or MM access method */
+ continue;
+ /* gv_target now points to ^#t in region "reg" */
+ /* To write the LGTRIG logical jnl record, choose some region that has journaling enabled */
+ if (!reg->read_only && !jnl_format_done && JNL_WRITE_LOGICAL_RECS(csa))
+ lgtrig_reg = reg;
+ if (!gv_target->root)
+ continue;
/* kill ^#t("#TNAME") */
BUILD_HASHT_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME));
if (0 != gvcst_data())
+ { /* Issue error if we dont have permissions to touch ^#t global */
+ if (reg->read_only)
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(reg));
gvcst_kill(TRUE);
- }
- for (reg_indx = 0, reg = gd_header->regions; reg_indx < gd_header->n_regions; reg_indx++, reg++)
- {
- if (!reg->open)
- gv_init_reg(reg);
- gv_cur_region = reg;
- change_reg();
- csa = cs_addrs;
- /* To write the LGTRIG logical jnl record, choose the first region that has journaling enabled */
- if (!reg->read_only && !jnl_format_done && JNL_WRITE_LOGICAL_RECS(csa))
- {
- JNLPOOL_INIT_IF_NEEDED(csa, csa->hdr, csa->nl); /* see previous usage for comment on why it is needed */
- assert(dollar_tlevel);
- T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_TRIGLOADFAIL); /* needed to set update_trans TRUE on this region
- * even if NO db updates happen to ^#t nodes. */
- jnl_format(JNL_LGTRIG, NULL, &trigjrec, 0);
- jnl_format_done = TRUE;
}
- SET_GVTARGET_TO_HASHT_GBL(csa);
- INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
- /* There might not be any ^#t in this region, so check */
- if (0 != gv_target->root)
- { /* Give error on region only if it has #t global indicating the presence
- * of triggers.
- */
- if (reg->read_only)
- rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, REG_LEN_STR(reg));
- /* Kill all descendents of ^#t(trigvn, indx) where trigvn is any global with a trigger,
- * but skip the "#XYZ" entries. setup ^#t(trigvn,"$") as the PREV key for op_gvorder
- */
- BUILD_HASHT_SUB_CURRKEY(LITERAL_MAXHASHVAL, STRLEN(LITERAL_MAXHASHVAL));
- TREF(gv_last_subsc_null) = FALSE; /* We know its not null, but prior state is unreliable */
- while (TRUE)
+ /* Kill all descendents of ^#t(trigvn, ...) where trigvn is any global with a trigger,
+ * but skip the ^#t("#...",...) entries. Setup ^#t("$") as the key for op_gvorder
+ */
+ BUILD_HASHT_SUB_CURRKEY(LITERAL_MAXHASHVAL, STRLEN(LITERAL_MAXHASHVAL));
+ TREF(gv_last_subsc_null) = FALSE; /* We know its not null, but prior state is unreliable */
+ this_db_updated = FALSE;
+ while (TRUE)
+ {
+ op_gvorder(&curr_gbl_name);
+ /* quit:$length(curr_gbl_name)=0 */
+ if (0 == curr_gbl_name.str.len)
+ break;
+ /* $get(^#t(curr_gbl_name,#COUNT)) */
+ BUILD_HASHT_SUB_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len,
+ LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT));
+ if (gvcst_get(&trigger_count))
{
- op_gvorder(&curr_gbl_name);
- /* quit:$length(curr_gbl_name)=0 */
- if (0 == curr_gbl_name.str.len)
- break;
- /* $get(^#t(curr_gbl_name,#COUNT)) */
- BUILD_HASHT_SUB_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len,
- LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT));
- if (gvcst_get(&trigger_count))
- {
- mv_count_ptr = &trigger_count;
- count = MV_FORCE_INT(mv_count_ptr);
- /* $get(^#t(curr_gbl_name,#CYCLE)) */
- BUILD_HASHT_SUB_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len,
- LITERAL_HASHCYCLE, STRLEN(LITERAL_HASHCYCLE));
- if (!gvcst_get(&trigger_cycle))
- { /* Found #COUNT, there must be #CYCLE */
- 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(csa) VARLSTCNT(12) ERR_TRIGDEFBAD, 6,
- curr_gbl_name.str.len, curr_gbl_name.str.addr,
- curr_gbl_name.str.len, curr_gbl_name.str.addr,
- LEN_AND_LIT("\"#CYCLE\""),
- ERR_TEXT, 2,
- RTS_ERROR_TEXT("#CYCLE field is missing"));
- }
- }
- mv_cycle_ptr = &trigger_cycle;
- cycle = MV_FORCE_INT(mv_cycle_ptr);
- /* kill ^#t(curr_gbl_name) */
- BUILD_HASHT_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len);
- gvcst_kill(TRUE);
- cycle++;
- MV_FORCE_MVAL(&trigger_cycle, cycle);
- /* set ^#t(curr_gbl_name,#CYCLE)=trigger_cycle */
- SET_TRIGGER_GLOBAL_SUB_SUB_MVAL(curr_gbl_name.str.addr, curr_gbl_name.str.len,
- LITERAL_HASHCYCLE, STRLEN(LITERAL_HASHCYCLE), trigger_cycle, result);
- assert(PUT_SUCCESS == result);
- } /* else there is no #COUNT, then no triggers, leave #CYCLE alone */
- /* get ready for op_gvorder() call for next trigger under ^#t */
- BUILD_HASHT_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len);
- }
+ /* Now that we know there is something to kill, check if we have permissions to touch ^#t global */
+ if (reg->read_only)
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(reg));
+ mv_count_ptr = &trigger_count;
+ count = MV_FORCE_UINT(mv_count_ptr);
+ /* $get(^#t(curr_gbl_name,#CYCLE)) */
+ BUILD_HASHT_SUB_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len,
+ LITERAL_HASHCYCLE, STRLEN(LITERAL_HASHCYCLE));
+ if (!gvcst_get(&trigger_cycle))
+ { /* Found #COUNT, there must be #CYCLE */
+ 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(csa) VARLSTCNT(12) ERR_TRIGDEFBAD, 6,
+ curr_gbl_name.str.len, curr_gbl_name.str.addr,
+ curr_gbl_name.str.len, curr_gbl_name.str.addr, LEN_AND_LIT("\"#CYCLE\""),
+ ERR_TEXT, 2, RTS_ERROR_TEXT("#CYCLE field is missing"));
+ }
+ mv_cycle_ptr = &trigger_cycle;
+ cycle = MV_FORCE_UINT(mv_cycle_ptr);
+ if (!jnl_format_done && JNL_WRITE_LOGICAL_RECS(csa))
+ {
+ jnl_format(JNL_LGTRIG, NULL, &trigjrec, 0);
+ jnl_format_done = TRUE;
+ }
+ /* kill ^#t(curr_gbl_name) */
+ BUILD_HASHT_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len);
+ gvcst_kill(TRUE);
+ /* Note : ^#t(curr_gbl_name,"#TRHASH") is also killed as part of the above */
+ cycle++;
+ MV_FORCE_MVAL(&trigger_cycle, cycle);
+ /* set ^#t(curr_gbl_name,#CYCLE)=trigger_cycle */
+ SET_TRIGGER_GLOBAL_SUB_SUB_MVAL(curr_gbl_name.str.addr, curr_gbl_name.str.len,
+ LITERAL_HASHCYCLE, STRLEN(LITERAL_HASHCYCLE), trigger_cycle, result);
+ assert(PUT_SUCCESS == result);
+ this_db_updated = TRUE;
+ triggers_deleted += count;
+ } /* else there is no #COUNT, then no triggers, leave #CYCLE alone */
+ /* get ready for op_gvorder() call for next trigger under ^#t */
+ BUILD_HASHT_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len);
+ }
+ if (this_db_updated)
+ {
csa->incr_db_trigger_cycle = TRUE;
if (dollar_ztrigger_invoked)
{ /* increment db_dztrigger_cycle so that next gvcst_put/gvcst_kill in this transaction,
@@ -874,6 +862,28 @@ void trigger_delete_all(char *trigger_rec, uint4 len)
}
}
}
- util_out_print_gtmio("All existing triggers deleted", FLUSH);
+ if (!jnl_format_done && (NULL != lgtrig_reg))
+ { /* There was no journaled region that had a ^#t update, but found at least one journaled region
+ * so write a LGTRIG logical jnl record there.
+ */
+ GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(lgtrig_reg);
+ csa = cs_addrs;
+ JNLPOOL_INIT_IF_NEEDED(csa, csa->hdr, csa->nl); /* see previous usage for comment on why it is needed */
+ assert(dollar_tlevel);
+ T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_TRIGLOADFAIL); /* needed to set update_trans TRUE on this region
+ * even if NO db updates happen to ^#t nodes. */
+ jnl_format(JNL_LGTRIG, NULL, &trigjrec, 0);
+ jnl_format_done = TRUE;
+ }
+ if (triggers_deleted)
+ {
+ util_out_print_gtmio("All existing triggers (count = !UL) deleted", FLUSH, triggers_deleted);
+ trig_stats[STATS_DELETED] += triggers_deleted;
+ trig_stats[STATS_NOERROR_TRIGFILE]++;
+ } else
+ {
+ util_out_print_gtmio("No matching triggers found for deletion", FLUSH);
+ trig_stats[STATS_UNCHANGED_TRIGFILE]++;
+ }
}
#endif /* GTM_TRIGGER */
diff --git a/sr_unix/trigger_delete_protos.h b/sr_unix/trigger_delete_protos.h
index 61c7934..98a0105 100644
--- a/sr_unix/trigger_delete_protos.h
+++ b/sr_unix/trigger_delete_protos.h
@@ -12,15 +12,15 @@
#ifndef MU_TRIG_DELETE_PROTOS_H_INCLUDED
#define MU_TRIG_DELETE_PROTOS_H_INCLUDED
-STATICFNDCL void cleanup_trigger_hash(char *trigvn, int trigvn_len, char **values, uint4 *value_len, stringkey *set_hash,
+void cleanup_trigger_hash(char *trigvn, int trigvn_len, char **values, uint4 *value_len, stringkey *set_hash,
stringkey *kill_hash, boolean_t del_kill_hash, int match_index);
-STATICFNDCL void cleanup_trigger_name(char *trigvn, int trigvn_len, char *trigger_name, int trigger_name_len);
+void cleanup_trigger_name(char *trigvn, int trigvn_len, char *trigger_name, int trigger_name_len);
STATICFNDCL int4 update_trigger_hash_value(char *trigvn, int trigvn_len, char **values, uint4 *value_len, stringkey *set_hash,
stringkey *kill_hash, int old_trig_index, int new_trig_index);
-STATICFNDCL int4 update_trigger_name_value(int trigvn_len, char *trig_name, int trig_name_len, int new_trig_index);
+STATICFNDCL int4 update_trigger_name_value(char *trig_name, int trig_name_len, int new_trig_index);
boolean_t trigger_delete_name(char *trigger_name, uint4 trigger_name_len, uint4 *trig_stats);
int4 trigger_delete(char *trigvn, int trigvn_len, mval *trigger_count, int index);
-void trigger_delete_all(char *trigger_rec, uint4 len);
+void trigger_delete_all(char *trigger_rec, uint4 len, uint4 *trig_stats);
#endif
diff --git a/sr_unix/trigger_fill_xecute_buffer.c b/sr_unix/trigger_fill_xecute_buffer.c
index 2541dd5..182789e 100644
--- a/sr_unix/trigger_fill_xecute_buffer.c
+++ b/sr_unix/trigger_fill_xecute_buffer.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2013 Fidelity Information Services, Inc *
+ * Copyright 2010, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -23,7 +23,7 @@
#include "mv_stent.h" /* for COPY_SUBS_TO_GVCURRKEY macro */
#include "gvsub2str.h" /* for COPY_SUBS_TO_GVCURRKEY */
#include "format_targ_key.h" /* for COPY_SUBS_TO_GVCURRKEY */
-#include "targ_alloc.h" /* for SET_GVTARGET_TO_HASHT_GBL & SWITCH_TO_DEFAULT_REGION */
+#include "targ_alloc.h" /* for SET_GVTARGET_TO_HASHT_GBL */
#include "filestruct.h" /* for INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED (FILE_INFO) */
#include "mvalconv.h"
#include "gdscc.h" /* needed for tp.h */
@@ -42,6 +42,7 @@
#include "gtmimagename.h"
#include "trigger_fill_xecute_buffer.h"
#include "trigger_gbl_fill_xecute_buffer.h"
+#include "gtm_trigger_trc.h"
GBLREF sgmnt_data_ptr_t cs_data;
GBLREF sgmnt_addrs *cs_addrs;
@@ -55,8 +56,6 @@ GBLREF int4 tstart_trigger_depth;
GBLREF int4 gtm_trigger_depth;
GBLREF tp_frame *tp_pointer;
-LITREF mval literal_hasht;
-
error_def(ERR_TRIGNAMBAD);
error_def(ERR_TPRETRY);
@@ -112,10 +111,12 @@ int trigger_fill_xecute_buffer(gv_trigger_t *trigdsc)
|| (tp_pointer->implicit_tstart && tp_pointer->implicit_trigger
&& (tstart_trigger_depth != gtm_trigger_depth))) /* Case 3 */
{ /* Test for Case 3/4 where we get to do very little: */
+ DBGTRIGR((stderr, "trigger_fill_xecute_buffer: Case 2/3\n"));
assert((!tp_pointer->implicit_trigger) || (0 < gtm_trigger_depth));
trigger_fill_xecute_buffer_read_trigger_source(trigdsc);
} else
{ /* Test for Case 1 where we only need a condition handler */
+ DBGTRIGR((stderr, "trigger_fill_xecute_buffer: Case 1\n"));
assert(tp_pointer->implicit_tstart && tp_pointer->implicit_trigger);
assert(tstart_trigger_depth == gtm_trigger_depth);
ESTABLISH_RET(trigger_fill_xecute_buffer_ch, SIGNAL);
@@ -151,6 +152,8 @@ STATICFNDEF void trigger_fill_xecute_buffer_read_trigger_source(gv_trigger_t *tr
gvt_trigger = trigdsc->gvt_trigger; /* We now know our base block now */
index = trigdsc - gvt_trigger->gv_trig_array + 1; /* We now know our trigger index value */
i2mval(&trig_index, index);
+ DBGTRIGR((stderr, "trigger_fill_xecute_buffer_read_trigger_source: entry $tlevel:%d\tindex:%d of %d\n",
+ dollar_tlevel, index, gvt_trigger->num_gv_triggers));
gvt = gv_target = gvt_trigger->gv_target; /* gv_target contains global name */
gbl.addr = gvt->gvname.var_name.addr;
gbl.len = gvt->gvname.var_name.len;
@@ -175,6 +178,7 @@ STATICFNDEF void trigger_fill_xecute_buffer_read_trigger_source(gv_trigger_t *tr
* updater on the secondary so we dont expect it to see any concurrent trigger changes
* Assert accordingly.
*/
+ DBGTRIGR((stderr, "trigger_fill_xecute_buffer_read_trigger_source: stale trigger view\n"));
assert(CDB_STAGNATE > t_tries);
assert(IS_GTM_IMAGE);
t_retry(cdb_sc_triggermod);
diff --git a/sr_unix/trigger_gbl_fill_xecute_buffer.c b/sr_unix/trigger_gbl_fill_xecute_buffer.c
index b120082..e719300 100644
--- a/sr_unix/trigger_gbl_fill_xecute_buffer.c
+++ b/sr_unix/trigger_gbl_fill_xecute_buffer.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2013 Fidelity Information Services, Inc *
+ * Copyright 2010, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -24,11 +24,13 @@
#include "op.h"
#include "trigger.h"
#include "trigger_gbl_fill_xecute_buffer.h"
+#include "gtm_trigger_trc.h"
#include "mvalconv.h"
#include "memcoherency.h"
#include "t_retry.h"
#include "gtmimagename.h"
#include "filestruct.h" /* for FILE_INFO, needed by REG2CSA */
+#include "have_crit.h"
LITREF mval literal_ten;
@@ -47,6 +49,8 @@ GBLREF gv_key *gv_currkey;
GBLREF uint4 dollar_tlevel;
GBLREF unsigned int t_tries;
+LITREF char *trigger_subs[];
+
STATICDEF char *xecute_buff;
STATICFNDCL CONDITION_HANDLER(trigger_gbl_fill_xecute_buffer_ch);
@@ -66,7 +70,6 @@ STATICFNDEF CONDITION_HANDLER(trigger_gbl_fill_xecute_buffer_ch)
char *trigger_gbl_fill_xecute_buffer(char *trigvn, int trigvn_len, mval *trig_index, mval *first_rec, int4 *xecute_len)
{
mval data_val;
- boolean_t have_value;
mval index, key_val, *val_ptr;
int4 len, xecute_buff_len;
int4 num;
@@ -80,32 +83,41 @@ char *trigger_gbl_fill_xecute_buffer(char *trigvn, int trigvn_len, mval *trig_in
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
- /* assert(0 < dollar_tlevel); Too be added later when it stops breaking MUPIP SELECT & $ZTRIGGER("SELECT"..) */
+ assert(0 < dollar_tlevel); /* Too be added later when it stops breaking MUPIP SELECT & $ZTRIGGER("SELECT"..) */
xecute_buff = NULL;
ESTABLISH_RET(trigger_gbl_fill_xecute_buffer_ch, NULL);
index = *trig_index;
+ DBGTRIGR((stderr, "trigger_gbl_fill_xecute_buffer: entry $tlevel:%d\tindex:%d\t:crit:%d\tkv:%d\n",
+ dollar_tlevel, mval2i(&index), have_crit(CRIT_HAVE_ANY_REG), key_val.str.len));
if (NULL != first_rec)
{
+ DBGTRIGR((stderr, "trigger_gbl_fill_xecute_buffer: NULL != first_rec\n"));
xecute_buff_len = first_rec->str.len;
assert(MAX_XECUTE_LEN >= xecute_buff_len);
xecute_buff = malloc(xecute_buff_len);
memcpy(xecute_buff, first_rec->str.addr, xecute_buff_len);
} else
{ /* First check for a single record xecute string */
- BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, index, LITERAL_XECUTE, LITERAL_XECUTE_LEN);
- if (gvcst_get(&data_val))
+ DBGTRIGR((stderr, "trigger_gbl_fill_xecute_buffer: First check for a single record xecute string\n"));
+ BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, index,
+ trigger_subs[XECUTE_SUB], STRLEN(trigger_subs[XECUTE_SUB]));
+ if (gvcst_get(&key_val))
{
- xecute_buff_len = data_val.str.len;
+ xecute_buff_len = key_val.str.len;
assert(MAX_XECUTE_LEN >= xecute_buff_len);
xecute_buff = malloc(xecute_buff_len);
- memcpy(xecute_buff, data_val.str.addr, xecute_buff_len);
+ memcpy(xecute_buff, key_val.str.addr, xecute_buff_len);
*xecute_len = xecute_buff_len;
+ DBGTRIGR((stderr, "trigger_gbl_fill_xecute_buffer: Found a single record xecute string of %d bytes\n",
+ xecute_buff_len));
REVERT;
return xecute_buff;
} else
{ /* No single line trigger exists. See if multi-line trigger exists. The form is ^#t(gbl,indx,XECUTE,n)
* so can be easily tested for with $DATA().
*/
+ DBGTRIGR((stderr, "trigger_gbl_fill_xecute_buffer: No single record xecute string(%d), try for multiline\n",
+ key_val.str.len));
op_gvdata(&data_val);
if ((literal_ten.m[0] != data_val.m[0]) || (literal_ten.m[1] != data_val.m[1]))
{ /* The process' view of the triggers is likely stale. Restart to be safe.
@@ -114,8 +126,8 @@ char *trigger_gbl_fill_xecute_buffer(char *trigvn, int trigvn_len, mval *trig_in
* updater on the secondary so we dont expect it to see any concurrent trigger changes
* Assert accordingly. Note similar asserts occur in t_end.c and tp_tend.c.
*/
- assert(CDB_STAGNATE > t_tries);
assert(IS_GTM_IMAGE);
+ DBGTRIGR((stderr, "trigger_gbl_fill_xecute_buffer: multiline not found, retry\n"));
/* Assert that the cycle has changed but in order to properly do the assert, we need a memory
* barrier since cs_data->db_trigger_cycle could be stale in our cache.
*/
@@ -124,16 +136,26 @@ char *trigger_gbl_fill_xecute_buffer(char *trigvn, int trigvn_len, mval *trig_in
DEBUG_ONLY(gvt_cycle = gv_target->db_trigger_cycle);
DEBUG_ONLY(csd_cycle = cs_data->db_trigger_cycle);
assert(csd_cycle > gvt_cycle);
- t_retry(cdb_sc_triggermod);
+ if (CDB_STAGNATE > t_tries)
+ t_retry(cdb_sc_triggermod);
+ assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
+ trgindx = mval2i(&index);
+ SET_PARAM_STRING(util_buff, util_len, trgindx, ",\"XECUTE\"");
+ rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn,
+ trigvn_len, trigvn, util_len, util_buff);
}
}
/* Multi-line triggers exist */
num = 0;
i2mval(&xecute_index, num);
- BUILD_HASHT_SUB_MSUB_SUB_MSUB_CURRKEY(trigvn, trigvn_len, index, LITERAL_XECUTE, LITERAL_XECUTE_LEN, xecute_index);
+ BUILD_HASHT_SUB_MSUB_SUB_MSUB_CURRKEY(trigvn, trigvn_len, index,
+ trigger_subs[XECUTE_SUB], STRLEN(trigger_subs[XECUTE_SUB]), xecute_index);
if (!gvcst_get(&key_val))
- { /* There has to be an XECUTE string */
- assert(FALSE);
+ { /* There has to be an XECUTE string or else it is a retry situation (due to concurrent updates) */
+ DBGTRIGR((stderr, "trigger_gbl_fill_xecute_buffer: problem getting multiline record count, retry\n"));
+ if (CDB_STAGNATE > t_tries)
+ t_retry(cdb_sc_triggermod);
+ assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
trgindx = mval2i(&index);
SET_PARAM_STRING(util_buff, util_len, trgindx, ",\"XECUTE\"");
rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn,
@@ -147,14 +169,19 @@ char *trigger_gbl_fill_xecute_buffer(char *trigvn, int trigvn_len, mval *trig_in
while (len < xecute_buff_len)
{
i2mval(&xecute_index, ++num);
- BUILD_HASHT_SUB_MSUB_SUB_MSUB_CURRKEY(trigvn, trigvn_len, index, LITERAL_XECUTE, LITERAL_XECUTE_LEN,
- xecute_index);
+ BUILD_HASHT_SUB_MSUB_SUB_MSUB_CURRKEY(trigvn, trigvn_len, index,
+ trigger_subs[XECUTE_SUB], STRLEN(trigger_subs[XECUTE_SUB]), xecute_index);
if (!gvcst_get(&key_val))
break;
if (xecute_buff_len < (len + key_val.str.len))
- { /* The DB string total is longer than the length stored at index 0 -- something is wrong */
+ { /* The DB string total is longer than the length stored at index 0 -- something is wrong.
+ * Most likely a retry necessary due to concurrent changes.
+ */
+ DBGTRIGR((stderr, "trigger_gbl_fill_xecute_buffer: problem getting multiline component, retry\n"));
free(xecute_buff);
- assert(FALSE);
+ if (CDB_STAGNATE > t_tries)
+ t_retry(cdb_sc_triggermod);
+ assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
SET_PARAM_STRING(util_buff, util_len, num, ",\"XECUTE\"");
rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn,
trigvn_len, trigvn, util_len, util_buff);
diff --git a/sr_unix/trigger_parse.c b/sr_unix/trigger_parse.c
index e5be210..b742197 100644
--- a/sr_unix/trigger_parse.c
+++ b/sr_unix/trigger_parse.c
@@ -530,12 +530,21 @@ boolean_t check_trigger_name(char *name_str, uint4 *name_len)
*/
lcl_name_len = *name_len;
if (MAX_USER_TRIGNAME_LEN < lcl_name_len)
+ {
+ util_out_print_gtmio("Trigger name length [!UL] exceeds maximum supported length of [!UL]",
+ FLUSH, lcl_name_len, MAX_USER_TRIGNAME_LEN);
return FALSE;
+ }
ptr = (unsigned char *)name_str;
if (('%' != *ptr) && !ISALPHA_ASCII(*ptr))
+ {
+ util_out_print_gtmio("Trigger name does not begin with an ascii alphabet or %", FLUSH);
return FALSE;
+ }
for (len = lcl_name_len - 1, ptr++; (0 < len) && ISALNUM_ASCII(*ptr); ptr++, len--)
;
+ if (len)
+ util_out_print_gtmio("Trigger name has non-alphanumeric character", FLUSH);
return (0 == len);
}
@@ -592,7 +601,7 @@ STATICFNDEF boolean_t process_options(char *option_str, uint4 option_len, boolea
}
break;
default:
- assertpro(FALSE); /* Parsing should have found invalid command */
+ assert(FALSE); /* Parsing should have found invalid command */
break;
}
} while (ptr = strtok(NULL, ","));
@@ -1231,7 +1240,7 @@ boolean_t trigger_parse(char *input, uint4 input_len, char *trigvn, char **value
if ((XTENDED_STOP_LEN != input_len) || (0 != memcmp(XTENDED_STOP, input, XTENDED_STOP_LEN)))
{
ptr1 = values[XECUTE_SUB] + value_len[XECUTE_SUB];
- if (0 < (max_output_len - input_len - 1))
+ if ((input_len + 1) < max_output_len)
{
memcpy(ptr1, input, input_len);
ptr1 += input_len;
@@ -1243,7 +1252,7 @@ boolean_t trigger_parse(char *input, uint4 input_len, char *trigvn, char **value
} else
{
*multi_line_xecute = FALSE;
- util_out_print_gtmio("Trigger definition too long", FLUSH);
+ util_out_print_gtmio("Error : Trigger definition too long", FLUSH);
return FALSE;
}
}
@@ -1251,7 +1260,7 @@ boolean_t trigger_parse(char *input, uint4 input_len, char *trigvn, char **value
if (!process_xecute(values[XECUTE_SUB], &value_len[XECUTE_SUB], TRUE))
{
*multi_line_xecute = FALSE;
- ERROR_MSG_RETURN("Error parsing XECUTE string: ", value_len[XECUTE_SUB], values[XECUTE_SUB]);
+ ERROR_MSG_RETURN("Error : Parsing XECUTE string: ", value_len[XECUTE_SUB], values[XECUTE_SUB]);
}
*multi_line_xecute = out_multi_line_xecute;
*max_len = max_output_len;
@@ -1261,20 +1270,20 @@ boolean_t trigger_parse(char *input, uint4 input_len, char *trigvn, char **value
len = (uint4)input_len;
if ('^' != *ptr1++)
{
- ERROR_MSG_RETURN("Missing global name:\n", input_len, input);
+ ERROR_MSG_RETURN("Error : Missing global name:\n", input_len, input);
}
ptr = ptr1;
len--;
if (('%' != *ptr1) && !ISALPHA_ASCII(*ptr1))
{
- ERROR_MSG_RETURN("Invalid global name:\n", input_len, input);
+ ERROR_MSG_RETURN("Error : Invalid global name:\n", input_len, input);
}
ptr1++;
while (ISALNUM_ASCII(*ptr1))
ptr1++;
if (('(' != *ptr1) && !ISSPACE_ASCII(*ptr1))
{
- ERROR_MSG_RETURN("Invalid global name:\n", input_len, input);
+ ERROR_MSG_RETURN("Error : Invalid global name:\n", input_len, input);
}
trigvn_len = (int)(ptr1 - ptr);
if (MAX_MIDENT_LEN < trigvn_len)
@@ -1299,7 +1308,7 @@ boolean_t trigger_parse(char *input, uint4 input_len, char *trigvn, char **value
len = 0;
if (0 > --max_output_len)
{
- util_out_print_gtmio("Trigger definition too long", FLUSH);
+ util_out_print_gtmio("Error : Trigger definition too long", FLUSH);
return TRIG_FAILURE;
}
values[GVSUBS_SUB][len] = '\0';
@@ -1313,7 +1322,7 @@ boolean_t trigger_parse(char *input, uint4 input_len, char *trigvn, char **value
cmd_ary = save_cmd_ary;
if (parse_ret)
{
- ERROR_MSG_RETURN("Parse error in input:\n", input_len, input);
+ ERROR_MSG_RETURN("Error : In parsing input:\n", input_len, input);
}
values[CMD_SUB] = values[GVSUBS_SUB] + value_len[GVSUBS_SUB] + 1;
if (CLI_PRESENT == cli_present("COMMANDS"))
@@ -1353,7 +1362,7 @@ boolean_t trigger_parse(char *input, uint4 input_len, char *trigvn, char **value
if (CLI_PRESENT == cli_present("COMMANDS.ZTKILL"))
{
if (found_kill)
- ERROR_MSG_RETURN("KILL and ZTKILL incompatible: ", value_len[CMD_SUB], values[CMD_SUB]);
+ ERROR_MSG_RETURN("Error : KILL and ZTKILL incompatible: ", value_len[CMD_SUB], values[CMD_SUB]);
ADD_COMMA_IF_NEEDED(count, ptr, max_output_len);
ADD_STRING(count, ptr, gvtr_cmd_mval[GVTR_CMDTYPE_ZTKILL].str.len,
gvtr_cmd_mval[GVTR_CMDTYPE_ZTKILL].str.addr, max_output_len);
@@ -1370,9 +1379,9 @@ boolean_t trigger_parse(char *input, uint4 input_len, char *trigvn, char **value
value_len[CMD_SUB] = 0;
UPDATE_TRIG_PTRS(values[CMD_SUB], values[DELIM_SUB], value_len[CMD_SUB], max_output_len);
GET_CLI_STR_AND_CHECK("DELIM", delim_present, max_output_len, process_delim, values[DELIM_SUB], value_len[DELIM_SUB],
- values[TRIGNAME_SUB], "Error parsing DELIM string: ");
+ values[TRIGNAME_SUB], "Error : Parsing DELIM string: ");
GET_CLI_STR_AND_CHECK("NAME", name_present, max_output_len, check_trigger_name, values[TRIGNAME_SUB],
- value_len[TRIGNAME_SUB], values[OPTIONS_SUB], "Error parsing NAME string: ");
+ value_len[TRIGNAME_SUB], values[OPTIONS_SUB], "Error : Parsing NAME string: ");
if (CLI_PRESENT == cli_present("OPTIONS"))
{
boolean_t isolation, noisolation, consistency, noconsistency;
@@ -1381,7 +1390,8 @@ boolean_t trigger_parse(char *input, uint4 input_len, char *trigvn, char **value
if (!process_options(values[OPTIONS_SUB], value_len[OPTIONS_SUB], &isolation, &noisolation, &consistency,
&noconsistency))
{
- ERROR_MSG_RETURN("Inconsistent values in OPTIONS string: ", value_len[OPTIONS_SUB], values[OPTIONS_SUB]);
+ ERROR_MSG_RETURN("Error : Inconsistent values in OPTIONS string: ",
+ value_len[OPTIONS_SUB], values[OPTIONS_SUB]);
}
count = 0;
ptr = values[OPTIONS_SUB];
@@ -1411,7 +1421,7 @@ boolean_t trigger_parse(char *input, uint4 input_len, char *trigvn, char **value
GET_CLI_STR_AND_CHECK("PIECES", pieces_present, max_output_len, process_pieces, values[PIECES_SUB], value_len[PIECES_SUB],
values[ZDELIM_SUB], "");
GET_CLI_STR_AND_CHECK("ZDELIM", zdelim_present, max_output_len, process_delim, values[ZDELIM_SUB], value_len[ZDELIM_SUB],
- values[XECUTE_SUB], "Error parsing ZDELIM string: ");
+ values[XECUTE_SUB], "Error : Parsing ZDELIM string: ");
/* Since process_xecute() does a test compile of the xecute string, it changes the parsing table from MUPIP TRIGGER
* to GT.M. To avoid problems with saving and restoring the parse state (which would have to be done with globals
* that are static in cli_parse.c), it is much easier to put process_xecute() last in the list of qualifiers to check -
@@ -1426,7 +1436,7 @@ boolean_t trigger_parse(char *input, uint4 input_len, char *trigvn, char **value
{
ptr = values[XECUTE_SUB];
len = value_len[XECUTE_SUB];
- ERROR_MSG_RETURN("Error parsing XECUTE string: ", len, ptr);
+ ERROR_MSG_RETURN("Error : Parsing XECUTE string: ", len, ptr);
}
} else
value_len[XECUTE_SUB] = 0;
@@ -1438,28 +1448,28 @@ boolean_t trigger_parse(char *input, uint4 input_len, char *trigvn, char **value
*ptr = '\0';
if (!xecute_present && !out_multi_line_xecute)
{
- ERROR_STR_RETURN("XECUTE value missing");
+ ERROR_STR_RETURN("Error: XECUTE value missing");
}
if (0 == value_len[CMD_SUB])
{
- ERROR_STR_RETURN("COMMANDS value missing");
+ ERROR_STR_RETURN("Error: COMMANDS value missing");
}
if (delim_present && zdelim_present)
{
- ERROR_STR_RETURN("Can't have both DELIM and ZDELIM in same entry");
+ ERROR_STR_RETURN("Error: Can't have both DELIM and ZDELIM in same entry");
}
if ((delim_present || zdelim_present) && !set_present)
{
- ERROR_STR_RETURN("DELIM and ZDELIM need a commands=SET");
+ ERROR_STR_RETURN("Error: DELIM and ZDELIM need a commands=SET");
}
if (pieces_present && (!delim_present && !zdelim_present))
{
- ERROR_STR_RETURN("PIECES need either DELIM or ZDELIM");
+ ERROR_STR_RETURN("Error: PIECES need either DELIM or ZDELIM");
}
if (MAX_HASH_INDEX_LEN < (trigvn_len + 1 + value_len[GVSUBS_SUB] + 1 + value_len[DELIM_SUB] + 1
+ value_len[ZDELIM_SUB] + 1 + value_len[XECUTE_SUB] + 1))
{
- ERROR_STR_RETURN("Entry too large to properly index");
+ ERROR_STR_RETURN("Error: Entry too large to properly index");
}
}
*multi_line_xecute = out_multi_line_xecute;
diff --git a/sr_unix/trigger_read_name_entry.c b/sr_unix/trigger_read_name_entry.c
deleted file mode 100644
index be21fcc..0000000
--- a/sr_unix/trigger_read_name_entry.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/****************************************************************
- * *
- * Copyright 2010, 2013 Fidelity Information Services, Inc *
- * *
- * This source code contains the intellectual property *
- * of its copyright holder(s), and is made available *
- * under a license. If you do not know the terms of *
- * the license, please stop and do not read further. *
- * *
- ****************************************************************/
-
-#include "mdef.h"
-
-#ifdef GTM_TRIGGER
-
-#include "gdsroot.h" /* for gdsfhead.h */
-#include "gdsbt.h" /* for gdsfhead.h */
-#include "gdsfhead.h"
-#include "gvcst_protos.h"
-#include <rtnhdr.h>
-#include "gv_trigger.h"
-#include "trigger.h"
-#include "trigger_read_name_entry.h"
-#include "mv_stent.h" /* for COPY_SUBS_TO_GVCURRKEY macro */
-#include "gvsub2str.h" /* for COPY_SUBS_TO_GVCURRKEY */
-#include "format_targ_key.h" /* for COPY_SUBS_TO_GVCURRKEY */
-#include "targ_alloc.h" /* for SET_GVTARGET_TO_HASHT_GBL & SWITCH_TO_DEFAULT_REGION */
-#include "gdscc.h" /* needed for tp.h */
-#include "gdskill.h" /* needed for tp.h */
-#include "buddy_list.h" /* needed for tp.h */
-#include "hashtab_int4.h" /* needed for tp.h */
-#include "filestruct.h" /* needed for jnl.h */
-#include "jnl.h" /* needed for tp.h */
-#include "tp.h" /* for sgm_info */
-
-GBLREF sgmnt_data_ptr_t cs_data;
-GBLREF gd_region *gv_cur_region;
-GBLREF gv_key *gv_currkey;
-GBLREF sgm_info *sgm_info_ptr;
-
-LITREF mval literal_hasht;
-
-boolean_t trigger_read_name_entry(mident *trig_name, mval *val)
-{
- gv_key save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
- gd_region *save_gv_cur_region;
- gv_namehead *save_gv_target;
- sgm_info *save_sgm_info_ptr;
- boolean_t status;
- DCL_THREADGBL_ACCESS;
-
- SETUP_THREADGBL_ACCESS;
- SAVE_TRIGGER_REGION_INFO(save_currkey);
- SWITCH_TO_DEFAULT_REGION;
- INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
- if (0 == gv_target->root)
- {
- RESTORE_TRIGGER_REGION_INFO(save_currkey);
- return FALSE;
- }
- BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trig_name->addr, trig_name->len - 1);
- status = gvcst_get(val);
- RESTORE_TRIGGER_REGION_INFO(save_currkey);
- return status;
-}
-#endif
diff --git a/sr_unix/trigger_read_name_entry.h b/sr_unix/trigger_read_name_entry.h
deleted file mode 100644
index 228b9b5..0000000
--- a/sr_unix/trigger_read_name_entry.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/****************************************************************
- * *
- * Copyright 2010 Fidelity Information Services, Inc *
- * *
- * This source code contains the intellectual property *
- * of its copyright holder(s), and is made available *
- * under a license. If you do not know the terms of *
- * the license, please stop and do not read further. *
- * *
- ****************************************************************/
-
-#ifndef TRIGGER_READ_NAME_ENTRY_H_INCLUDED
-#define TRIGGER_READ_NAME_ENTRY_H_INCLUDED
-
-boolean_t trigger_read_name_entry(mident *trig_name, mval *val);
-
-#endif
diff --git a/sr_unix/trigger_select.c b/sr_unix/trigger_select.c
index 43e6313..b2376ad 100644
--- a/sr_unix/trigger_select.c
+++ b/sr_unix/trigger_select.c
@@ -34,7 +34,7 @@
#include "trigger_user_name.h"
#include "change_reg.h"
#include "gvcst_protos.h"
-#include "op.h"
+#include "op.h" /* for op_tstart etc. */
#include "mupip_exit.h"
#include "zshow.h"
#include "util.h"
@@ -54,6 +54,8 @@
#include "gtmio.h"
#include "have_crit.h"
#include "hashtab_mname.h"
+#include "tp_frame.h"
+#include "tp_restart.h"
GBLREF sgmnt_addrs *cs_addrs;
GBLREF sgmnt_data_ptr_t cs_data;
@@ -66,8 +68,12 @@ GBLREF io_pair io_curr_device;
GBLREF io_pair io_std_device; /* standard device */
GBLREF sgm_info *sgm_info_ptr;
GBLREF int (*op_open_ptr)(mval *v, mval *p, int t, mval *mspace);
+GBLREF uint4 dollar_tlevel;
+GBLREF unsigned char t_fail_hist[CDB_MAX_TRIES];
+#ifdef DEBUG
+GBLREF boolean_t donot_INVOKE_MUMTSTART;
+#endif
-LITREF mval literal_hasht;
LITREF mval literal_zero;
LITREF mval literal_ten;
LITREF char *trigger_subs[];
@@ -77,20 +83,22 @@ LITREF char *trigger_subs[];
#define NAM_LEN(PTR, LEN) MIN(STRLEN((PTR)), (LEN))
-#define COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(OUT_BUFF, OUT_PTR, VAL, VAL_LEN) \
-{ \
- mval op_val; \
- \
- assert(MAX_BUFF_SIZE >= VAL_LEN); \
- if ((INTCAST(OUT_PTR - OUT_BUFF) + VAL_LEN) > MAX_BUFF_SIZE) \
- { \
- STR2MVAL(op_val, OUT_BUFF, (unsigned int)(OUT_PTR - OUT_BUFF)); \
- op_write(&op_val); \
- io_curr_device.out->dollar.x = 0; \
- OUT_PTR = OUT_BUFF; \
- } \
- memcpy(OUT_PTR, (const void *)VAL, VAL_LEN); \
- OUT_PTR += VAL_LEN; \
+#define COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(OUT_BUFF, OUT_PTR, VAL, VAL_LEN) \
+{ \
+ if ((INTCAST(OUT_PTR - OUT_BUFF) + VAL_LEN) > MAX_BUFF_SIZE) \
+ { \
+ util_out_print_gtmio("!AD", NOFLUSH, (unsigned int)(OUT_PTR - OUT_BUFF), OUT_BUFF); \
+ OUT_PTR = OUT_BUFF; \
+ } \
+ if (VAL_LEN > MAX_BUFF_SIZE) \
+ { \
+ util_out_print_gtmio("!AD", NOFLUSH, VAL_LEN, VAL); \
+ OUT_PTR = OUT_BUFF; \
+ } else \
+ { \
+ memcpy(OUT_PTR, (const void *)VAL, VAL_LEN); \
+ OUT_PTR += VAL_LEN; \
+ } \
}
#define COPY_SUBSCRIPT(OUT_BUFF, OUT_PTR, CHPTR, LEN_LEFT, IS_TYPE) \
@@ -149,14 +157,19 @@ LITREF char *trigger_subs[];
select_status = TRIG_FAILURE; \
}
+error_def(ERR_DBROLLEDBACK);
+error_def(ERR_MUNOACTION);
error_def(ERR_MUNOACTION);
error_def(ERR_MUPCLIERR);
-error_def(ERR_TRIGDEFBAD);
error_def(ERR_MUPCLIERR);
-error_def(ERR_MUNOACTION);
-
+error_def(ERR_NEEDTRIGUPGRD);
+error_def(ERR_TRIGDEFBAD);
-STATICDEF char *triggerfile_quals[] = {"-name=", "", "-commands=", "-options=", "-delim=", "-zdelim=", "-pieces=", "-xecute="};
+STATICDEF char *triggerfile_quals[] = {
+#define TRIGGER_SUBSDEF(SUBSTYPE, SUBSNAME, LITMVALNAME, TRIGFILEQUAL, PARTOFHASH) TRIGFILEQUAL,
+#include "trigger_subs_def.h"
+#undef TRIGGER_SUBSDEF
+};
STATICFNDEF void write_subscripts(char *out_rec, char **out_ptr, char **sub_ptr, int *sub_len)
{
@@ -195,7 +208,7 @@ STATICFNDEF void write_subscripts(char *out_rec, char **out_ptr, char **sub_ptr,
*out_ptr = out_p;
}
-STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 file_name_len, mval *op_val, int nam_indx)
+STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, int nam_indx)
{
mval data_val;
char out_rec[MAX_BUFF_SIZE];
@@ -220,6 +233,7 @@ STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 fil
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
+ assert(!cs_addrs->hdr->hasht_upgrade_needed); /* all callers should have errored out otherwise */
BUILD_HASHT_SUB_SUB_CURRKEY(gbl_name, gbl_name_len, LITERAL_HASHCOUNT, LITERAL_HASHCOUNT_LEN);
if (gvcst_get(&trigger_count))
{
@@ -228,12 +242,9 @@ STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 fil
{ /* There has to be a #LABEL */
if (CDB_STAGNATE > t_tries)
t_retry(cdb_sc_triggermod);
- else
- {
- assert(FALSE);
- rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, gbl_name_len,
- gbl_name, gbl_name_len, gbl_name, LEN_AND_LIT("\"#LABEL\""));
- }
+ assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
+ rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, gbl_name_len,
+ gbl_name, gbl_name_len, gbl_name, LEN_AND_LIT("\"#LABEL\""));
}
skip_chars = 1;
if ((trigger_value.str.len != STRLEN(HASHT_GBL_CURLABEL))
@@ -250,12 +261,9 @@ STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 fil
{ /* There has to be a #CYCLE */
if (CDB_STAGNATE > t_tries)
t_retry(cdb_sc_triggermod);
- else
- {
- assert(FALSE);
- rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, gbl_name_len,
- gbl_name, gbl_name_len, gbl_name, LEN_AND_LIT("\"#CYCLE\""));
- }
+ assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
+ rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, gbl_name_len,
+ gbl_name, gbl_name_len, gbl_name, LEN_AND_LIT("\"#CYCLE\""));
}
assert(MAX_DIGITS_IN_INT >= trigger_value.str.len);
memcpy(cycle, trigger_value.str.addr, trigger_value.str.len);
@@ -269,21 +277,29 @@ STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 fil
BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(gbl_name, gbl_name_len, mi, trigger_subs[TRIGNAME_SUB],
STRLEN(trigger_subs[TRIGNAME_SUB]));
out_rec_ptr = out_rec;
- if (gvcst_get(&trigger_value))
- {
- *out_rec_ptr++ = COMMENT_LITERAL;
+ if (!gvcst_get(&trigger_value))
+ { /* There has to be a #NAME */
+ 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(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, gbl_name_len,
+ gbl_name, gbl_name_len, gbl_name, LEN_AND_LIT("\"#NAME\""));
- COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, TRIGGER_NAME_COMMENT,
- STR_LIT_LEN(TRIGGER_NAME_COMMENT));
- COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, trigger_value.str.addr,
- trigger_value.str.len);
- COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, TRIGGER_CYCLE_COMMENT,
- STR_LIT_LEN(TRIGGER_CYCLE_COMMENT));
- COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, cycle, STRLEN(cycle));
- STR2MVAL((*op_val), out_rec, (unsigned int)(out_rec_ptr - out_rec));
- op_write(op_val);
- op_wteol(1);
}
+ *out_rec_ptr++ = COMMENT_LITERAL;
+ COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, TRIGGER_NAME_COMMENT,
+ STR_LIT_LEN(TRIGGER_NAME_COMMENT));
+ COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, trigger_value.str.addr,
+ trigger_value.str.len - 1); /* remove last # in name */
+ COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, SPANREG_REGION_LIT,
+ SPANREG_REGION_LITLEN);
+ COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, gv_cur_region->rname,
+ gv_cur_region->rname_len);
+ COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, ")", 1);
+ COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, TRIGGER_CYCLE_COMMENT,
+ STR_LIT_LEN(TRIGGER_CYCLE_COMMENT));
+ COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, cycle, STRLEN(cycle));
+ util_out_print_gtmio("!AD", FLUSH, (unsigned int)(out_rec_ptr - out_rec), out_rec);
out_rec_ptr = out_rec;
*out_rec_ptr++ = '+';
*out_rec_ptr++ = '^';
@@ -298,6 +314,11 @@ STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 fil
write_subscripts(out_rec, &out_rec_ptr, &sub_ptr, &sub_len);
COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, ")", 1);
}
+ /* Assert that BHASH and LHASH are not part of NUM_SUBS calculation
+ * (confirms the -2 done in the #define of NUM_SUBS).
+ */
+ assert(BHASH_SUB == NUM_SUBS);
+ assert(LHASH_SUB == (NUM_SUBS + 1));
for (sub_indx = 0; sub_indx < NUM_SUBS; sub_indx++)
{
if ((GVSUBS_SUB == sub_indx) || (CHSET_SUB == sub_indx))
@@ -305,6 +326,7 @@ STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 fil
BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(gbl_name, gbl_name_len, mi, trigger_subs[sub_indx],
STRLEN(trigger_subs[sub_indx]));
have_value = gvcst_get(&trigger_value);
+ have_value = have_value && (trigger_value.str.len);
multi_record = FALSE;
if (!have_value && (XECUTE_SUB == sub_indx))
{
@@ -314,7 +336,7 @@ STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 fil
if (have_value || multi_record)
{
if (TRIGNAME_SUB == sub_indx)
- { /* Output name only if it is user defined */
+ { /* Output "-name=XYZ" only if it is user defined */
BUILD_HASHT_SUB_MSUB_SUB_MSUB_CURRKEY(gbl_name, gbl_name_len, mi,
trigger_subs[sub_indx], STRLEN(trigger_subs[sub_indx]), mi);
if (!trigger_user_name(trigger_value.str.addr, trigger_value.str.len))
@@ -360,11 +382,9 @@ STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 fil
}
}
}
- /* we had better have an XECUTE STRING, probably should check some buddies */
- assert(NULL != xecute_buff);
- STR2MVAL((*op_val), out_rec, (unsigned int)(out_rec_ptr - out_rec));
- op_write(op_val);
- op_wteol(1);
+ /* we had better have an XECUTE STRING, if not it is a restartable situation */
+ DEBUG_ONLY(if (NULL == xecute_buff) TREF(donot_commit) |= DONOTCOMMIT_TRIGGER_SELECT_XECUTE;)
+ util_out_print_gtmio("!AD", FLUSH, (unsigned int)(out_rec_ptr - out_rec), out_rec);
if (multi_line)
{
ptr1 = xecute_buff;
@@ -377,16 +397,12 @@ STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 fil
ptr2 = ptrtop; /* if last line is not terminated by newline, make it so */
out_rec_ptr = out_rec;
COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, ptr1, UINTCAST(ptr2 - ptr1));
- STR2MVAL((*op_val), out_rec, (unsigned int)(out_rec_ptr - out_rec));
- op_write(op_val);
- op_wteol(1);
+ util_out_print_gtmio("!AD", FLUSH, (unsigned int)(out_rec_ptr - out_rec), out_rec);
ptr1 = ptr2 + 1;
} while (ptr1 < ptrtop);
out_rec_ptr = out_rec;
COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, XTENDED_STOP, XTENDED_STOP_LEN);
- STR2MVAL((*op_val), out_rec, (unsigned int)(out_rec_ptr - out_rec));
- op_write(op_val);
- op_wteol(1);
+ util_out_print_gtmio("!AD", FLUSH, (unsigned int)(out_rec_ptr - out_rec), out_rec);
}
if (NULL != xecute_buff)
{
@@ -397,42 +413,34 @@ STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 fil
}
}
-STATICFNDEF void write_gbls_or_names(char *gbl_name, uint4 gbl_name_len, uint4 file_name_len, mval *op_val, boolean_t trig_name)
+STATICFNDEF void write_gbls_or_names(char *gbl_name, uint4 gbl_name_len, boolean_t trig_name)
{
char save_name[MAX_MIDENT_LEN], curr_name[MAX_MIDENT_LEN];
boolean_t wildcard;
- gv_key save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
- gd_region *save_gv_cur_region;
- gv_namehead *save_gv_target;
- sgm_info *save_sgm_info_ptr;
- mname_entry ms_gvname;
mval mv_curr_nam;
- mval mi, trigger_count, trig_gbl;
- mval *mv_trig_cnt_ptr, mv_trigger_val;
+ mval mi, trig_gbl;
+ mval mv_trigger_val;
int indx, count;
- char *ptr;
+ char *ptr, *ptr2;
uint4 curr_name_len;
int trigvn_len;
- gvnh_reg_t *gvnh_reg;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
+ /* If ^#t needs to be upgraded, issue error. Cannot read older ^#t format that newer version does not always understand */
+ if (cs_addrs->hdr->hasht_upgrade_needed)
+ rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_NEEDTRIGUPGRD, 2, DB_LEN_STR(gv_cur_region));
memcpy(save_name, gbl_name, gbl_name_len);
wildcard = (NULL != (ptr = memchr(gbl_name, '*', gbl_name_len)));
if (wildcard)
{
- *ptr = '\0';
gbl_name_len--;
assert(INTCAST(ptr - gbl_name) == gbl_name_len);
}
- mv_trig_cnt_ptr = &trigger_count;
memcpy(curr_name, gbl_name, gbl_name_len);
curr_name_len = gbl_name_len;
- STR2MVAL(mv_curr_nam, gbl_name, gbl_name_len);
while (TRUE)
{
- if (0 != memcmp(curr_name, save_name, gbl_name_len))
- break;
if (trig_name)
{
BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STR_LIT_LEN(LITERAL_HASHTNAME), curr_name, curr_name_len);
@@ -445,32 +453,34 @@ STATICFNDEF void write_gbls_or_names(char *gbl_name, uint4 gbl_name_len, uint4 f
break;
memcpy(curr_name, mv_curr_nam.str.addr, mv_curr_nam.str.len);
curr_name_len = mv_curr_nam.str.len;
+ if (0 != memcmp(curr_name, save_name, gbl_name_len))
+ break;
continue;
}
break;
}
ptr = mv_trigger_val.str.addr;
- trigvn_len = STRLEN(mv_trigger_val.str.addr);
- ptr += trigvn_len + 1;
- A2I(ptr, mv_trigger_val.str.addr + mv_trigger_val.str.len, indx);
+ ptr2 = memchr(ptr, '\0', mv_trigger_val.str.len);
+ if (NULL == ptr2)
+ { /* We expect $c(0) in the middle of ptr. If we dont find it, this is a restartable situation */
+ 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(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6,
+ LEN_AND_LIT("\"#TNAME\""), curr_name_len, curr_name,
+ mv_trigger_val.str.len, mv_trigger_val.str.addr);
+ }
+ trigvn_len = ptr2 - ptr;
+ assert(('\0' == *ptr2) && (mv_trigger_val.str.len > trigvn_len));
+ ptr2++;
+ A2I(ptr2, mv_trigger_val.str.addr + mv_trigger_val.str.len, indx);
STR2MVAL(trig_gbl, mv_trigger_val.str.addr, trigvn_len);
- SAVE_TRIGGER_REGION_INFO(save_currkey);
- ms_gvname.var_name.addr = mv_trigger_val.str.addr;
- ms_gvname.var_name.len = trigvn_len;
- COMPUTE_HASH_MNAME(&ms_gvname);
- GV_BIND_NAME_ONLY(gd_header, &ms_gvname, gvnh_reg);
- SET_GVTARGET_TO_HASHT_GBL(gv_target->gd_csa);
- INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
} else
{
STR2MVAL(trig_gbl, curr_name, curr_name_len);
indx = 0;
}
- write_out_trigger(trig_gbl.str.addr, trig_gbl.str.len, file_name_len, op_val, indx);
- if (trig_name)
- {
- RESTORE_TRIGGER_REGION_INFO(save_currkey);
- }
+ write_out_trigger(trig_gbl.str.addr, trig_gbl.str.len, indx);
if (wildcard)
{
if (trig_name)
@@ -485,13 +495,15 @@ STATICFNDEF void write_gbls_or_names(char *gbl_name, uint4 gbl_name_len, uint4 f
if (0 == mv_curr_nam.str.len)
break;
memcpy(curr_name, mv_curr_nam.str.addr, mv_curr_nam.str.len);
+ if (0 != memcmp(curr_name, save_name, gbl_name_len))
+ break;
curr_name_len = mv_curr_nam.str.len;
} else
break;
}
}
-STATICFNDEF void dump_all_triggers(uint4 file_name_len, mval *op_val)
+STATICFNDEF void dump_all_triggers(void)
{
mval curr_gbl_name, val;
gd_region *reg;
@@ -509,17 +521,18 @@ STATICFNDEF void dump_all_triggers(uint4 file_name_len, mval *op_val)
save_gvtarget = gv_target;
for (reg_index = 0, reg = gd_header->regions; reg_index < gd_header->n_regions; reg_index++, reg++)
{
- if (!reg->open)
- gv_init_reg(reg);
- gv_cur_region = reg;
- change_reg();
- SET_GVTARGET_TO_HASHT_GBL(cs_addrs);
- INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
+ GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(reg);
+ if (NULL == cs_addrs) /* not MM or BG access method, which means GT.CM */
+ continue;
+ /* gv_target now points to ^#t in region "reg" */
if (0 != gv_target->root)
{
+ /* If ^#t needs to be upgraded, issue error. Cannot read older ^#t format */
+ if (cs_addrs->hdr->hasht_upgrade_needed)
+ rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_NEEDTRIGUPGRD, 2, DB_LEN_STR(gv_cur_region));
op_gvdata(&val);
if ((literal_ten.m[0] == val.m[0]) && (literal_ten.m[1] == val.m[1]))
- { /* $DATA(^#t) is 10 - get first subscript (trigger's global) */
+ { /* $DATA(^#t) is 10 - get first subscript (trigger's global) */
BUILD_HASHT_SUB_CURRKEY(LITERAL_MAXHASHVAL, STR_LIT_LEN(LITERAL_MAXHASHVAL));
while (TRUE)
{
@@ -528,7 +541,7 @@ STATICFNDEF void dump_all_triggers(uint4 file_name_len, mval *op_val)
break;
gbl_len = curr_gbl_name.str.len;
memcpy(global, curr_gbl_name.str.addr, gbl_len);
- write_out_trigger(global, gbl_len, file_name_len, op_val, 0);
+ write_out_trigger(global, gbl_len, 0);
BUILD_HASHT_SUB_CURRKEY(global, gbl_len);
}
} else
@@ -537,26 +550,16 @@ STATICFNDEF void dump_all_triggers(uint4 file_name_len, mval *op_val)
}
}
-boolean_t trigger_select(char *select_list, uint4 select_list_len, char *file_name, uint4 file_name_len)
+/* returns TRUE (not TRIG_FAILURE) in case of failure */
+boolean_t trigger_select_tpwrap(char *select_list, uint4 select_list_len, char *file_name, uint4 file_name_len)
{
- char *sel_ptr, *strtok_ptr, *prev_ptr, *ptr1, *ptr2;
- int gbl_len, prev_len;
- mname_entry gvname;
- gv_namehead *save_gvtarget;
- gv_key save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
- gd_region *save_gv_cur_region;
- char save_select_list[MAX_BUFF_SIZE];
- mval trigger_value;
- int len, len1, badpos;
- int local_errno;
- boolean_t trig_name;
- gv_namehead *save_gv_target;
- sgm_info *save_sgm_info_ptr;
- boolean_t dump_all;
mval op_val, op_pars;
boolean_t select_status;
io_pair save_io_curr_device;
- gvnh_reg_t *gvnh_reg;
+ mval ts_mv;
+ int loopcnt;
+ DEBUG_ONLY(unsigned int lcl_t_tries;)
+ enum cdb_sc failure;
static readonly unsigned char open_params_list[] =
{
@@ -572,15 +575,13 @@ boolean_t trigger_select(char *select_list, uint4 select_list_len, char *file_na
(unsigned char)iop_eol
};
static readonly unsigned char no_param = (unsigned char)iop_eol;
+ DCL_THREADGBL_ACCESS;
+ SETUP_THREADGBL_ACCESS;
/* make a local copy of the select list and use it to avoid string-pool problems */
if (MAX_BUFF_SIZE <= select_list_len)
- return TRIG_FAILURE;
- memcpy(save_select_list, select_list, select_list_len);
- save_select_list[select_list_len] = '\0';
+ return TRUE; /* failure return */
gvinit();
- dump_all = FALSE;
- prev_len = 0;
op_pars.mvtype = MV_STR;
op_val.mvtype = MV_STR;
if (0 == file_name_len)
@@ -608,13 +609,130 @@ boolean_t trigger_select(char *select_list, uint4 select_list_len, char *file_na
}
save_io_curr_device = io_curr_device;
op_use(&op_val, &op_pars);
+ TREF(ztrig_use_io_curr_device) = TRUE;
+ select_status = TRIG_SUCCESS;
+ ts_mv.mvtype = MV_STR;
+ ts_mv.str.len = 0;
+ ts_mv.str.addr = NULL;
+ if (0 == dollar_tlevel)
+ { /* If not already wrapped in TP, wrap it now implicitly */
+ assert(!donot_INVOKE_MUMTSTART);
+ DEBUG_ONLY(donot_INVOKE_MUMTSTART = TRUE);
+ /* Note down dollar_tlevel before op_tstart. This is needed to determine if we need to break from the for-loop
+ * below after a successful op_tcommit of the trigger select . We cannot check that dollar_tlevel is zero
+ * since the op_tstart done below can be a nested sub-transaction
+ */
+ op_tstart((IMPLICIT_TSTART + IMPLICIT_TRIGGER_TSTART), TRUE, &ts_mv, 0); /* 0 ==> save no locals but RESTART OK */
+ /* The following for loop structure is similar to that in function "trigger_trgfile_tpwrap" and various
+ * other places so any changes here might need to be reflected there as well.
+ */
+ for (loopcnt = 0; ; loopcnt++)
+ {
+ assert(donot_INVOKE_MUMTSTART); /* Make sure still set */
+ DEBUG_ONLY(lcl_t_tries = t_tries);
+ select_status = trigger_select_tpwrap_helper(select_list, select_list_len);
+ if (0 == dollar_tlevel)
+ break;
+ assert(0 < t_tries);
+ assert((CDB_STAGNATE == t_tries) || (lcl_t_tries == t_tries - 1));
+ failure = LAST_RESTART_CODE;
+ assert(((cdb_sc_onln_rlbk1 != failure) && (cdb_sc_onln_rlbk2 != failure))
+ || !gv_target || !gv_target->root);
+ assert((cdb_sc_onln_rlbk2 != failure) || !IS_GTM_IMAGE || TREF(dollar_zonlnrlbk));
+ if (cdb_sc_onln_rlbk2 == failure)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DBROLLEDBACK);
+ /* else if (cdb_sc_onln_rlbk1 == status) we don't need to do anything other than trying again. Since this
+ * is ^#t global, we don't need to GVCST_ROOT_SEARCH before continuing with the next restart because the
+ * trigger load logic already takes care of doing INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED before doing the
+ * actual trigger load
+ */
+ /* We expect the above function to return with either op_tcommit or a tp_restart invoked.
+ * In the case of op_tcommit, we expect dollar_tlevel to be 0 and if so we break out of the loop.
+ * In the tp_restart case, we expect a maximum of 4 tries/retries and much lesser usually.
+ * Additionally we also want to avoid an infinite loop so limit the loop to what is considered
+ * a huge iteration count and assertpro if that is reached as it suggests an out-of-design situation.
+ */
+ assertpro(TPWRAP_HELPER_MAX_ATTEMPTS >= loopcnt);
+ }
+ } else
+ {
+ select_status = trigger_select(select_list, select_list_len);
+ assert(0 < dollar_tlevel);
+ }
+ TREF(ztrig_use_io_curr_device) = FALSE;
+ if (0 != file_name_len)
+ {
+ op_val.mvtype = op_pars.mvtype = MV_STR;
+ op_val.str.addr = (char *)file_name;;
+ op_val.str.len = file_name_len;
+ op_pars.str.len = SIZEOF(no_param);
+ op_pars.str.addr = (char *)&no_param;
+ op_close(&op_val, &op_pars);
+ /* Return back to the current device */
+ io_curr_device = save_io_curr_device;
+ }
+ return (TRIG_FAILURE == select_status);
+}
+
+STATICFNDEF boolean_t trigger_select_tpwrap_helper(char *select_list, uint4 select_list_len)
+{
+ enum cdb_sc cdb_status;
+ boolean_t select_status;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ ESTABLISH_RET(trigger_tpwrap_ch, TRIG_FAILURE);
+ select_status = trigger_select(select_list, select_list_len);
+ if (TRIG_SUCCESS == select_status)
+ {
+ GVTR_OP_TCOMMIT(cdb_status);
+ if (cdb_sc_normal != cdb_status)
+ t_retry(cdb_status); /* won't return */
+ } else
+ { /* Record cannot be committed - undo everything */
+ assert(donot_INVOKE_MUMTSTART);
+ DEBUG_ONLY(donot_INVOKE_MUMTSTART = FALSE);
+ /* Print $ztrigger/mupip-trigger output before rolling back TP */
+ TP_ZTRIGBUFF_PRINT;
+ OP_TROLLBACK(-1); /* returns but kills implicit transaction */
+ }
+ REVERT;
+ return select_status;
+}
+
+STATICFNDEF boolean_t trigger_select(char *select_list, uint4 select_list_len)
+{
+ boolean_t dump_all;
+ char save_select_list[MAX_BUFF_SIZE];
+ char *sel_ptr, *strtok_ptr, *prev_ptr, *ptr1, *ptr2;
+ int gbl_len, prev_len;
+ mname_entry gvname;
+ int len, len1, badpos;
+ boolean_t trig_name;
+ gv_key save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
+ gd_region *save_gv_cur_region;
+ gv_namehead *save_gv_target;
+ sgm_info *save_sgm_info_ptr;
+ boolean_t select_status;
+ gvnh_reg_t *gvnh_reg;
+ gd_binding *map, *start_map, *end_map;
+ gd_region *reg, *reg_start, *reg_top;
+ int *reg_done, reg_array_size, reg_index;
+ sgmnt_addrs *csa;
+
+ assert(dollar_tlevel);
+ select_status = TRIG_SUCCESS;
+ memcpy(save_select_list, select_list, select_list_len);
+ save_select_list[select_list_len] = '\0';
+ dump_all = FALSE;
+ prev_len = 0;
if (0 == select_list_len)
dump_all = TRUE;
else
{
for (ptr1 = save_select_list, len = select_list_len;
- (NULL != (ptr2 = strchr(ptr1, '*'))) && (len > (len1 = INTCAST(ptr2 - ptr1)));
- ptr1 = ptr2 + 1)
+ (NULL != (ptr2 = strchr(ptr1, '*'))) && (len > (len1 = INTCAST(ptr2 - ptr1)));
+ ptr1 = ptr2 + 1)
{ /* look for either a real "dump-it-all" *, an error *, or a wildcard * */
/* A "*" anywhere in the select list (at a place where a global name would be) is the same as only a "*" */
len -= (len1 + 1); /* Length after the "*" -- len1 is length before the "*" */
@@ -627,9 +745,8 @@ boolean_t trigger_select(char *select_list, uint4 select_list_len, char *file_na
break;
}
}
- select_status = TRIG_SUCCESS;
if (dump_all)
- dump_all_triggers(file_name_len, &op_val);
+ dump_all_triggers();
else
{
len = select_list_len;
@@ -652,55 +769,88 @@ boolean_t trigger_select(char *select_list, uint4 select_list_len, char *file_na
select_status, badpos);
continue;
}
- SAVE_TRIGGER_REGION_INFO(save_currkey);
gbl_len = NAM_LEN(sel_ptr + 1, (int)(ptr1 - sel_ptr) - 1);
ptr1 = sel_ptr + 1;
- if ((prev_len != gbl_len) || (0 != memcmp(prev_ptr, ptr1, gbl_len)))
- {
- prev_ptr = ptr1;
- prev_len = gbl_len;
- gvname.var_name.addr = ptr1;
- gvname.var_name.len = gbl_len;
+ /* Skip only if the previous global is the same as the current */
+ if ((prev_len == gbl_len) && (0 == memcmp(prev_ptr, ptr1, gbl_len)))
+ continue;
+ SAVE_TRIGGER_REGION_INFO(save_currkey);
+ prev_ptr = ptr1;
+ prev_len = gbl_len;
+ start_map = gv_srch_map(gd_header, ptr1, gbl_len);
+ ptr1[gbl_len - 1]++;
+ end_map = gv_srch_map(gd_header, ptr1, gbl_len);
+ ptr1[gbl_len - 1]--;
+ gvname.var_name.addr = ptr1;
+ gvname.var_name.len = gbl_len;
+ if (start_map != end_map)
+ { /* Global specification involves multiple regions */
+ reg_start = &gd_header->regions[0];
+ reg_array_size = gd_header->n_regions;
+ reg_done = malloc(reg_array_size * SIZEOF(*reg_done));
+ memset(reg_done, 0, reg_array_size * SIZEOF(*reg_done));
+ if ('*' == ptr1[gbl_len])
+ gvname.var_name.len++;
+ for (map = start_map; map <= end_map; map++)
+ {
+ reg = map->reg.addr;
+ GET_REG_INDEX(gd_header, reg_start, reg, reg_index); /* sets "reg_index" */
+ assert(reg_array_size > reg_index);
+ if (!reg_done[reg_index])
+ { /* this region first encountered now */
+ GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(reg);
+ if (NULL == cs_addrs) /* not BG or MM access method */
+ continue;
+ /* gv_target now points to ^#t in region "reg" */
+ if (0 != gv_target->root)
+ write_gbls_or_names(gvname.var_name.addr, gvname.var_name.len,
+ trig_name);
+ reg_done[reg_index] = TRUE;
+ }
+ }
+ free(reg_done);
+ } else
+ { /* Global specification involves only one region */
COMPUTE_HASH_MNAME(&gvname);
GV_BIND_NAME_ONLY(gd_header, &gvname, gvnh_reg);
- if ('*' == *(ptr1 + gbl_len))
- gvname.var_name.len++;
+ /* skip selecting/dumping triggers if not BG or MM access method */
+ if (NULL != cs_addrs)
+ {
+ if ('*' == ptr1[gbl_len])
+ gvname.var_name.len++;
+ SET_GVTARGET_TO_HASHT_GBL(gv_target->gd_csa);
+ INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
+ if (0 != gv_target->root)
+ write_gbls_or_names(gvname.var_name.addr, gvname.var_name.len,
+ trig_name);
+ }
}
- SET_GVTARGET_TO_HASHT_GBL(gv_target->gd_csa);
} else
{
if (len1 != (badpos = validate_input_trigger_name(ptr1, len1, NULL))) /* assignment is intended */
{ /* is the input name valid */
- INVALID_NAME_ERROR("Invalid name entry in SELECT list: ",
- sel_ptr, select_status, badpos);
+ INVALID_NAME_ERROR("Invalid name entry in SELECT list: ", sel_ptr, select_status, badpos);
continue;
}
if (TRIGNAME_SEQ_DELIM == *(sel_ptr + (len1 - 1)))
- /* drop the trailing # sign */
- len1--;
+ len1--; /* drop the trailing # sign */
gvname.var_name.addr = sel_ptr;
gvname.var_name.len = len1;
SAVE_TRIGGER_REGION_INFO(save_currkey);
- SWITCH_TO_DEFAULT_REGION;
+ for (reg = gd_header->regions, reg_top = reg + gd_header->n_regions; reg < reg_top; reg++)
+ {
+ GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(reg);
+ if (NULL == cs_addrs) /* not BG or MM access method */
+ continue;
+ /* gv_target now points to ^#t in region "reg" */
+ if (0 == gv_target->root)
+ continue;
+ write_gbls_or_names(gvname.var_name.addr, gvname.var_name.len, trig_name);
+ }
}
- INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
- if (0 != gv_target->root)
- write_gbls_or_names(gvname.var_name.addr, gvname.var_name.len, file_name_len, &op_val, trig_name);
RESTORE_TRIGGER_REGION_INFO(save_currkey);
} while (NULL != (sel_ptr = strtok_r(NULL, ",", &strtok_ptr))); /* Embedded assignment is intended */
}
- if (0 != file_name_len)
- {
- op_val.mvtype = op_pars.mvtype = MV_STR;
- op_val.str.addr = (char *)file_name;;
- op_val.str.len = file_name_len;
- op_pars.str.len = SIZEOF(no_param);
- op_pars.str.addr = (char *)&no_param;
- op_close(&op_val, &op_pars);
- /* Return back to the current device */
- io_curr_device = save_io_curr_device;
- }
return select_status;
}
-
#endif
diff --git a/sr_unix/trigger_select_protos.h b/sr_unix/trigger_select_protos.h
index 7660921..ed32c44 100644
--- a/sr_unix/trigger_select_protos.h
+++ b/sr_unix/trigger_select_protos.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010 Fidelity Information Services, Inc *
+ * Copyright 2010, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -13,10 +13,12 @@
#define TRIGGER_SELECT_PROTOS_INCLUDED
STATICFNDCL void write_subscripts(char *out_rec, char **out_ptr, char **sub_ptr, int *sub_len);
-STATICFNDCL void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 file_name_len, mval *op_val, int nam_indx);
-STATICFNDCL void write_gbls_or_names(char *gbl_name, uint4 gbl_name_len, uint4 file_name_len, mval *op_val, boolean_t trig_name);
-STATICFNDCL void dump_all_triggers(uint4 file_name_len, mval *op_val);
+STATICFNDCL void write_out_trigger(char *gbl_name, uint4 gbl_name_len, int nam_indx);
+STATICFNDCL void write_gbls_or_names(char *gbl_name, uint4 gbl_name_len, boolean_t trig_name);
+STATICFNDCL void dump_all_triggers(void);
-boolean_t trigger_select(char *select_list, uint4 select_list_len, char *file_name, uint4 file_name_len);
+boolean_t trigger_select_tpwrap(char *select_list, uint4 select_list_len, char *file_name, uint4 file_name_len);
+STATICFNDCL boolean_t trigger_select_tpwrap_helper(char *select_list, uint4 select_list_len);
+STATICFNDCL boolean_t trigger_select(char *select_list, uint4 select_list_len);
#endif /* TRIGGER_SELECT_PROTOS_INCLUDED */
diff --git a/sr_unix/trigger_source_read_andor_verify.c b/sr_unix/trigger_source_read_andor_verify.c
index 5afcf20..07f4f94 100644
--- a/sr_unix/trigger_source_read_andor_verify.c
+++ b/sr_unix/trigger_source_read_andor_verify.c
@@ -23,12 +23,11 @@
#include "trigger.h"
#include "trigger_fill_xecute_buffer.h"
#include "trigger_gbl_fill_xecute_buffer.h"
-#include "trigger_read_name_entry.h"
#include "trigger_source_read_andor_verify.h"
#include "gvsub2str.h" /* for COPY_SUBS_TO_GVCURRKEY */
#include "format_targ_key.h" /* for COPY_SUBS_TO_GVCURRKEY */
#include "hashtab.h" /* for STR_HASH (in COMPUTE_HASH_MNAME) */
-#include "targ_alloc.h" /* for SET_GVTARGET_TO_HASHT_GBL & SWITCH_TO_DEFAULT_REGION */
+#include "targ_alloc.h" /* for SET_GVTARGET_TO_HASHT_GBL */
#include "filestruct.h" /* for INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED (FILE_INFO) */
#include "mvalconv.h"
#include "gdscc.h" /* needed for tp.h */
@@ -49,6 +48,11 @@
#include "mv_stent.h"
#include "gv_trigger_protos.h"
#include "hashtab_mname.h"
+#include "hashtab_str.h" /* needed by trigger_update_protos.h */
+#include "trigger_update_protos.h" /* for trigger_name_search prototype */
+#include "change_reg.h" /* for "change_reg" prototype */
+#include "gvnh_spanreg.h"
+#include "min_max.h"
GBLREF uint4 dollar_tlevel;
GBLREF sgmnt_addrs *cs_addrs;
@@ -64,19 +68,32 @@ GBLREF int4 gtm_trigger_depth;
GBLREF trans_num local_tn;
GBLREF unsigned int t_tries;
GBLREF unsigned char t_fail_hist[CDB_MAX_TRIES];
+GBLREF rtn_tabent *rtn_names_end;
#ifdef DEBUG
GBLREF boolean_t donot_INVOKE_MUMTSTART;
#endif
LITREF mval literal_batch;
-LITREF mval literal_hasht;
#define TRIG_FAILURE_RC -1
+#define ISSUE_TRIGNAMENF_ERROR_IF_APPROPRIATE(TRIGNAME) \
+{ \
+ DCL_THREADGBL_ACCESS; \
+ \
+ SETUP_THREADGBL_ACCESS; \
+ if (!TREF(op_fntext_tlevel)) \
+ { \
+ CLEAR_IMPLICIT_TP_BEFORE_ERROR; \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TRIGNAMENF, 2, TRIGNAME->len, TRIGNAME->addr); \
+ } \
+}
+
+STATICFNDCL gd_region *find_region(mstr *regname);
STATICFNDCL CONDITION_HANDLER(trigger_source_raov_ch);
-STATICFNDCL int trigger_source_raov(mstr *trigname, trigger_action trigger_op);
-STATICFNDCL int trigger_source_raov_tpwrap_helper(mstr *trigname, trigger_action trigger_op);
-STATICFNDCL boolean_t trigger_source_raov_trigload(mstr *trigname, gv_trigger_t **ret_trigdsc);
+STATICFNDCL int trigger_source_raov(mstr *trigname, trigger_action trigger_op, gd_region *reg, rhdtyp **rtn_vec);
+STATICFNDCL int trigger_source_raov_tpwrap_helper(mstr *trigname, trigger_action trigger_op, gd_region *reg, rhdtyp **rtn_vec);
+STATICFNDCL boolean_t trigger_source_raov_trigload(mstr *trigname, gv_trigger_t **ret_trigdsc, gd_region *reg);
error_def(ERR_DBROLLEDBACK);
error_def(ERR_TPRETRY);
@@ -90,13 +107,13 @@ error_def(ERR_TRIGNAMENF);
* condition caused the error, this will restart and retry the transaction. Note that since skip_INVOKE_RESTART
* is not set before this op_tcommit, it with throw a restart rather than returning a restartable code.
*/
-#define CLEAR_IMPLICIT_TP_BEFORE_ERROR \
- if (tp_pointer->implicit_trigger && (0 == gtm_trigger_depth)) \
- { /* We have an implicit TP fence */ \
- enum cdb_sc status; \
- /* Eliminate transaction by commiting it (nothing was done) */ \
- status = op_tcommit(); \
- assert(cdb_sc_normal == status); \
+#define CLEAR_IMPLICIT_TP_BEFORE_ERROR \
+ if (dollar_tlevel && tp_pointer->implicit_trigger && (0 == gtm_trigger_depth)) \
+ { /* We have an implicit TP fence */ \
+ enum cdb_sc status; \
+ /* Eliminate transaction by commiting it (nothing was done) */ \
+ status = op_tcommit(); \
+ assert(cdb_sc_normal == status); \
}
@@ -120,6 +137,24 @@ CONDITION_HANDLER(trigger_source_raov_ch)
NEXTCH;
}
+STATICFNDEF gd_region *find_region(mstr *regname)
+{
+ gd_region *reg, *reg_top;
+ mstr tmpstr;
+ int comp;
+
+ assert(NULL != gd_header);
+ for (reg = gd_header->regions, reg_top = reg + gd_header->n_regions; reg < reg_top; reg++)
+ {
+ tmpstr.len = reg->rname_len;
+ tmpstr.addr = (char *)reg->rname;
+ MSTR_CMP(tmpstr, *regname, comp);
+ if (0 == comp)
+ return reg;
+ }
+ return NULL;
+}
+
/* Routine to check on the named trigger. This routine is called from (at least) two places: the above get_src_line()
* routine where it is called to retrieve trigger source (left in source definition buffer of the trigger) and the other
* time it is called from op_setzbrk() to load and/or compile the trigger. In both cases, the trigger may be loaded or
@@ -130,48 +165,88 @@ CONDITION_HANDLER(trigger_source_raov_ch)
* The following sitations can exist:
*
* 1. No trigger by the given name is loaded. For this situation, we need to locate and load the trigger and its source.
- * 2. Trigger is loaded but no source is in the trigger source buffer. For this situation, verify the trigger load is
- * current. If not, restart things. If is current, load the source.
- * 3. Trigger and source both loaded. Verify the trigger is current. if not restart things.
+ * 2. Trigger is loaded but no source is in the trigger source buffer. For this situation, load the source and mark the
+ * trigger as part of the transaction.
+ * 3. Trigger and source both loaded. For this situation, mark the trigger as part of the transaction.
*
- * In addition, we can be entered either with a TP FENCE already enabled or without one. How we deal with restarts varries
- * depending on which is true:
+ * If a TP fence is not in place, we provide an implcit wrapper that will catch our restarts and reinvoke the logic
+ * that will reload the trigger from scratch. We do not verify that the trigger information in memory is fresh.
*
- * - If in a TP fence already, if we hit a condition where we need to restart, we throw a trigger based restart condition
- * but because we aren't necessarily driving any triggers here, there is nothing in the restart process that actually
- * forces the trigger to reload before we come back here. So we call gvtr_free() on the region in question to force
- * those triggers to reload completely, even if it is us that ends up doing it when we get back here.
- * - If NOT under a TP fence already, we provide an implcit wrapper that will catch our restarts and reinvoke the logic
- * that will reload the trigger from scratch.
+ * If a TP FENCE is in place and we are in the final retry, we verify that the triggers are current and reload them if
+ * not. This avoids the possibility of using stale triggers.
*
* Note, this routine is for loading trigger source when we are not driving triggers. The trigger_fill_xecute_buffer()
* should be used when fetching source for trigger execution because it is lighter weight with built-in trigger refetch
* logic since we are using the globals the triggers live in. In this case, the trigger access is adhoc for the $TEXT()
* ZPRINT and ZBREAK uses.
*/
-int trigger_source_read_andor_verify(mstr *trigname, trigger_action trigger_op)
+int trigger_source_read_andor_verify(mstr *trigname, trigger_action trigger_op, rhdtyp **rtn_vec)
{
- gd_region *save_gv_cur_region;
- gv_namehead *save_gv_target;
- sgm_info *save_sgm_info_ptr;
+ char *ptr, *ptr_beg, *ptr_top;
+ enum cdb_sc failure;
+ gd_region *reg;
int src_fetch_status;
- gv_key save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
+ mstr regname;
+ rtn_tabent *rttabent;
uint4 cycle;
DEBUG_ONLY(unsigned int lcl_t_tries;)
- enum cdb_sc failure;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
assert(NULL != trigname);
assert((NULL != trigname->addr) && (0 != trigname->len));
- /* Before we try to save anything, see if there is something to save and initialize stuff if not */
if (NULL == gd_header)
- { /* If we do initialize things, start off in the default region since we need it shortly anyway */
gvinit();
- SWITCH_TO_DEFAULT_REGION;
+ DBGTRIGR((stderr, "trigger_source_read_andor_verify: Entered with trigger action %d $tlevel=%d, $trigdepth=%d\n",
+ trigger_op, dollar_tlevel, gtm_trigger_depth));
+ /*
+ * Input parameter "trigname" is of the form
+ * a) <21-BYTE-MAX-TRUNCATED-GBLNAME>#<AUTO-GENERATED-CNT>#[RUNTIME-DISAMBIGUATOR][/REGION-NAME] OR
+ * b) <28-BYTE-USER-SPECIFIED-TRIGNAME>#[RUNTIME-DISAMBIGUATOR][/REGION-NAME]
+ * where
+ * <21-BYTE-MAX-TRUNCATED-GBLNAME>#<AUTO-GENERATED-CNT> OR <28-BYTE-USER-SPECIFIED-TRIGNAME> is the
+ * auto-generated or user-specified trigger name we are searching for
+ * RUNTIME-DISAMBIGUATOR is the unique string appended at the end by the runtime to distinguish
+ * multiple triggers in different regions with the same auto-generated or user-given name
+ * REGION-NAME is the name of the region in the gld where we specifically want to search for trigger names
+ * [] implies optional parts
+ *
+ * Example usages are
+ * x# : trigger routine user-named "x"
+ * x#1# : trigger routine auto-named "x#1"
+ * x#1#A : trigger routine auto-named "x#1" but also runtime disambiguated by "#A" at the end
+ * x#/BREG : trigger routine user-named "x" in region BREG
+ * x#A/BREG : trigger routine user-named "x", runtime disambiguated by "#A", AND in region BREG
+ * x#1#/BREG : trigger routine auto-named "x#1" in region BREG
+ * x#1#A/BREG : trigger routine auto-named "x#1", runtime disambiguated by "#A", AND in region BREG
+ */
+ /* First lets locate the trigger. Try simple way first - lookup in routine name table.
+ * But "find_rtn_tabent" function has no clue about REGION-NAME so remove /REGION-NAME (if any) before invoking it.
+ */
+ regname.len = 0;
+ reg = NULL;
+ for (ptr_beg = trigname->addr, ptr_top = ptr_beg + trigname->len, ptr = ptr_top - 1; ptr >= ptr_beg; ptr--)
+ {
+ /* If we see a '#' and have not yet seen a '/' we are sure no region-name disambiguator has been specified */
+ if ('#' == *ptr)
+ break;
+ if ('/' == *ptr)
+ {
+ trigname->len = ptr - trigname->addr;
+ ptr++;
+ regname.addr = ptr;
+ regname.len = ptr_top - ptr;
+ reg = find_region(®name); /* find region "regname" in "gd_header" */
+ if (NULL == reg)
+ { /* Specified region-name is not present in current gbldir.
+ * Treat non-existent region name as if trigger was not found.
+ */
+ ISSUE_TRIGNAMENF_ERROR_IF_APPROPRIATE(trigname);
+ return TRIG_FAILURE_RC;
+ }
+ break;
+ }
}
- SAVE_TRIGGER_REGION_INFO(save_currkey);
- DBGTRIGR((stderr, "trigger_source_raov: Entered with trigger action %d\n", trigger_op));
/* First determination is if a TP fence is already in operation or not */
if (0 == dollar_tlevel)
{ /* We need a TP fence - provide one */
@@ -185,7 +260,7 @@ int trigger_source_read_andor_verify(mstr *trigname, trigger_action trigger_op)
for (;;)
{ /* Now that we are TP wrapped, fetch the trigger source lines from the ^#t global */
DEBUG_ONLY(lcl_t_tries = t_tries);
- src_fetch_status = trigger_source_raov_tpwrap_helper(trigname, trigger_op);
+ src_fetch_status = trigger_source_raov_tpwrap_helper(trigname, trigger_op, reg, rtn_vec);
if ((0 == src_fetch_status) || (TRIG_FAILURE_RC == src_fetch_status))
{
assert(0 == dollar_tlevel); /* op_tcommit should have made sure of this */
@@ -213,14 +288,15 @@ int trigger_source_read_andor_verify(mstr *trigname, trigger_action trigger_op)
}
} else
/* no return if TP restart */
- src_fetch_status = trigger_source_raov(trigname, trigger_op);
+ src_fetch_status = trigger_source_raov(trigname, trigger_op, reg, rtn_vec);
assert((0 == src_fetch_status) || (TRIG_FAILURE_RC == src_fetch_status));
- RESTORE_TRIGGER_REGION_INFO(save_currkey);
+ DBGTRIGR((stderr, "trigger_source_read_andor_verify: leaving with source from 0x%lx\n",
+ (*rtn_vec)?(*((rhdtyp **)rtn_vec))->trigr_handle:NULL));
return src_fetch_status;
}
/* Now TP wrap and fetch the trigger source lines from the ^#t global */
-STATICFNDEF int trigger_source_raov_tpwrap_helper(mstr *trigname, trigger_action trigger_op)
+STATICFNDEF int trigger_source_raov_tpwrap_helper(mstr *trigname, trigger_action trigger_op, gd_region *reg, rhdtyp **rtn_vec)
{
enum cdb_sc cdb_status;
int rc;
@@ -228,7 +304,7 @@ STATICFNDEF int trigger_source_raov_tpwrap_helper(mstr *trigname, trigger_action
DBGTRIGR((stderr, "trigger_source_tpwrap_helper: Entered\n"));
ESTABLISH_RET(trigger_source_raov_ch, SIGNAL);
assert(donot_INVOKE_MUMTSTART);
- rc = trigger_source_raov(trigname, trigger_op);
+ rc = trigger_source_raov(trigname, trigger_op, reg, rtn_vec);
assert((0 == rc) || (TRIG_FAILURE_RC == rc));
/* Finish it now verifying it completed successfully */
GVTR_OP_TCOMMIT(cdb_status);
@@ -245,30 +321,104 @@ STATICFNDEF int trigger_source_raov_tpwrap_helper(mstr *trigname, trigger_action
* loading the trigger, loading the source, verifying proper source/trigger is loaded and compiling if
* desired. If we complete successfully, returns 0. Error returns caught by condition handlers can return other values.
*/
-STATICFNDEF int trigger_source_raov(mstr *trigname, trigger_action trigger_op)
+STATICFNDEF int trigger_source_raov(mstr *trigname, trigger_action trigger_op, gd_region *reg, rhdtyp **rtn_vec)
{
- sgmnt_addrs *csa=NULL;
- sgmnt_data_ptr_t csd;
- rhdtyp *rtn_vector;
+ boolean_t runtime_disambiguator_specified;
+ gd_region *save_gv_cur_region;
+ gv_key save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
gv_namehead *gvt;
+ gv_namehead *save_gv_target;
+ gvnh_reg_t *gvnh_reg;
+ gv_trigger_t *trigdsc;
gvt_trigger_t *gvt_trigger;
- mstr gbl, xecute_buff;
int index;
- mval trig_index;
- gv_trigger_t *trigdsc;
- uint4 cycle_start;
- boolean_t triggers_reloaded, db_trigger_cycle_mismatch, ztrig_cycle_mismatch;
+ mident rtn_name;
+ mstr gbl, xecute_buff;
+ mval trig_index, val;
+ rhdtyp *rtn_vector;
+ rtn_tabent *rttabent;
+ sgm_info *save_sgm_info_ptr;
+ sgmnt_addrs *csa, *regcsa;
+ sgmnt_data_ptr_t csd;
+ boolean_t db_trigger_cycle_mismatch, ztrig_cycle_mismatch, needs_reload, needs_restart;
+ DCL_THREADGBL_ACCESS;
+ SETUP_THREADGBL_ACCESS;
assert(dollar_tlevel); /* A TP wrap should have been done by the caller if needed */
- /* First lets locate the trigger. Try simple way first - lookup in routine name table */
- if (NULL == (rtn_vector = find_rtn_hdr(trigname))) /* Note assignment */
- { /* Wasn't found - look for it the harder way in the #t of the default region */
- if(TRIG_FAILURE == trigger_source_raov_trigload(trigname, &trigdsc))
+ DBGTRIGR((stderr, "trigger_source_raov: Entered with trigger action %d\n", trigger_op));
+ /* Before we try to save anything, see if there is something to save and initialize stuff if not */
+ SAVE_TRIGGER_REGION_INFO(save_currkey);
+ if (find_rtn_tabent(&rttabent, trigname))
+ rtn_vector = rttabent->rt_adr;
+ else
+ rtn_vector = NULL;
+ DBGTRIGR((stderr, "trigger_source_raov: routine was %sfound\n", (NULL == rtn_vector)?"not ":""));
+ /* If region is specified, a null-runtime-disambiguator is treated as if runtime-disambiguator was not specified.
+ * If region is NOT specified, a null-runtime-disambiguator is treated as if runtime-disambiguator was specified.
+ */
+ runtime_disambiguator_specified = ('#' != trigname->addr[trigname->len - 1]);
+ if (!runtime_disambiguator_specified && (NULL != reg))
+ { /* Region-name has been specified and no runtime-disambiguator specified. Need to further refine the
+ * search done by find_rtn_tabent to focus on the desired region in case multiple routines with the same
+ * trigger name (but different runtime-disambiguators) exist.
+ */
+ rtn_name.len = MIN(trigname->len, MAX_MIDENT_LEN);
+ rtn_name.addr = trigname->addr;
+ if (!reg->open)
+ gv_init_reg(reg); /* Open the region before obtaining "csa" */
+ regcsa = &FILE_INFO(reg)->s_addrs;
+ assert('#' == rtn_name.addr[rtn_name.len - 1]);
+ for ( ; rttabent <= rtn_names_end; rttabent++)
+ {
+ if ((rttabent->rt_name.len < rtn_name.len) || memcmp(rttabent->rt_name.addr, rtn_name.addr, rtn_name.len))
+ { /* Past the list of routines with same name as trigger but different runtime disambiguators */
+ rtn_vector = NULL;
+ break;
+ }
+ rtn_vector = rttabent->rt_adr;
+ trigdsc = (gv_trigger_t *)rtn_vector->trigr_handle;
+ gvt_trigger = trigdsc->gvt_trigger;
+ gvt = gvt_trigger->gv_target;
+ /* Target region and trigger routine's region do not match, continue */
+ if (gvt->gd_csa != regcsa)
+ continue;
+ /* Check if global name associated with the trigger is indeed mapped to the corresponding region
+ * by the gld. If not treat this case as if the trigger is invisible and move on
+ */
+ gbl.addr = gvt->gvname.var_name.addr;
+ gbl.len = gvt->gvname.var_name.len;
+ TP_CHANGE_REG_IF_NEEDED(gvt->gd_csa->region);
+ csa = cs_addrs;
+ csd = csa->hdr;
+ COMPUTE_HASH_MNAME(&gvt->gvname);
+ GV_BIND_NAME_ONLY(gd_header, &gvt->gvname, gvnh_reg); /* does tp_set_sgm() */
+ if (((NULL == gvnh_reg->gvspan) && (gv_cur_region != reg))
+ || ((NULL != gvnh_reg->gvspan) && !gvnh_spanreg_ismapped(gvnh_reg, gd_header, reg)))
+ continue;
+ /* Target region and trigger routine's region match, break (this check is a formality) */
+ if (gvt->gd_csa == regcsa)
+ break;
+ }
+ }
+ csa = NULL;
+ if (NULL == rtn_vector)
+ { /* If runtime disambiguator was specified and routine is not found, look no further.
+ * Otherwise, look for it in the #t global of any (or specified) region in current gbldir.
+ */
+ DBGTRIGR((stderr, "trigger_source_raov: find trigger by name without disambiguator\n"));
+ if (runtime_disambiguator_specified
+ || (TRIG_FAILURE == trigger_source_raov_trigload(trigname, &trigdsc, reg)))
+ {
+ RESTORE_TRIGGER_REGION_INFO(save_currkey);
+ ISSUE_TRIGNAMENF_ERROR_IF_APPROPRIATE(trigname);
return TRIG_FAILURE_RC;
+ }
+ rtn_vector = trigdsc->rtn_desc.rt_adr;
} else
{ /* Have a routine header addr. From that we can get the gv_trigger_t descriptor and from that, the
- * gvt_trigger and other necessaries
+ * gvt_trigger and other necessities.
*/
+ DBGTRIGR((stderr, "trigger_source_raov: routine header found, now load it\n"));
trigdsc = (gv_trigger_t *)rtn_vector->trigr_handle;
gvt_trigger = trigdsc->gvt_trigger; /* We now know our base block now */
index = trigdsc - gvt_trigger->gv_trig_array + 1; /* We now know our trigger index value */
@@ -278,122 +428,116 @@ STATICFNDEF int trigger_source_raov(mstr *trigname, trigger_action trigger_op)
TP_CHANGE_REG_IF_NEEDED(gvt->gd_csa->region);
csa = cs_addrs;
csd = csa->hdr;
- assert(csd == cs_data);
- /* Verify trigger is current. Note we use CSA for this check since within this transaction we could have multiple
- * triggers from the same global in flight preventing us from reloading a trigger. By checking CSA, we at least get
- * a consistent trigger view and depend on CSA being checked as current in op_tcommit.
- */
- triggers_reloaded = FALSE;
- SHM_READ_MEMORY_BARRIER;
- tp_set_sgm();
- db_trigger_cycle_mismatch = (csa->db_trigger_cycle != gvt->db_trigger_cycle);
- ztrig_cycle_mismatch = (csa->db_dztrigger_cycle && (gvt->db_dztrigger_cycle != csa->db_dztrigger_cycle));
- if (db_trigger_cycle_mismatch || ztrig_cycle_mismatch)
- { /* The process' view of the triggers is stale. We cannot proceed unless the triggers get reloaded.
- * If triggers have been driven for this global in this transaction, we have to throw a restart. To
- * reload and go if triggers have already been driven creates a potential consistency issues plus
- * the possibility that we could remove a trigger actively running which will cause major issues
- * when the trigger returns.
- *
- * To prevent these sort of issues, we compare the local_tn value when the last trigger was driven
- * in this global (recorded by gtm_trigger() in gvt->trig_local_tn) to the current local_tn value.
- * If the same, we have to restart. Else, we can reload the triggers and keep going.
- *
- * Triggers can be invoked only by GT.M and Update process. Out of these, we expect only
- * GT.M to see restarts due to concurrent trigger changes. Update process is the only
- * updater on the secondary so we dont expect it to see any concurrent trigger changes
- * Assert accordingly. Note similar asserts occur in t_end.c and tp_tend.c.
+ if (runtime_disambiguator_specified && (NULL != reg))
+ { /* Runtime-disambiguator has been specified and routine was found. But region-name-disambiguator
+ * has also been specified. Check if found routine is indeed in the specified region. If not
+ * treat it as a failure to find the trigger.
*/
- DBGTRIGR((stderr, "trigger_source_raov: Trigger cycle difference detected - db_trigger_cycle - "
- "csa: %d, csd: %d, gvt: %d db_ztrigger_cycle: csa: %d, gvt: %d\n",
- csa->db_trigger_cycle, csd->db_trigger_cycle, gvt->db_trigger_cycle,
- csa->db_dztrigger_cycle, gvt->db_dztrigger_cycle));
- assert(IS_GTM_IMAGE);
- if ((local_tn == gvt->trig_local_tn) && db_trigger_cycle_mismatch)
- { /* Already dispatched trigger for this gvn in this transaction - must restart. But do so ONLY
- * if the process' trigger view changed because of a concurrent trigger load/unload and NOT
- * because of $ZTRIGGER as part of this transaction as that could cause unintended restarts.
- */
- assert(CDB_STAGNATE > t_tries);
- DBGTRIGR((stderr, "trigger_source_raov: throwing TP restart\n"));
- t_retry(cdb_sc_triggermod);
- }
- cycle_start = csa->db_trigger_cycle;
- gvtr_db_read_hasht(csa);
- gvt_trigger = gvt->gvt_trigger;
- if (NULL == gvt_trigger)
- { /* No triggers were loaded for this region (all gone now) */
- CLEAR_IMPLICIT_TP_BEFORE_ERROR;
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TRIGNAMENF, 2, trigname->len, trigname->addr);
+ if (!reg->open)
+ gv_init_reg(reg);
+ if (&FILE_INFO(reg)->s_addrs != csa)
+ {
+ RESTORE_TRIGGER_REGION_INFO(save_currkey);
+ ISSUE_TRIGNAMENF_ERROR_IF_APPROPRIATE(trigname);
+ return TRIG_FAILURE_RC;
}
- gvt->db_trigger_cycle = cycle_start;
- gvt->db_dztrigger_cycle = csa->db_dztrigger_cycle;
- DBGTRIGR((stderr, "trigger_source_raov: triggers reloaded - "
- "gvt->db_trigger_cycle updated to %d\n", gvt->db_trigger_cycle));
- if (TRIG_FAILURE == trigger_source_raov_trigload(trigname, &trigdsc))
+ /* Check if global name is indeed mapped to this region by the gld. If not treat this case as
+ * if the trigger is invisible and issue an error
+ */
+ COMPUTE_HASH_MNAME(&gvt->gvname);
+ GV_BIND_NAME_ONLY(gd_header, &gvt->gvname, gvnh_reg); /* does tp_set_sgm() */
+ if (((NULL == gvnh_reg->gvspan) && (gv_cur_region != reg))
+ || ((NULL != gvnh_reg->gvspan) && !gvnh_spanreg_ismapped(gvnh_reg, gd_header, reg)))
+ {
+ RESTORE_TRIGGER_REGION_INFO(save_currkey);
+ ISSUE_TRIGNAMENF_ERROR_IF_APPROPRIATE(trigname);
return TRIG_FAILURE_RC;
- triggers_reloaded = TRUE;
- } else
- DBGTRIGR((stderr, "trigger_source_raov: trigger validated\n"));
- /* Only proceed with this next section at this point if triggers have not been reloaded. If they have
- * been reloaded, the rtn_vector address will have changed causing issues in this section. In that case,
- * we just need to fall out of this section to the common section which rebuilds things as necessary.
- */
- if (!triggers_reloaded)
- { /* Triggers were not reloaded - see if we need to load the source or not */
- if (TRIGGER_COMPILE == trigger_op)
- { /* This trigger has been verified so if it is already compiled, we are done */
- if (NULL != trigdsc->rtn_desc.rt_adr)
- return 0;
}
- /* Else we need the trigger source loaded */
- if (0 == ((gv_trigger_t *)rtn_vector->trigr_handle)->xecute_str.str.len)
+ }
+ DBGTRIGR((stderr, "trigger_source_raov: existing trigger routine has %d bytes of source\n",
+ ((gv_trigger_t *)rtn_vector->trigr_handle)->xecute_str.str.len));
+ assert(csd == cs_data);
+ tp_set_sgm();
+ /* If we are in the final retry, ensure we dont rely on stale triggers as we cannot afford any restarts now */
+ if (CDB_STAGNATE <= t_tries)
+ {
+ ztrig_cycle_mismatch = (csa->db_dztrigger_cycle && (gvt->db_dztrigger_cycle != csa->db_dztrigger_cycle));
+ db_trigger_cycle_mismatch = (csa->db_trigger_cycle != gvt->db_trigger_cycle);
+ needs_reload = (db_trigger_cycle_mismatch || ztrig_cycle_mismatch);
+ DBGTRIGR((stderr, "trigger_source_raov: ztrig_cycle_mismatch=%d\tdb_trigger_cycle_mismatch=%d\treload?%d\n",
+ ztrig_cycle_mismatch, db_trigger_cycle_mismatch, needs_reload));
+ if (needs_reload && (TRIG_FAILURE == trigger_source_raov_trigload(trigname, &trigdsc, reg)))
{
- SET_GVTARGET_TO_HASHT_GBL(csa);
- INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
- assert(0 == trigdsc->xecute_str.str.len); /* Make sure not replacing/losing a buffer */
- i2mval(&trig_index, index);
- xecute_buff.addr = trigger_gbl_fill_xecute_buffer(gbl.addr, gbl.len, &trig_index, NULL,
- (int4 *)&xecute_buff.len);
- trigdsc->xecute_str.str = xecute_buff;
+ RESTORE_TRIGGER_REGION_INFO(save_currkey);
+ ISSUE_TRIGNAMENF_ERROR_IF_APPROPRIATE(trigname);
+ return TRIG_FAILURE_RC;
}
}
- /* We have referenced this trigger's source. Mark it in gv_target so we know if we have to restart later
- * if trigger changes instead of just reloading it on-the-fly.
+ /* Now that this TP has relied on this process' current trigger view, ensure that any later action in the same
+ * TP that detects and reloads newer triggers (e.g. trigger invocation) restarts the entire TP transaction.
*/
gvt->trig_local_tn = local_tn;
+
+ /* If this trigger is already compiled, we are done */
+ if ((TRIGGER_COMPILE == trigger_op) && (NULL != trigdsc->rtn_desc.rt_adr))
+ {
+ DBGTRIGR((stderr, "trigger_source_raov: trigger already compiled, all done\n"));
+ RESTORE_TRIGGER_REGION_INFO(save_currkey);
+ *rtn_vec = rtn_vector;
+ return 0;
+ }
+ /* Else load the trigger source as needed */
+ if (0 == trigdsc->xecute_str.str.len)
+ {
+ DBGTRIGR((stderr, "trigger_source_raov: get the source\n"));
+ SET_GVTARGET_TO_HASHT_GBL(csa);
+ INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
+ assert(0 == trigdsc->xecute_str.str.len); /* Make sure not replacing/losing a buffer */
+ i2mval(&trig_index, index);
+ xecute_buff.addr = trigger_gbl_fill_xecute_buffer(gbl.addr, gbl.len, &trig_index, NULL,
+ (int4 *)&xecute_buff.len);
+ trigdsc->xecute_str.str = xecute_buff;
+ }
}
/* If the trigger is not already compiled, it needs to be since the routine header is the method for obtaining the
* trigger descriptor. If routine is already compiled, we don't need to compile it again.
*/
if ((TRIGGER_COMPILE == trigger_op) || (NULL == trigdsc->rtn_desc.rt_adr))
{
+ DBGTRIGR((stderr, "trigger_source_raov: compile it\n"));
if (0 != gtm_trigger_complink(trigdsc, TRUE))
{
PRN_ERROR; /* Flush out any compiler messages for compile record */
rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRIGCOMPFAIL, 2,
- trigdsc->rtn_desc.rt_name.len, trigdsc->rtn_desc.rt_name.addr);
+ trigdsc->rtn_desc.rt_name.len - 1, trigdsc->rtn_desc.rt_name.addr);
}
assert(trigdsc->rtn_desc.rt_adr);
assert(trigdsc->rtn_desc.rt_adr == CURRENT_RHEAD_ADR(trigdsc->rtn_desc.rt_adr));
/* If compile only, the source code is no longer needed so release it */
if ((TRIGGER_COMPILE == trigger_op) && (0 < trigdsc->xecute_str.str.len))
{
+ DBGTRIGR((stderr, "trigger_source_raov: free the source\n"));
free(trigdsc->xecute_str.str.addr);
trigdsc->xecute_str.str.addr = NULL;
trigdsc->xecute_str.str.len = 0;
}
+ rtn_vector = trigdsc->rtn_desc.rt_adr;
} else
{
assert(TRIGGER_SRC_LOAD == trigger_op);
assert(NULL != trigdsc->xecute_str.str.addr);
assert(0 < trigdsc->xecute_str.str.len);
}
+ RESTORE_TRIGGER_REGION_INFO(save_currkey);
+ assert(rtn_vector);
+ assert(trigdsc == rtn_vector->trigr_handle);
+ assert(((gv_trigger_t *)rtn_vector->trigr_handle)->xecute_str.str.len);
+ *rtn_vec = rtn_vector;
return 0;
}
/* Routine called when need triggers loaded for a given global */
-STATICFNDEF boolean_t trigger_source_raov_trigload(mstr *trigname, gv_trigger_t **ret_trigdsc)
+STATICFNDEF boolean_t trigger_source_raov_trigload(mstr *trigname, gv_trigger_t **ret_trigdsc, gd_region *reg)
{
mval val;
char *ptr;
@@ -404,25 +548,21 @@ STATICFNDEF boolean_t trigger_source_raov_trigload(mstr *trigname, gv_trigger_t
gvt_trigger_t *gvt_trigger;
mstr xecute_buff;
mname_entry gvname;
- int index;
+ int index, n;
mval trig_index;
gv_trigger_t *trigdsc;
uint4 cycle_start;
gvnh_reg_t *gvnh_reg;
- DCL_THREADGBL_ACCESS;
+ boolean_t name_not_found;
- SETUP_THREADGBL_ACCESS;
- /* Find region trigger name is in */
- if (!trigger_read_name_entry(trigname, &val))
- { /* Trigger name not found - nothing we can do */
- if (!TREF(op_fntext_tlevel))
- {
- CLEAR_IMPLICIT_TP_BEFORE_ERROR;
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TRIGNAMENF, 2, trigname->len, trigname->addr);
- }
- return TRIG_FAILURE;
- }
+ assert(dollar_tlevel);
+ DBGTRIGR((stderr, "trigger_source_raov_trigload: entry for %s\n", trigname->addr));
+ /* Find region trigger name is in. If "region-name" has been specified, find only in that region. */
+ name_not_found = !trigger_name_search(trigname->addr, trigname->len, &val, ®);
+ if (name_not_found)
+ return TRIG_FAILURE; /* Trigger name not found - nothing we can do */
/* Extract region name and trigger index number from result */
+ assert(NULL != reg);
ptr = val.str.addr;
len = STRLEN(ptr); /* Do it this way since "val" has multiple fields null separated */
ptr += len;
@@ -433,6 +573,14 @@ STATICFNDEF boolean_t trigger_source_raov_trigload(mstr *trigname, gv_trigger_t
gvname.var_name.len = len;
COMPUTE_HASH_MNAME(&gvname);
GV_BIND_NAME_ONLY(gd_header, &gvname, gvnh_reg); /* does tp_set_sgm() */
+ if (NULL != gvnh_reg->gvspan)
+ {
+ assert(gvnh_spanreg_ismapped(gvnh_reg, gd_header, reg)); /* "trigger_name_search" would have ensured this */
+ GV_BIND_SUBSREG(gd_header, reg, gvnh_reg); /* sets gv_target/gv_cur_region/cs_addrs */
+ } else
+ { /* gv_target/gv_cur_region/cs_addrs would have been set by GV_BIND_NAME_ONLY */
+ assert(gv_cur_region == reg);
+ }
gvt = gv_target;
assert(cs_addrs == gvt->gd_csa);
csa = gvt->gd_csa;
@@ -443,15 +591,15 @@ STATICFNDEF boolean_t trigger_source_raov_trigload(mstr *trigname, gv_trigger_t
gvtr_db_read_hasht(csa);
gvt_trigger = gvt->gvt_trigger;
if (NULL == gvt_trigger)
- { /* No trigger were loaded for this region (all gone now) */
- CLEAR_IMPLICIT_TP_BEFORE_ERROR;
- rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRIGNAMENF, 2, trigname->len, trigname->addr);
+ {
+ if (CDB_STAGNATE > t_tries)
+ t_retry(cdb_sc_triggermod);
+ return TRIG_FAILURE; /* Return an error instead of TRIGDEFBAD */
}
gvt->db_trigger_cycle = cycle_start;
gvt->db_dztrigger_cycle = csa->db_dztrigger_cycle;
gvt->trig_local_tn = local_tn; /* Mark this trigger as being referenced in this transaction */
- DBGTRIGR((stderr, "trigger_source_raov_trigload: gvt->db_trigger_cycle updated to %d\n",
- gvt->db_trigger_cycle));
+ DBGTRIGR((stderr, "trigger_source_raov_trigload: gvt->db_trigger_cycle updated to %d\n", gvt->db_trigger_cycle));
SET_GVTARGET_TO_HASHT_GBL(csa);
INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
trigdsc = &gvt_trigger->gv_trig_array[index - 1];
diff --git a/sr_unix/trigger_source_read_andor_verify.h b/sr_unix/trigger_source_read_andor_verify.h
index 0f43204..8f65544 100644
--- a/sr_unix/trigger_source_read_andor_verify.h
+++ b/sr_unix/trigger_source_read_andor_verify.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2011 Fidelity Information Services, Inc *
+ * Copyright 2011, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -18,7 +18,7 @@ typedef enum
TRIGGER_COMPILE
} trigger_action;
-int trigger_source_read_andor_verify(mstr *trigname, trigger_action trigger_op);
+int trigger_source_read_andor_verify(mstr *trigname, trigger_action trigger_op, rhdtyp **rtn_vec);
#endif /* GTM_TRIGGER */
diff --git a/sr_unix/trigger_subs_def.h b/sr_unix/trigger_subs_def.h
index e17b73b..d58db8e 100644
--- a/sr_unix/trigger_subs_def.h
+++ b/sr_unix/trigger_subs_def.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2011 Fidelity Information Services, Inc *
+ * Copyright 2011, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -11,16 +11,24 @@
/* Define trigger subscript types/order. Used to define enum trig_subs_t in trigger.h
* and trigger_subs in mtables.c.
+ *
+ * Note : The order of lines below matters to a great extent. For example TRIGNAME needs to be before CMD
+ * which in turn needs to be before XECUTE as that otherwise affects the output of MUPIP TRIGGER -SELECT.
+ * There are other requirements like this in MUPIP TRIGGER -SELECT output format.
+ * In addition, BHASH and LHASH need to be at the end of this list. The #define of NUM_SUBS relies on this.
*/
-TRIGGER_SUBDEF(TRIGNAME),
-TRIGGER_SUBDEF(GVSUBS),
-TRIGGER_SUBDEF(CMD),
-TRIGGER_SUBDEF(OPTIONS),
-TRIGGER_SUBDEF(DELIM),
-TRIGGER_SUBDEF(ZDELIM),
-TRIGGER_SUBDEF(PIECES),
-TRIGGER_SUBDEF(XECUTE),
-TRIGGER_SUBDEF(CHSET),
-TRIGGER_SUBDEF(LHASH),
-TRIGGER_SUBDEF(BHASH)
+/*
+TRIGGER_SUBSDEF (trigsubstype, subsname, litmvalname, trigfilequal, partofhash )
+*/
+TRIGGER_SUBSDEF (TRIGNAME_SUB, "TRIGNAME", literal_trigname, "-name=", TRSBS_IN_NONE )
+TRIGGER_SUBSDEF (GVSUBS_SUB, "GVSUBS", literal_gvsubs, "", (TRSBS_IN_LHASH | TRSBS_IN_BHASH) )
+TRIGGER_SUBSDEF (CMD_SUB, "CMD", literal_cmd, "-commands=", TRSBS_IN_NONE )
+TRIGGER_SUBSDEF (OPTIONS_SUB, "OPTIONS", literal_options, "-options=", TRSBS_IN_NONE )
+TRIGGER_SUBSDEF (DELIM_SUB, "DELIM", literal_delim, "-delim=", TRSBS_IN_BHASH )
+TRIGGER_SUBSDEF (ZDELIM_SUB, "ZDELIM", literal_zdelim, "-zdelim=", TRSBS_IN_BHASH )
+TRIGGER_SUBSDEF (PIECES_SUB, "PIECES", literal_pieces, "-pieces=", TRSBS_IN_BHASH )
+TRIGGER_SUBSDEF (XECUTE_SUB, "XECUTE", literal_xecute, "-xecute=", (TRSBS_IN_LHASH | TRSBS_IN_BHASH) )
+TRIGGER_SUBSDEF (CHSET_SUB, "CHSET", literal_chset, "", TRSBS_IN_NONE )
+TRIGGER_SUBSDEF (BHASH_SUB, "BHASH", literal_bhash, "", TRSBS_IN_NONE )
+TRIGGER_SUBSDEF (LHASH_SUB, "LHASH", literal_lhash, "", TRSBS_IN_NONE )
diff --git a/sr_unix/trigger_trgfile.c b/sr_unix/trigger_trgfile.c
index 071cc63..3f103da 100644
--- a/sr_unix/trigger_trgfile.c
+++ b/sr_unix/trigger_trgfile.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2013 Fidelity Information Services, Inc *
+ * Copyright 2010, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -24,9 +24,9 @@
#include "hashtab_str.h"
#include "trigger_trgfile_protos.h"
#include "trigger_delete_protos.h"
+#include "trigger.h" /* needed by "trigger_update_protos.h" for trig_stats_t prototype */
#include "trigger_update_protos.h"
#include "file_input.h"
-#include "trigger.h"
#include "op.h" /* for op_tstart */
#include "op_tcommit.h"
#include "gdscc.h" /* needed for tp.h */
@@ -46,17 +46,22 @@
#include "t_retry.h"
#include "gtmimagename.h"
-#define TRIG_ERROR_RETURN \
-{ \
- if (lcl_implicit_tpwrap) \
- { /* only if we were implicitly wrapped */ \
- assert(dollar_tlevel); \
- assert(donot_INVOKE_MUMTSTART); \
- DEBUG_ONLY(donot_INVOKE_MUMTSTART = FALSE); \
- OP_TROLLBACK(-1); /* Unroll implicit TP */ \
- REVERT; \
- } \
- return TRIG_FAILURE; \
+#define TRIG_ERROR_RETURN \
+{ \
+ DCL_THREADGBL_ACCESS; \
+ \
+ SETUP_THREADGBL_ACCESS; \
+ if (lcl_implicit_tpwrap) \
+ { /* only if we were implicitly wrapped */ \
+ assert(dollar_tlevel); \
+ assert(donot_INVOKE_MUMTSTART); \
+ DEBUG_ONLY(donot_INVOKE_MUMTSTART = FALSE); \
+ /* Print $ztrigger/mupip-trigger output before rolling back TP */ \
+ TP_ZTRIGBUFF_PRINT; \
+ OP_TROLLBACK(-1); /* Unroll implicit TP */ \
+ REVERT; \
+ } \
+ return TRIG_FAILURE; \
}
GBLREF sgm_info *first_sgm_info;
@@ -74,15 +79,13 @@ GBLREF unsigned char t_fail_hist[CDB_MAX_TRIES];
GBLREF boolean_t donot_INVOKE_MUMTSTART;
#endif
-LITREF mval literal_hasht;
-
error_def(ERR_DBROLLEDBACK);
error_def(ERR_ZFILNMBAD);
STATICFNDEF boolean_t trigger_trgfile_tpwrap_helper(char *trigger_filename, uint4 trigger_filename_len, boolean_t noprompt,
boolean_t lcl_implicit_tpwrap)
{
- boolean_t all_triggers_error;
+ boolean_t trigger_error;
uint4 i;
io_pair io_save_device;
io_pair io_trigfile_device;
@@ -95,18 +98,22 @@ STATICFNDEF boolean_t trigger_trgfile_tpwrap_helper(char *trigger_filename, uint
char *values[NUM_SUBS];
unsigned short value_len[NUM_SUBS];
- all_triggers_error = FALSE;
if (lcl_implicit_tpwrap)
ESTABLISH_RET(trigger_tpwrap_ch, TRIG_FAILURE); /* Return through here is a failure */
io_save_device = io_curr_device;
- file_input_init(trigger_filename, trigger_filename_len);
+ file_input_init(trigger_filename, trigger_filename_len, IOP_REWIND);
if (mupip_error_occurred)
+ {
+ assert(!memcmp(&io_curr_device, &io_save_device, SIZEOF(io_curr_device)));
+ io_curr_device = io_save_device; /* just in case in PRO */
TRIG_ERROR_RETURN;
+ }
io_trigfile_device = io_curr_device;
record_num = 0;
for (i = 0; NUM_STATS > i; i++)
trig_stats[i] = 0;
- while ((0 == io_curr_device.in->dollar.zeof) && (0 <= (len = file_input_get(&trigger_rec))))
+ trigger_error = FALSE;
+ while ((0 == io_curr_device.in->dollar.zeof) && (0 <= (len = file_input_get(&trigger_rec, 0))))
{
io_curr_device = io_save_device;
record_num++;
@@ -114,7 +121,9 @@ STATICFNDEF boolean_t trigger_trgfile_tpwrap_helper(char *trigger_filename, uint
util_out_print_gtmio("File !AD, Line !UL: ", NOFLUSH, trigger_filename_len, trigger_filename, record_num);
trigger_status = trigger_update_rec(trigger_rec, (uint4)len, noprompt, trig_stats, &io_trigfile_device,
&record_num);
- all_triggers_error |= (TRIG_FAILURE == trigger_status);
+ trigger_error |= (TRIG_FAILURE == trigger_status);
+ assert(!trigger_error || trig_stats[STATS_ERROR_TRIGFILE]);
+ assert(trigger_error || !trig_stats[STATS_ERROR_TRIGFILE]);
io_curr_device = io_trigfile_device;
}
if ((-1 == len) && (!io_curr_device.in->dollar.zeof))
@@ -122,44 +131,37 @@ STATICFNDEF boolean_t trigger_trgfile_tpwrap_helper(char *trigger_filename, uint
io_curr_device = io_save_device;
util_out_print_gtmio("File !AD, Line !UL: Line too long", FLUSH, trigger_filename_len, trigger_filename,
++record_num);
+ io_curr_device = io_trigfile_device;
}
file_input_close();
io_curr_device = io_save_device;
- if (all_triggers_error)
+ if (trigger_error)
{
util_out_print_gtmio("=========================================", FLUSH);
- util_out_print_gtmio("!UL trigger file entries matched existing triggers", FLUSH, trig_stats[STATS_UNCHANGED]);
- util_out_print_gtmio("!UL trigger file entries have errors", FLUSH, trig_stats[STATS_ERROR]);
+ util_out_print_gtmio("!UL trigger file entries have errors", FLUSH, trig_stats[STATS_ERROR_TRIGFILE]);
util_out_print_gtmio("!UL trigger file entries have no errors", FLUSH,
- trig_stats[STATS_ADDED] + trig_stats[STATS_DELETED] + trig_stats[STATS_MODIFIED]);
+ trig_stats[STATS_NOERROR_TRIGFILE] + trig_stats[STATS_UNCHANGED_TRIGFILE]);
util_out_print_gtmio("=========================================", FLUSH);
- TRIG_ERROR_RETURN;
- }
- if (lcl_implicit_tpwrap)
- {
- GVTR_OP_TCOMMIT(cdb_status);
- if (cdb_sc_normal != cdb_status)
- t_retry(cdb_status); /* won't return */
- REVERT;
+ TRIG_ERROR_RETURN; /* rollback the trigger transaction due to errors and return */
}
- if ((0 == trig_stats[STATS_ERROR])
- && (0 != (trig_stats[STATS_ADDED] + trig_stats[STATS_DELETED] + trig_stats[STATS_UNCHANGED]
- + trig_stats[STATS_MODIFIED])))
+ if (trig_stats[STATS_ADDED] + trig_stats[STATS_DELETED] + trig_stats[STATS_UNCHANGED_TRIGFILE] + trig_stats[STATS_MODIFIED])
{
util_out_print_gtmio("=========================================", FLUSH);
util_out_print_gtmio("!UL triggers added", FLUSH, trig_stats[STATS_ADDED]);
util_out_print_gtmio("!UL triggers deleted", FLUSH, trig_stats[STATS_DELETED]);
- util_out_print_gtmio("!UL trigger file entries not changed", FLUSH, trig_stats[STATS_UNCHANGED]);
util_out_print_gtmio("!UL triggers modified", FLUSH, trig_stats[STATS_MODIFIED]);
+ util_out_print_gtmio("!UL trigger file entries did update database trigger content",
+ FLUSH, trig_stats[STATS_NOERROR_TRIGFILE]);
+ util_out_print_gtmio("!UL trigger file entries did not update database trigger content",
+ FLUSH, trig_stats[STATS_UNCHANGED_TRIGFILE]);
util_out_print_gtmio("=========================================", FLUSH);
- } else if (0 != trig_stats[STATS_ERROR])
+ }
+ if (lcl_implicit_tpwrap)
{
- util_out_print_gtmio("=========================================", FLUSH);
- util_out_print_gtmio("!UL trigger file entries matched existing triggers", FLUSH, trig_stats[STATS_UNCHANGED]);
- util_out_print_gtmio("!UL trigger file entries have errors", FLUSH, trig_stats[STATS_ERROR]);
- util_out_print_gtmio("!UL trigger file entries have no errors", FLUSH,
- trig_stats[STATS_ADDED] + trig_stats[STATS_DELETED] + trig_stats[STATS_MODIFIED]);
- util_out_print_gtmio("=========================================", FLUSH);
+ GVTR_OP_TCOMMIT(cdb_status); /* commit the trigger transaction */
+ if (cdb_sc_normal != cdb_status)
+ t_retry(cdb_status); /* won't return */
+ REVERT;
}
return TRIG_SUCCESS;
}
@@ -168,14 +170,13 @@ boolean_t trigger_trgfile_tpwrap(char *trigger_filename, uint4 trigger_filename_
{
boolean_t trigger_status = TRIG_FAILURE;
mval ts_mv;
- int loopcnt;
+ int loopcnt, utilbuff_len;
struct stat statbuf;
DEBUG_ONLY(unsigned int lcl_t_tries;)
enum cdb_sc failure;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
-
ts_mv.mvtype = MV_STR;
ts_mv.str.len = 0;
ts_mv.str.addr = NULL;
@@ -183,12 +184,19 @@ boolean_t trigger_trgfile_tpwrap(char *trigger_filename, uint4 trigger_filename_
assert('\0' == trigger_filename[trigger_filename_len]); /* should have been made sure by caller */
if (-1 == Stat(trigger_filename, &statbuf))
{
- util_out_print_gtmio("Invalid file name: !AD: !AZ", FLUSH, trigger_filename_len, trigger_filename, STRERROR(errno));
+ DEBUG_ONLY(TREF(gtmio_skip_tlevel_assert) = TRUE;)
+ util_out_print_gtmio("Invalid file name: !AD: !AZ",
+ FLUSH, trigger_filename_len, trigger_filename, STRERROR(errno));
+ DEBUG_ONLY(TREF(gtmio_skip_tlevel_assert) = FALSE;)
+ TP_ZTRIGBUFF_PRINT; /* Print $ztrigger/mupip-trigger output before returning */
return TRUE; /* Failure */
} else if (!S_ISREG(statbuf.st_mode))
{
- util_out_print_gtmio("Invalid file name: !AD: Not a proper input file", FLUSH, trigger_filename_len,
- trigger_filename);
+ DEBUG_ONLY(TREF(gtmio_skip_tlevel_assert) = TRUE;)
+ util_out_print_gtmio("Invalid file name: !AD: Not a proper input file",
+ FLUSH, trigger_filename_len, trigger_filename);
+ DEBUG_ONLY(TREF(gtmio_skip_tlevel_assert) = FALSE;)
+ TP_ZTRIGBUFF_PRINT; /* Print $ztrigger/mupip-trigger output before returning */
return TRUE; /* Failure */
}
if (0 == dollar_tlevel)
@@ -199,7 +207,11 @@ boolean_t trigger_trgfile_tpwrap(char *trigger_filename, uint4 trigger_filename_
* below after a successful op_tcommit of the $ZTRIGGER operation. We cannot check that dollar_tlevel is zero
* since the op_tstart done below can be a nested sub-transaction
*/
- op_tstart((IMPLICIT_TSTART + IMPLICIT_TRIGGER_TSTART), TRUE, &ts_mv, 0); /* 0 ==> save no locals but RESTART OK */
+ op_tstart(IMPLICIT_TSTART, TRUE, &ts_mv, 0); /* 0 ==> save no locals but RESTART OK */
+ /* Note down length of unprocessed util_out buffer */
+ assert(NULL != TREF(util_outptr));
+ utilbuff_len = INTCAST(TREF(util_outptr) - TREF(util_outbuff_ptr));
+ assert(OUT_BUFF_SIZE >= utilbuff_len);
/* The following for loop structure is similar to that in module trigger_update.c (function "trigger_update")
* and module gv_trigger.c (function gvtr_db_tpwrap) so any changes here might need to be reflected there as well.
*/
@@ -207,6 +219,8 @@ boolean_t trigger_trgfile_tpwrap(char *trigger_filename, uint4 trigger_filename_
{
assert(donot_INVOKE_MUMTSTART); /* Make sure still set */
DEBUG_ONLY(lcl_t_tries = t_tries);
+ TREF(ztrigbuffLen) = utilbuff_len; /* reset ztrig buffer at start of each try/retry */
+ TREF(util_outptr) = TREF(util_outbuff_ptr); /* Signal any unflushed text from previous try as gone */
trigger_status = trigger_trgfile_tpwrap_helper(trigger_filename, trigger_filename_len, noprompt, TRUE);
if (0 == dollar_tlevel)
break;
@@ -223,8 +237,6 @@ boolean_t trigger_trgfile_tpwrap(char *trigger_filename, uint4 trigger_filename_
* trigger load logic already takes care of doing INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED before doing the
* actual trigger load
*/
- util_out_print_gtmio("RESTART has invalidated this transaction's previous output. New output follows.",
- FLUSH);
/* We expect the above function to return with either op_tcommit or a tp_restart invoked.
* In the case of op_tcommit, we expect dollar_tlevel to be 0 and if so we break out of the loop.
* In the tp_restart case, we expect a maximum of 4 tries/retries and much lesser usually.
diff --git a/sr_unix/trigger_update.c b/sr_unix/trigger_update.c
index e641752..03c7870 100644
--- a/sr_unix/trigger_update.c
+++ b/sr_unix/trigger_update.c
@@ -34,7 +34,7 @@
#include "mv_stent.h" /* for COPY_SUBS_TO_GVCURRKEY macro */
#include "gvsub2str.h" /* for COPY_SUBS_TO_GVCURRKEY */
#include "format_targ_key.h" /* for COPY_SUBS_TO_GVCURRKEY */
-#include "targ_alloc.h" /* for SET_GVTARGET_TO_HASHT_GBL & SWITCH_TO_DEFAULT_REGION */
+#include "targ_alloc.h" /* for SET_GVTARGET_TO_HASHT_GBL */
#include "gdsblk.h"
#include "gdscc.h" /* needed for tp.h */
#include "gdskill.h" /* needed for tp.h */
@@ -56,10 +56,13 @@
#include "t_retry.h"
#include "gtmimagename.h"
#include "hashtab_mname.h"
+#include "zshow.h" /* for "format2disp" prototype */
+#include "compiler.h"
#include "t_begin.h"
#include "repl_msg.h"
#include "gtmsource.h"
-#include "zshow.h"
+#include "change_reg.h" /* for "change_reg" prototype */
+#include "gvnh_spanreg.h" /* for "gvnh_spanreg_subs_gvt_init" prototype */
GBLREF sgmnt_data_ptr_t cs_data;
GBLREF sgm_info *first_sgm_info;
@@ -80,40 +83,53 @@ GBLREF boolean_t donot_INVOKE_MUMTSTART;
#endif
error_def(ERR_DBROLLEDBACK);
+error_def(ERR_NEEDTRIGUPGRD);
+error_def(ERR_REMOTEDBNOTRIG);
error_def(ERR_TEXT);
error_def(ERR_TPRETRY);
error_def(ERR_TPRETRY);
error_def(ERR_TRIGDEFBAD);
error_def(ERR_TRIGLOADFAIL);
-error_def(ERR_TRIGMODINTP);
error_def(ERR_TRIGMODREGNOTRW);
-error_def(ERR_TRIGNOSPANGBL);
+error_def(ERR_TRIGNAMBAD);
LITREF mval gvtr_cmd_mval[GVTR_CMDTYPES];
LITREF int4 gvtr_cmd_mask[GVTR_CMDTYPES];
-LITREF mval literal_hasht;
LITREF mval literal_one;
LITREF char *trigger_subs[];
#define MAX_COMMANDS_LEN 32 /* Need room for S,K,ZK,ZTK + room for expansion */
#define MAX_OPTIONS_LEN 32 /* Need room for NOI,NOC + room for expansion */
#define MAX_TRIGNAME_SEQ_NUM 999999
+#define MAX_TRIG_DISPLEN 80 /* maximum length of a trigger that is displayed in case of errors */
#define LITERAL_M "M"
#define OPTIONS_I 1
#define OPTIONS_NOI 2
#define OPTIONS_C 4
#define OPTIONS_NOC 8
-#define ADD_UPDATE_NOCHANGE 0x00
+#define NO_NAME_CHANGE 0
+#define NO_CMD_CHANGE 0
+#define NO_OPTIONS_CHANGE 0
+
#define ADD_UPDATE_NAME 0x01
#define ADD_UPDATE_CMDS 0x02
#define ADD_UPDATE_OPTIONS 0x04
+
#define SUB_UPDATE_NAME 0x10
#define SUB_UPDATE_CMDS 0x20
-#define SUB_UPDATE_OPTIONS 0x40
-#define SUB_UPDATE_NOCHANGE 0x00
#define DELETE_REC 0x80
+/* Defines macros for types of triggers; one is SET type triggers, one is Non-SET type triggers */
+#define OPR_KILL 0
+#define OPR_SET 1
+#define NUM_OPRS 2
+#define OPR_SETKILL 2
+
+#define SEQ_SUCCESS 0
+
+#define MAX_HASH_LEN MAX_HASH_INDEX_LEN + 1 + MAX_DIGITS_IN_INT
+
#define BUILD_COMMAND_BITMAP(BITMAP, COMMANDS) \
{ \
char lcl_cmds[MAX_COMMANDS_LEN + 1]; \
@@ -167,24 +183,24 @@ LITREF char *trigger_subs[];
} while (lcl_ptr = strtok_r(NULL, ",", &strtok_ptr)); \
}
-#define COMMAND_BITMAP_TO_STR(COMMANDS, BITMAP, LEN) \
-{ \
- int count, cmdtype, lcl_len; \
- char *lcl_ptr; \
- \
- count = 0; \
- lcl_ptr = COMMANDS; \
- lcl_len = LEN; \
- for (cmdtype = 0; cmdtype < GVTR_CMDTYPES; cmdtype++) \
- { \
- if (gvtr_cmd_mask[cmdtype] & (BITMAP)) \
- { \
- ADD_COMMA_IF_NEEDED(count, lcl_ptr, lcl_len); \
- ADD_STRING(count, lcl_ptr, gvtr_cmd_mval[cmdtype].str.len, gvtr_cmd_mval[cmdtype].str.addr, lcl_len); \
- } \
- } \
- *lcl_ptr = '\0'; \
- LEN = STRLEN(COMMANDS); \
+#define COMMAND_BITMAP_TO_STR(COMMANDS, BITMAP, LEN) \
+{ \
+ int count, cmdtype, lcl_len; \
+ char *lcl_ptr; \
+ \
+ count = 0; \
+ lcl_ptr = COMMANDS; \
+ lcl_len = LEN; \
+ for (cmdtype = 0; cmdtype < GVTR_CMDTYPES; cmdtype++) \
+ { \
+ if (gvtr_cmd_mask[cmdtype] & (BITMAP)) \
+ { \
+ ADD_COMMA_IF_NEEDED(count, lcl_ptr, lcl_len); \
+ ADD_STRING(count, lcl_ptr, gvtr_cmd_mval[cmdtype].str.len, gvtr_cmd_mval[cmdtype].str.addr, lcl_len); \
+ } \
+ } \
+ *lcl_ptr = '\0'; \
+ LEN = STRLEN(COMMANDS); \
}
#define BUILD_OPTION_BITMAP(BITMAP, OPTIONS) \
@@ -262,13 +278,15 @@ LITREF char *trigger_subs[];
LEN = STRLEN(OPTIONS); \
}
-#define TOO_LONG_REC_KEY_ERROR_MSG \
-{ \
- trig_stats[STATS_ERROR]++; \
- if (KEY_TOO_LONG == result) \
- util_out_print_gtmio("^!AD trigger - key larger than max key size", FLUSH, trigvn_len, trigvn); \
- else \
- util_out_print_gtmio("^!AD trigger - value larger than max record size", FLUSH, trigvn_len, trigvn); \
+#define TOO_LONG_REC_KEY_ERROR_MSG \
+{ \
+ UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen); \
+ if (KEY_TOO_LONG == result) \
+ util_out_print_gtmio("Error : ^!AD trigger - key larger than max key size", \
+ FLUSH, disp_trigvn_len, disp_trigvn); \
+ else \
+ util_out_print_gtmio("Error : ^!AD trigger - value larger than max record size", \
+ FLUSH, disp_trigvn_len, disp_trigvn); \
}
#define IF_ERROR_THEN_TOO_LONG_ERROR_MSG_AND_RETURN_FAILURE(RESULT) \
@@ -276,30 +294,27 @@ LITREF char *trigger_subs[];
if (PUT_SUCCESS != RESULT) \
{ \
TOO_LONG_REC_KEY_ERROR_MSG; \
- return TRIG_FAILURE; \
+ return STATS_ERROR_TRIGFILE; \
} \
}
-#define TRIGGER_SAME_NAME_EXISTS_ERROR \
-{ \
- trig_stats[STATS_ERROR]++; \
- util_out_print_gtmio("a trigger named !AD already exists", FLUSH, value_len[TRIGNAME_SUB], values[TRIGNAME_SUB]); \
- return TRIG_FAILURE; \
-}
-
-/* This error macro is used for all definition errors where the target is ^#t(GVN,<index>,<required subscript>) */
-#define HASHT_GVN_DEFINITION_RETRY_OR_ERROR(INDEX,SUBSCRIPT,CSA) \
-{ \
- if (CDB_STAGNATE > t_tries) \
- t_retry(cdb_sc_triggermod); \
- else \
- { \
- assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number); \
- /* format "INDEX,SUBSCRIPT" of ^#t(GVN,INDEX,SUBSCRIPT) in the error message */ \
- SET_PARAM_STRING(util_buff, util_len, INDEX, SUBSCRIPT); \
- rts_error_csa(CSA_ARG(CSA) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn, \
- trigvn_len, trigvn, util_len, util_buff); \
- } \
+#define TRIGGER_SAME_NAME_EXISTS_ERROR(OPNAME, DISP_TRIGVN_LEN, DISP_TRIGVN) \
+{ \
+ assert(dollar_tlevel); \
+ if (CDB_STAGNATE > t_tries) \
+ { /* Directly jump to final retry since we cannot issue this error accurately \
+ * unless we are in the final retry. Dont waste time in intermediate tries. \
+ * But before then record the fact that the intermediate tries had normal status. \
+ */ \
+ for ( ; t_tries < (CDB_STAGNATE - 1); t_tries++) \
+ t_fail_hist[t_tries] = cdb_sc_normal; \
+ t_retry(cdb_sc_triggermod); \
+ } \
+ UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen); \
+ util_out_print_gtmio("Error : !AZ trigger on ^!AD not added as another trigger named !AD already exists", \
+ FLUSH, OPNAME, DISP_TRIGVN_LEN, DISP_TRIGVN, \
+ value_len[TRIGNAME_SUB], values[TRIGNAME_SUB]); \
+ return STATS_ERROR_TRIGFILE; \
}
/* This error macro is used for all definition errors where the target is ^#t(GVN,<#LABEL|#COUNT|#CYCLE>) */
@@ -351,37 +366,21 @@ STATICFNDEF int4 update_commands(char *trigvn, int trigvn_len, int trigger_index
new_trig_cmds, STRLEN(new_trig_cmds), result);
if (PUT_SUCCESS != result)
return result;
- if ((0 != (gvtr_cmd_mask[GVTR_CMDTYPE_SET] & orig_cmd_bm)) && (0 == (gvtr_cmd_mask[GVTR_CMDTYPE_SET] & new_cmd_bm)))
+ if ((gvtr_cmd_mask[GVTR_CMDTYPE_SET] & orig_cmd_bm) && !(gvtr_cmd_mask[GVTR_CMDTYPE_SET] & new_cmd_bm))
{ /* SET was removed from the commands, so delete the SET specific attributes */
- BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, mv_trig_indx, LITERAL_DELIM, LITERAL_DELIM_LEN);
+ BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, mv_trig_indx,
+ trigger_subs[DELIM_SUB], STRLEN(trigger_subs[DELIM_SUB]));
gvcst_kill(TRUE);
- BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, mv_trig_indx, LITERAL_ZDELIM, LITERAL_ZDELIM_LEN);
+ BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, mv_trig_indx,
+ trigger_subs[ZDELIM_SUB], STRLEN(trigger_subs[ZDELIM_SUB]));
gvcst_kill(TRUE);
- BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, mv_trig_indx, LITERAL_PIECES, LITERAL_PIECES_LEN);
+ BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, mv_trig_indx,
+ trigger_subs[PIECES_SUB], STRLEN(trigger_subs[PIECES_SUB]));
gvcst_kill(TRUE);
}
- trigger_incr_cycle(trigvn, trigvn_len);
return SUB_UPDATE_CMDS;
}
-STATICFNDEF int4 update_options(char *trigvn, int trigvn_len, int trigger_index, char *trig_options, char *option_value)
-{
- mval mv_trig_indx;
- int4 result;
- DCL_THREADGBL_ACCESS;
-
- SETUP_THREADGBL_ACCESS;
- if (!validate_label(trigvn, trigvn_len))
- return INVALID_LABEL;
- i2mval(&mv_trig_indx, trigger_index);
- SET_TRIGGER_GLOBAL_SUB_MSUB_SUB_STR(trigvn, trigvn_len, mv_trig_indx, trigger_subs[OPTIONS_SUB],
- STRLEN(trigger_subs[OPTIONS_SUB]), trig_options, STRLEN(trig_options), result);
- if (PUT_SUCCESS != result)
- return result;
- trigger_incr_cycle(trigvn, trigvn_len);
- return SUB_UPDATE_OPTIONS;
-}
-
STATICFNDEF int4 update_trigger_name(char *trigvn, int trigvn_len, int trigger_index, char *db_trig_name, char *tf_trig_name,
uint4 tf_trig_name_len)
{
@@ -392,52 +391,178 @@ STATICFNDEF int4 update_trigger_name(char *trigvn, int trigvn_len, int trigger_i
SETUP_THREADGBL_ACCESS;
retval = NO_NAME_CHANGE;
- if ((0 != tf_trig_name_len) && (tf_trig_name_len != STRLEN(db_trig_name) - 1)
- || (0 != memcmp(tf_trig_name, db_trig_name, tf_trig_name_len)))
+ if (tf_trig_name_len && (tf_trig_name_len != STRLEN(db_trig_name) - 1)
+ || memcmp(tf_trig_name, db_trig_name, tf_trig_name_len))
{
if (!validate_label(trigvn, trigvn_len))
return INVALID_LABEL;
i2mval(&mv_trig_indx, trigger_index);
tf_trig_name[tf_trig_name_len++] = TRIGNAME_SEQ_DELIM;
- SET_TRIGGER_GLOBAL_SUB_MSUB_SUB_STR(trigvn, trigvn_len, mv_trig_indx, LITERAL_TRIGNAME, STRLEN(LITERAL_TRIGNAME),
- tf_trig_name, tf_trig_name_len, result);
+ SET_TRIGGER_GLOBAL_SUB_MSUB_SUB_STR(trigvn, trigvn_len, mv_trig_indx,
+ trigger_subs[TRIGNAME_SUB], STRLEN(trigger_subs[TRIGNAME_SUB]), tf_trig_name, tf_trig_name_len, result);
if (PUT_SUCCESS != result)
return result;
cleanup_trigger_name(trigvn, trigvn_len, db_trig_name, STRLEN(db_trig_name));
- trigger_incr_cycle(trigvn, trigvn_len);
retval = ADD_UPDATE_NAME;
}
return retval;
}
-STATICFNDEF boolean_t check_unique_trigger_name(char *trigvn, int trigvn_len, char *trigger_name, uint4 trigger_name_len)
+/*
+ * Input: trigger_name and trigger_name_length
+ * [optional] srch_reg (when non-NULL this is the only region to search)
+ *
+ * Output: returns TRUE if trigger name is found, false if not.
+ * srch_reg set to the region the name was found in.
+ * val is the "<gbl>\0<trigindx>" string to which the name points
+ *
+ * This function is similar to check_unique_trigger_name_full(), but is only called from
+ * trigger_source_read_andor_verify()
+ */
+boolean_t trigger_name_search(char *trigger_name, uint4 trigger_name_len, mval *val, gd_region **srch_reg)
{
- gv_key save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
- gd_region *save_gv_cur_region;
- gv_namehead *save_gv_target;
- sgm_info *save_sgm_info_ptr;
- boolean_t status;
- mval val;
+ boolean_t name_found;
+ char *ptr, *ptr2;
+ gd_region *reg, *reg_top;
+ gd_region *save_gv_cur_region;
+ gv_key save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
+ gv_namehead *save_gv_target;
+ gvnh_reg_t *gvnh_reg;
+ int index, len;
+ mname_entry gvname;
+ sgm_info *save_sgm_info_ptr;
+
+ /* Example trigger name could be x#1#A:BREG to indicate trigger on global ^x with an autogenerated name x#1
+ * that exists in multiple regions and hence had a runtime disambiguator of x#1#A. The :BREG is a region-level
+ * disambiguator to indicate we want to focus on BREG region to search for triggers with the name x#1.
+ * We dont expect the input trigger name to contain the runtime and region-level disambiguator but in case both
+ * are present we treat it as if the runtime disambiguator was absent.
+ */
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ /* Remove trailing # (if any) in trigger name before searching in ^#t as it is not stored in the ^#t("#TNAME",...) node */
+ assert('#' == trigger_name[trigger_name_len - 1]);
+ if ('#' == trigger_name[trigger_name_len - 1])
+ trigger_name_len--;
+ /* We only check user supplied names for uniqueness. With autogenerated names it is possible for
+ * same name to exist in multiple regions (in case two globals with global name > 21 chars map to
+ * different regions and have one trigger per global name installed with auto-generated names.
+ * But even in that case, at most one auto-generated name per region is possible. So we have a limit
+ * on the max # of duplicated auto-generated names.
+ */
+ assert(0 < trigger_name_len);
+ SAVE_TRIGGER_REGION_INFO(save_currkey);
+ name_found = FALSE;
+ reg = *srch_reg;
+ if (NULL != reg)
+ reg_top = reg + 1; /* make sure we dont go in the for loop more than once */
+ else
+ {
+ reg = gd_header->regions;
+ reg_top = reg + gd_header->n_regions;
+ assert(reg < reg_top);
+ }
+ for ( ; reg < reg_top; reg++)
+ {
+ GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(reg);
+ if (NULL == cs_addrs) /* not BG or MM access method */
+ continue;
+ /* gv_target now points to ^#t in region "reg" */
+ if (0 == gv_target->root)
+ continue;
+ /* $get(^#t("#TNAME",trigger_name) */
+ BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trigger_name, trigger_name_len);
+ if (!gvcst_get(val))
+ continue;
+ ptr = val->str.addr;
+ ptr2 = memchr(ptr, '\0', val->str.len); /* Do it this way since "val" has multiple fields null separated */
+ if (NULL == ptr2)
+ { /* We expect $c(0) in the middle of ptr. If we dont find it, this is a restartable situation */
+ 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\""),
+ trigger_name_len, trigger_name);
+ }
+ len = ptr2 - ptr;
+ assert(('\0' == *ptr2) && (val->str.len > len));
+ ptr2++;
+ A2I(ptr2, val->str.addr + val->str.len, index);
+ gvname.var_name.addr = val->str.addr;
+ gvname.var_name.len = len;
+ /* Check if global name is indeed mapped to this region by the gld.
+ * If not treat this case as if the trigger is invisible to us i.e. move on to next region.
+ */
+ COMPUTE_HASH_MNAME(&gvname);
+ GV_BIND_NAME_ONLY(gd_header, &gvname, gvnh_reg); /* does tp_set_sgm() */
+ if (((NULL == gvnh_reg->gvspan) && (gv_cur_region != reg))
+ || ((NULL != gvnh_reg->gvspan) && !gvnh_spanreg_ismapped(gvnh_reg, gd_header, reg)))
+ continue;
+ *srch_reg = reg;
+ name_found = TRUE;
+ break;
+ }
+ RESTORE_TRIGGER_REGION_INFO(save_currkey);
+ return name_found;
+}
+
+/* Returns TRUE if name is NOT found. FALSE if name is found. If name is found, "val" holds the value of the found node */
+boolean_t check_unique_trigger_name_full(char **values, uint4 *value_len, mval *val, boolean_t *new_match,
+ char *trigvn, int trigvn_len, stringkey *kill_trigger_hash, stringkey *set_trigger_hash)
+{
+ boolean_t overall_name_found, this_name_found;
+ gd_region *reg, *reg_top;
+ gv_key save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
+ gd_region *save_gv_cur_region;
+ gv_namehead *save_gv_target;
+ sgm_info *save_sgm_info_ptr;
+ int set_index, kill_index;
+ boolean_t db_matched_set, db_matched_kill, full_match, trigger_exists;
+ mval setname, killname;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
DEBUG_ONLY(if (WBTEST_HELPOUT_TRIGNAMEUNIQ == gtm_white_box_test_case_number) return TRUE;)
- /* We only check user supplied names for uniqueness (since autogenerated names are unique). */
- if (0 == trigger_name_len)
+ /* We only check user supplied names for uniqueness. With autogenerated names it is possible for
+ * same name to exist in multiple regions (in case two globals with global name > 21 chars map to
+ * different regions and have one trigger per global name installed with auto-generated names.
+ * But even in that case, at most one auto-generated name per region is possible. So we have a limit
+ * on the max # of duplicated auto-generated names.
+ */
+ *new_match = TRUE;
+ if (0 == value_len[TRIGNAME_SUB])
return TRUE;
SAVE_TRIGGER_REGION_INFO(save_currkey);
- SWITCH_TO_DEFAULT_REGION;
- INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
- if (0 == gv_target->root)
+ overall_name_found = FALSE;
+ for (reg = gd_header->regions, reg_top = reg + gd_header->n_regions; reg < reg_top; reg++)
{
- RESTORE_TRIGGER_REGION_INFO(save_currkey);
- return TRUE;
+ GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(reg);
+ if (NULL == cs_addrs) /* not BG or MM access method */
+ continue;
+ /* gv_target now points to ^#t in region "reg" */
+ if (0 == gv_target->root)
+ continue;
+ /* $get(^#t("#TNAME",trigger_name) */
+ BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME),
+ values[TRIGNAME_SUB], value_len[TRIGNAME_SUB]);
+ this_name_found = gvcst_get(val);
+ if (this_name_found)
+ {
+ overall_name_found = TRUE;
+ trigger_exists = trigger_already_exists(trigvn, trigvn_len, values, value_len,
+ set_trigger_hash, kill_trigger_hash,
+ &set_index, &kill_index, &db_matched_set, &db_matched_kill,
+ &full_match, &setname, &killname);
+ if (!full_match)
+ {
+ *new_match = FALSE;
+ break;
+ }
+ }
}
- /* $get(^#t("#TNAME",trigger_name) */
- BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trigger_name, trigger_name_len);
- status = !gvcst_get(&val);
RESTORE_TRIGGER_REGION_INFO(save_currkey);
- return status;
+ return !overall_name_found;
}
STATICFNDEF int4 add_trigger_hash_entry(char *trigvn, int trigvn_len, char *cmd_value, int trigindx, boolean_t add_kill_hash,
@@ -452,19 +577,13 @@ STATICFNDEF int4 add_trigger_hash_entry(char *trigvn, int trigvn_len, char *cmd_
int num_len;
char *ptr;
int4 result;
- gv_key save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
- gd_region *save_gv_cur_region;
- gv_namehead *save_gv_target;
- sgm_info *save_sgm_info_ptr;
boolean_t set_cmp;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
- SAVE_TRIGGER_REGION_INFO(save_currkey);
- SWITCH_TO_DEFAULT_REGION;
- if (gv_cur_region->read_only)
- rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(gv_cur_region));
- INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
+ 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 */
set_cmp = (NULL != strchr(cmd_value, 'S'));
mv_indx_ptr = &mv_indx;
num_len = 0;
@@ -477,52 +596,52 @@ STATICFNDEF int4 add_trigger_hash_entry(char *trigvn, int trigvn_len, char *cmd_
len = trigvn_len + 1 + num_len;
if (set_cmp)
{
- MV_FORCE_UMVAL(&mv_hash, set_hash->hash_code);
- if (0 != gv_target->root)
- {
- BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, "", 0);
- op_zprevious(&mv_indx);
- hash_indx = (0 == mv_indx.str.len) ? 1 : (mval2i(mv_indx_ptr) + 1);
- } else
- hash_indx = 1;
- i2mval(&mv_indx, hash_indx);
- SET_TRIGGER_GLOBAL_SUB_MSUB_MSUB_STR(LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, mv_indx,
- name_and_index, len, result);
- if (PUT_SUCCESS != result)
+ if (set_hash->hash_code != kill_hash->hash_code)
{
- RESTORE_TRIGGER_REGION_INFO(save_currkey);
- return result;
+ MV_FORCE_UMVAL(&mv_hash, set_hash->hash_code);
+ if (gv_target->root)
+ {
+ BUILD_HASHT_SUB_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len,
+ LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, "", 0);
+ op_zprevious(&mv_indx);
+ hash_indx = (0 == mv_indx.str.len) ? 1 : (mval2i(mv_indx_ptr) + 1);
+ } else
+ hash_indx = 1;
+ i2mval(&mv_indx, hash_indx);
+ SET_TRIGGER_GLOBAL_SUB_SUB_MSUB_MSUB_STR(trigvn, trigvn_len,
+ LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, mv_indx, name_and_index, len, result);
+ if (PUT_SUCCESS != result)
+ return result;
}
+ /* else: the next block of code for kill hash processing will add this hashcode in ^#t("#TRHASH",...) */
} else
set_hash->hash_code = 0;
if (add_kill_hash)
{
MV_FORCE_UMVAL(&mv_hash, kill_hash->hash_code);
- if (0 != gv_target->root)
+ if (gv_target->root)
{
- BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, "", 0);
+ BUILD_HASHT_SUB_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len,
+ LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, "", 0);
op_zprevious(&mv_indx);
hash_indx = (0 == mv_indx.str.len) ? 1 : (mval2i(mv_indx_ptr) + 1);
} else
hash_indx = 1;
i2mval(&mv_indx, hash_indx);
- SET_TRIGGER_GLOBAL_SUB_MSUB_MSUB_STR(LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, mv_indx,
- name_and_index, len, result);
+ SET_TRIGGER_GLOBAL_SUB_SUB_MSUB_MSUB_STR(trigvn, trigvn_len,
+ LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, mv_indx, name_and_index, len, result);
if (PUT_SUCCESS != result)
- {
- RESTORE_TRIGGER_REGION_INFO(save_currkey);
return result;
- }
} else
kill_hash->hash_code = 0;
- RESTORE_TRIGGER_REGION_INFO(save_currkey);
return PUT_SUCCESS;
}
-STATICFNDEF boolean_t trigger_already_exists(char *trigvn, int trigvn_len, char **values, uint4 *value_len, int *set_index,
- int *kill_index, boolean_t *set_cmp_result, boolean_t *kill_cmp_result,
- boolean_t *full_match, stringkey *set_trigger_hash, stringkey *kill_trigger_hash,
- mval *setname, mval *killname)
+STATICFNDEF boolean_t trigger_already_exists(char *trigvn, int trigvn_len, char **values, uint4 *value_len, /* input parm */
+ stringkey *set_trigger_hash, stringkey *kill_trigger_hash, /* input parm */
+ int *set_index, int *kill_index, boolean_t *set_cmp_result, /* output parm */
+ boolean_t *kill_cmp_result, boolean_t *full_match, /* output parm */
+ mval *setname, mval *killname) /* output parm */
{
sgmnt_addrs *csa;
boolean_t db_has_K;
@@ -532,156 +651,147 @@ STATICFNDEF boolean_t trigger_already_exists(char *trigvn, int trigvn_len, char
boolean_t kill_cmp, kill_found;
int kill_indx;
boolean_t name_match;
- gv_key save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
- gd_region *save_gv_cur_region;
- gv_namehead *save_gv_target;
- sgm_info *save_sgm_info_ptr;
boolean_t set_cmp, set_found, set_name_match, kill_name_match;
int set_indx;
mval trigindx;
- unsigned char util_buff[MAX_TRIG_UTIL_LEN];
+ unsigned char util_buff[MAX_TRIG_UTIL_LEN]; /* needed for HASHT_GVN_DEFINITION_RETRY_OR_ERROR macro */
int4 util_len;
mval val;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
- SAVE_TRIGGER_REGION_INFO(save_currkey);
- SWITCH_TO_DEFAULT_REGION;
- INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
- /* test with SET and/or KILL hash */
+ assert(cs_addrs->hasht_tree == gv_target); /* should have been set up by caller */
+ assert(gv_target->root); /* should have been ensured by caller */
+ /* Test with BHASH or LHASH.
+ * ^#t("GBL",1,"CMD") could contain one or more of "S,K,ZK,ZTK,ZTR".
+ * Out of the 5 commands above, a S type trigger uses the "BHASH" hash value.
+ * Everything else (K, ZK, ZTK, ZTR) uses the "LHASH" value.
+ * An easy check of one of these 4 commands is a chek for the letter K or R.
+ */
set_cmp = (NULL != strchr(values[CMD_SUB], 'S'));
kill_cmp = ((NULL != strchr(values[CMD_SUB], 'K')) || (NULL != strchr(values[CMD_SUB], 'R')));
set_found = kill_found = set_name_match = kill_name_match = FALSE;
csa = cs_addrs;
if (set_cmp)
- { /* test for SET hash match if SET command specified */
- set_found = search_triggers(trigvn, trigvn_len, values, value_len, set_trigger_hash, &hash_indx, &set_indx, 0,
- TRUE);
+ { /* test for SET hash match if SET command specified */
+ set_found = search_triggers(trigvn, trigvn_len, values, value_len, set_trigger_hash, &hash_indx, &set_indx, TRUE);
if (set_found)
{
- RESTORE_TRIGGER_REGION_INFO(save_currkey);
i2mval(&trigindx, set_indx);
BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigindx, trigger_subs[TRIGNAME_SUB],
STRLEN(trigger_subs[TRIGNAME_SUB]));
if (!gvcst_get(setname)) /* There has to be a name value */
HASHT_GVN_DEFINITION_RETRY_OR_ERROR(set_indx, ",\"TRIGNAME\"", csa);
- set_name_match = ((value_len[TRIGNAME_SUB] == (setname->str.len - 1))
- && (0 == memcmp(setname->str.addr, values[TRIGNAME_SUB], value_len[TRIGNAME_SUB])));
+ setname->str.len--; /* remove the # at the tail of the trigger name */
+ set_name_match = ((value_len[TRIGNAME_SUB] == setname->str.len)
+ && !memcmp(setname->str.addr, values[TRIGNAME_SUB], value_len[TRIGNAME_SUB]));
}
- }
+ } else
+ set_indx = 0;
*set_cmp_result = set_found;
+ kill_indx = -1;
if (kill_cmp || !set_found)
- { /* if SET is not found OR KILL is specified in commands, test for KILL hash match */
- kill_found = search_triggers(trigvn, trigvn_len, values, value_len, kill_trigger_hash, &hash_indx, &kill_indx, 0,
- FALSE);
+ { /* if SET is not found OR KILL is specified in commands, test for KILL hash match */
+ kill_found = search_triggers(trigvn, trigvn_len, values, value_len, kill_trigger_hash,
+ &hash_indx, &kill_indx, FALSE);
if (kill_found)
{
- RESTORE_TRIGGER_REGION_INFO(save_currkey);
- i2mval(&trigindx, kill_indx);
- BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigindx, trigger_subs[CMD_SUB],
- STRLEN(trigger_subs[CMD_SUB]));
- if (!gvcst_get(&val)) /* There has to be a command string */
- HASHT_GVN_DEFINITION_RETRY_OR_ERROR(kill_indx, ",\"CMD\"", csa);
- db_has_S = (NULL != memchr(val.str.addr, 'S', val.str.len));
- db_has_K = ((NULL != memchr(val.str.addr, 'K', val.str.len)) ||
- (NULL != memchr(val.str.addr, 'R', val.str.len)));
- /* Below means
- * NOT ( Matched trigger has SET && New trigger has SET &&
- * NOT ( Matched trigger has SET + KILL && New trigger has SET + KILL ) )
- *
- * KILL is found if:
- * The matched trigger does not have a SET || The new trigger does not have a SET
- * But not if the matched trigger has a SET or KILL && the new trigger does not have a SET or KILL
- */
- kill_found = !(db_has_S && set_cmp && !(db_has_S && db_has_K && set_cmp && kill_cmp));
- /* $get(^#t(trigvn,trigindx,"TRIGNAME") */
- BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigindx, trigger_subs[TRIGNAME_SUB],
- STRLEN(trigger_subs[TRIGNAME_SUB]));
- if (!gvcst_get(killname)) /* There has to be a name string */
- HASHT_GVN_DEFINITION_RETRY_OR_ERROR(kill_indx, ",\"TRIGNAME\"", csa);
- kill_name_match = ((value_len[TRIGNAME_SUB] == (killname->str.len - 1))
- && (0 == memcmp(killname->str.addr, values[TRIGNAME_SUB], value_len[TRIGNAME_SUB])));
- }
- }
- /* Starting from the beginning:
- * Matching both set and kill, but for different records -- don't update the kill record, hence the FALSE
- * Matching a set implies matching a kill -- hence the ||
- */
- if (set_found && kill_found && (set_indx != kill_indx))
- {
- *kill_cmp_result = FALSE;
- *kill_index = kill_indx;
- } else
- {
- *kill_cmp_result = (kill_found || set_found);
- if (!set_found)
+ if (!set_found || (kill_indx != set_indx))
+ {
+ i2mval(&trigindx, kill_indx);
+ BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigindx, trigger_subs[CMD_SUB],
+ STRLEN(trigger_subs[CMD_SUB]));
+ if (!gvcst_get(&val)) /* There has to be a command string */
+ HASHT_GVN_DEFINITION_RETRY_OR_ERROR(kill_indx, ",\"CMD\"", csa);
+ /* val.str.addr would contain something like the following
+ * ^#t("GBL",1,"CMD")="S,K,ZK,ZTK,ZTR".
+ * Out of the 5 commands above, a S type trigger uses the "BHASH" hash value.
+ * Everything else (K, ZK, ZTK, ZTR) uses the "LHASH" value.
+ */
+ db_has_S = (NULL != memchr(val.str.addr, 'S', val.str.len));
+ db_has_K = ((NULL != memchr(val.str.addr, 'K', val.str.len))
+ || (NULL != memchr(val.str.addr, 'R', val.str.len)));
+ if (!kill_cmp)
+ kill_found = (db_has_K && !db_has_S);
+ /* $get(^#t(trigvn,trigindx,"TRIGNAME") */
+ BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigindx, trigger_subs[TRIGNAME_SUB],
+ STRLEN(trigger_subs[TRIGNAME_SUB]));
+ if (!gvcst_get(killname)) /* There has to be a name string */
+ HASHT_GVN_DEFINITION_RETRY_OR_ERROR(kill_indx, ",\"TRIGNAME\"", csa);
+ killname->str.len--; /* remove the # at the tail of the trigger name */
+ kill_name_match = ((value_len[TRIGNAME_SUB] == killname->str.len)
+ && !memcmp(killname->str.addr, values[TRIGNAME_SUB], value_len[TRIGNAME_SUB]));
+ if (set_cmp && !set_found && !db_has_S)
+ {
+ *setname = *killname;
+ set_indx = kill_indx;
+ }
+ } else
+ *killname = *setname;
+ } else
{
- setname->mvtype = MV_STR;
- setname->str.addr = killname->str.addr;
- setname->str.len = killname->str.len;
+ kill_indx = -1;
+ if (!set_found)
+ set_indx = 0;
}
+ if (set_cmp && (kill_indx == set_indx))
+ kill_indx = -1;
}
- *set_index = (set_found) ? set_indx : (kill_found) ? kill_indx : 0;
+ *kill_index = kill_indx;
+ *kill_cmp_result = kill_found ? TRUE : set_found;
+ *set_index = set_indx;
/* If there is both a set and a kill and the set components don't match, there is no name match no matter if the kill
* components match or not. If there is no set, then the name match is only based on the kill components.
*/
- *full_match = (set_cmp) ? set_name_match : kill_name_match;
- RESTORE_TRIGGER_REGION_INFO(save_currkey);
+ *full_match = (set_cmp ? set_name_match : kill_name_match);
return (set_found || kill_found);
}
-STATICFNDEF int4 add_trigger_cmd_attributes(char *trigvn, int trigvn_len, int trigger_index, char *trig_cmds, char **values,
- uint4 *value_len, boolean_t set_compare, boolean_t kill_compare, stringkey *kill_hash, stringkey *set_hash)
+STATICFNDEF int4 add_trigger_cmd_attributes(char *trigvn, int trigvn_len, int trigger_index, char *trig_cmds, char **values,
+ uint4 *value_len, boolean_t db_matched_set, boolean_t db_matched_kill, stringkey *kill_hash, stringkey *set_hash,
+ uint4 db_cmd_bm, uint4 tf_cmd_bm)
{
char cmd_str[MAX_COMMANDS_LEN];
int cmd_str_len;
- uint4 db_cmd_bm;
mval mv_hash;
mval mv_trig_indx;
int4 result;
- uint4 tf_cmd_bm;
uint4 tmp_bm;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
if (!validate_label(trigvn, trigvn_len))
return INVALID_LABEL;
- BUILD_COMMAND_BITMAP(db_cmd_bm, trig_cmds);
- BUILD_COMMAND_BITMAP(tf_cmd_bm, values[CMD_SUB]);
/* If the trigger file command string is contained in the database command and either
* 1. the trigger file command has no SET components or
- * 2. the trigger file command matched a database SET component or
+ * 2. the trigger file command matched a database SET component
* then the trigger file command is already in the database, so return.
*/
- if ((tf_cmd_bm == (db_cmd_bm & tf_cmd_bm))
- && ((0 == (tf_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_SET])) || set_compare))
- return CMDS_PRESENT;
- /* If the database command string is contained in the trigger file command and the database is only a "SET"
- * and the trigger file SET matched the database, but not the KILL (which doesn't make sense until you realize that
- * trigger_already_exists() returns kill_compare as FALSE when the trigger file record matches both SET and KILL, but
- * the matches are with two different triggers, then the trigger file command is already in the database so return.
- */
- if ((db_cmd_bm == (db_cmd_bm & tf_cmd_bm))
- && ((db_cmd_bm == (db_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_SET])) && set_compare && !kill_compare))
- return CMDS_PRESENT;
+ if ((tf_cmd_bm == (db_cmd_bm & tf_cmd_bm)) && (!(tf_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_SET]) || db_matched_set))
+ return NO_CMD_CHANGE;
+ assert(!db_matched_set || db_matched_kill);
/* If merge would combine K and ZTK, it's an error */
- if (((0 != (db_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_KILL])) && (0 != (tf_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_ZTKILL])))
- || ((0 != (db_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_ZTKILL])) && (0 != (tf_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_KILL]))))
+ if (((db_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_KILL]) && (tf_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_ZTKILL]))
+ || ((db_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_ZTKILL]) && (tf_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_KILL])))
return K_ZTK_CONFLICT;
- if (!set_compare && kill_compare
- && (0 != (tf_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_SET])) && (0 != (db_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_SET])))
- { /* Subtract common (between triggerfile and DB) "non-S" from tf_cmd_bm */
- tmp_bm = gvtr_cmd_mask[GVTR_CMDTYPE_SET];
- COMMAND_BITMAP_TO_STR(values[CMD_SUB], tmp_bm, value_len[CMD_SUB]);
- /* since the KILL matches, update the corresponding trigger's KILLs */
- tmp_bm = db_cmd_bm | (tf_cmd_bm ^ (gvtr_cmd_mask[GVTR_CMDTYPE_SET] & tf_cmd_bm));
+ if (!db_matched_set && db_matched_kill
+ && (tf_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_SET]) && (db_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_SET]))
+ {
+ tmp_bm = (db_cmd_bm | tf_cmd_bm);
+ if (tmp_bm == db_cmd_bm)
+ { /* No change to commands in the KILL trigger entry in db.
+ * SET trigger (if it exists and is in a different trigger) to be processed separately.
+ */
+ return ADD_SET_NOCHNG_KILL_TRIG;
+ }
+ /* Commands are being added to the existing KILL trigger entry in db */
cmd_str_len = ARRAYSIZE(cmd_str);
COMMAND_BITMAP_TO_STR(cmd_str, tmp_bm, cmd_str_len);
i2mval(&mv_trig_indx, trigger_index);
SET_TRIGGER_GLOBAL_SUB_MSUB_SUB_STR(trigvn, trigvn_len, mv_trig_indx, trigger_subs[CMD_SUB],
STRLEN(trigger_subs[CMD_SUB]), cmd_str, cmd_str_len, result);
assert(result == PUT_SUCCESS);
- return (result == PUT_SUCCESS) ? ADD_NEW_TRIGGER : result;
+ return (result == PUT_SUCCESS) ? ADD_SET_MODIFY_KILL_TRIG : result;
}
cmd_str_len = ARRAYSIZE(cmd_str);
COMMAND_BITMAP_TO_STR(cmd_str, db_cmd_bm | tf_cmd_bm, cmd_str_len);
@@ -691,7 +801,7 @@ STATICFNDEF int4 add_trigger_cmd_attributes(char *trigvn, int trigvn_len, int t
if (PUT_SUCCESS != result)
return result;
strcpy(trig_cmds, cmd_str);
- if ((0 != (gvtr_cmd_mask[GVTR_CMDTYPE_SET] & tf_cmd_bm)) && (0 == (gvtr_cmd_mask[GVTR_CMDTYPE_SET] & db_cmd_bm)))
+ if ((gvtr_cmd_mask[GVTR_CMDTYPE_SET] & tf_cmd_bm) && !(gvtr_cmd_mask[GVTR_CMDTYPE_SET] & db_cmd_bm))
{ /* need to add SET attributes */
if (0 < value_len[DELIM_SUB])
{
@@ -714,8 +824,7 @@ STATICFNDEF int4 add_trigger_cmd_attributes(char *trigvn, int trigvn_len, int t
if (PUT_SUCCESS != result)
return result;
}
- if ((0 == (gvtr_cmd_mask[GVTR_CMDTYPE_SET] & db_cmd_bm))
- && (0 != (gvtr_cmd_mask[GVTR_CMDTYPE_SET] & tf_cmd_bm)))
+ if (!(gvtr_cmd_mask[GVTR_CMDTYPE_SET] & db_cmd_bm) && (gvtr_cmd_mask[GVTR_CMDTYPE_SET] & tf_cmd_bm))
{ /* We gained an "S" so we need to add the set hash value */
result = add_trigger_hash_entry(trigvn, trigvn_len, values[CMD_SUB], trigger_index, FALSE, kill_hash,
set_hash);
@@ -728,7 +837,6 @@ STATICFNDEF int4 add_trigger_cmd_attributes(char *trigvn, int trigvn_len, int t
return result;
}
}
- trigger_incr_cycle(trigvn, trigvn_len);
return ADD_UPDATE_CMDS;
}
@@ -747,14 +855,10 @@ STATICFNDEF int4 add_trigger_options_attributes(char *trigvn, int trigvn_len, in
SETUP_THREADGBL_ACCESS;
BUILD_OPTION_BITMAP(db_option_bm, trig_options);
BUILD_OPTION_BITMAP(tf_option_bm, values[OPTIONS_SUB]);
- if (tf_option_bm == (db_option_bm & tf_option_bm))
+ if (tf_option_bm == db_option_bm)
/* If trigger file OPTIONS is contained in the DB OPTIONS, then trigger file entry is already in DB, just return */
- return OPTIONS_PRESENT;
- tmp_bm = db_option_bm | tf_option_bm;
- if (((0 != (OPTIONS_C & tmp_bm)) && (0 != (OPTIONS_NOC & tmp_bm)))
- || ((0 != (OPTIONS_I & tmp_bm)) && (0 != (OPTIONS_NOI & tmp_bm))))
- /* Can't combine incompatible options, so triggers are different */
- return OPTION_CONFLICT;
+ return NO_OPTIONS_CHANGE;
+ tmp_bm = tf_option_bm;
if (!validate_label(trigvn, trigvn_len))
return INVALID_LABEL;
option_str_len = ARRAYSIZE(option_str);
@@ -765,88 +869,50 @@ STATICFNDEF int4 add_trigger_options_attributes(char *trigvn, int trigvn_len, in
if (PUT_SUCCESS != result)
return result;
strcpy(trig_options, option_str);
- trigger_incr_cycle(trigvn, trigvn_len);
return ADD_UPDATE_OPTIONS;
}
STATICFNDEF boolean_t subtract_trigger_cmd_attributes(char *trigvn, int trigvn_len, char *trig_cmds, char **values,
- uint4 *value_len, boolean_t set_cmp, stringkey *kill_hash, stringkey *set_hash)
+ uint4 *value_len, boolean_t db_matched_set, stringkey *kill_hash, stringkey *set_hash, int trigger_index,
+ uint4 db_cmd_bm, uint4 tf_cmd_bm)
{
char cmd_str[MAX_COMMANDS_LEN];
int cmd_str_len;
- uint4 db_cmd_bm;
uint4 len;
- uint4 tf_cmd_bm;
uint4 restore_set = 0;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
- BUILD_COMMAND_BITMAP(db_cmd_bm, trig_cmds);
- BUILD_COMMAND_BITMAP(tf_cmd_bm, values[CMD_SUB]);
- if (!set_cmp && (0 != (gvtr_cmd_mask[GVTR_CMDTYPE_SET] & tf_cmd_bm)))
- { /* If the set compare failed, we don't want to consider the SET */
+ if (!db_matched_set && (gvtr_cmd_mask[GVTR_CMDTYPE_SET] & tf_cmd_bm))
+ { /* If the set compare failed, we don't want to consider the SET */
restore_set = gvtr_cmd_mask[GVTR_CMDTYPE_SET];
tf_cmd_bm &= ~restore_set;
}
if (0 == (db_cmd_bm & tf_cmd_bm))
- /* If trigger file CMD does NOT overlap with the DB CMD, then no match. So no delete. Just return */
- return 0;
+ return 0; /* If trigger file CMD does NOT overlap with the DB CMD, then no match. So no delete. Just return */
cmd_str_len = ARRAYSIZE(cmd_str);
if (db_cmd_bm != (db_cmd_bm & tf_cmd_bm))
{ /* combine cmds - subtract trigger file attributes from db attributes */
COMMAND_BITMAP_TO_STR(cmd_str, (db_cmd_bm & tf_cmd_bm) ^ db_cmd_bm, cmd_str_len);
strcpy(trig_cmds, cmd_str);
+ /* If we lost the "S", need to delete the set hash value */
if ((0 != (gvtr_cmd_mask[GVTR_CMDTYPE_SET] & db_cmd_bm))
&& (0 == (gvtr_cmd_mask[GVTR_CMDTYPE_SET] & ((db_cmd_bm & tf_cmd_bm) ^ db_cmd_bm))))
- /* We lost the "S" so we need to delete the set hash value */
- cleanup_trigger_hash(trigvn, trigvn_len, values, value_len, set_hash, kill_hash, FALSE, 0);
+ cleanup_trigger_hash(trigvn, trigvn_len, values, value_len, set_hash, kill_hash, FALSE, trigger_index);
} else
{ /* Both cmds are the same - candidate for delete */
trig_cmds[0] = '\0';
db_cmd_bm |= restore_set;
- COMMAND_BITMAP_TO_STR(cmd_str, db_cmd_bm, cmd_str_len);
- value_len[CMD_SUB] = cmd_str_len;
- strcpy(values[CMD_SUB], cmd_str);
-
}
return SUB_UPDATE_CMDS;
}
-STATICFNDEF boolean_t subtract_trigger_options_attributes(char *trigvn, int trigvn_len, char *trig_options, char *option_value)
-{
- uint4 db_option_bm;
- char option_str[MAX_OPTIONS_LEN];
- int option_str_len;
- uint4 tf_option_bm;
- uint4 tmp_bm;
- DCL_THREADGBL_ACCESS;
-
- SETUP_THREADGBL_ACCESS;
- BUILD_OPTION_BITMAP(db_option_bm, trig_options);
- BUILD_OPTION_BITMAP(tf_option_bm, option_value);
- if (((0 != db_option_bm) && (0 != tf_option_bm)) && (0 == (db_option_bm & tf_option_bm)))
- /* If trigger file OPTIONS does NOT overlap with the DB OPTIONS, then no match. So no delete. Just return */
- return 0;
- if (db_option_bm != (db_option_bm & tf_option_bm))
- {
- /* combine options - subtract trigger file attributes from db attributes */
- tmp_bm = (db_option_bm & tf_option_bm) ^ db_option_bm;
- assert((0 == (OPTIONS_C & tmp_bm)) || (0 == (OPTIONS_NOC & tmp_bm)));
- assert((0 == (OPTIONS_I & tmp_bm)) || (0 == (OPTIONS_NOI & tmp_bm)));
- option_str_len = ARRAYSIZE(option_str);
- OPTION_BITMAP_TO_STR(option_str, tmp_bm, option_str_len);
- strcpy(trig_options, option_str);
- } else
- /* Both options are the same - candidate to delete */
- trig_options[0] = '\0';
- return SUB_UPDATE_OPTIONS;
-}
-
STATICFNDEF int4 modify_record(char *trigvn, int trigvn_len, char add_delete, int trigger_index, char **values, uint4 *value_len,
- mval *trigger_count, boolean_t set_compare, boolean_t kill_compare, stringkey *kill_hash, stringkey *set_hash)
+ mval *trigger_count, boolean_t db_matched_set, boolean_t db_matched_kill,
+ stringkey *kill_hash, stringkey *set_hash, int set_kill_bitmask)
{
char db_cmds[MAX_COMMANDS_LEN + 1];
- boolean_t name_matches;
+ boolean_t name_matches, sub_cmds;
int4 result;
uint4 retval;
mval trigindx;
@@ -856,16 +922,26 @@ STATICFNDEF int4 modify_record(char *trigvn, int trigvn_len, char add_delete, in
unsigned char util_buff[MAX_TRIG_UTIL_LEN];
int4 util_len;
mval val;
+ uint4 db_cmd_bm, tf_cmd_bm;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
- retval = 0;
i2mval(&trigindx, trigger_index);
+ /* get(^#t(GVN,trigindx,"CMD") */
BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigindx, trigger_subs[CMD_SUB], STRLEN(trigger_subs[CMD_SUB]));
if (!gvcst_get(&val)) /* There has to be a command string */
HASHT_GVN_DEFINITION_RETRY_OR_ERROR(trigger_index, ",\"CMD\"", REG2CSA(gv_cur_region));
memcpy(trig_cmds, val.str.addr, val.str.len);
trig_cmds[val.str.len] = '\0';
+ BUILD_COMMAND_BITMAP(db_cmd_bm, trig_cmds);
+ BUILD_COMMAND_BITMAP(tf_cmd_bm, values[CMD_SUB]);
+ /* If trigger file has specified SET and/or KILL triggers and each of them matched to different triggers in database,
+ * filter out only the respective category of triggers to go forward with the command addition/deletion.
+ */
+ if (OPR_KILL == set_kill_bitmask)
+ tf_cmd_bm &= ~gvtr_cmd_mask[GVTR_CMDTYPE_SET];
+ else if (OPR_SET == set_kill_bitmask)
+ tf_cmd_bm &= gvtr_cmd_mask[GVTR_CMDTYPE_SET];
/* get(^#t(GVN,trigindx,"OPTIONS") */
BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigindx, trigger_subs[OPTIONS_SUB],
STRLEN(trigger_subs[OPTIONS_SUB]));
@@ -884,72 +960,74 @@ STATICFNDEF int4 modify_record(char *trigvn, int trigvn_len, char add_delete, in
trig_name[val.str.len] = '\0';
if ('+' == add_delete)
{
- result = add_trigger_cmd_attributes(trigvn, trigvn_len, trigger_index, trig_cmds, values, value_len,
- set_compare, kill_compare, kill_hash, set_hash);
- switch (result)
- {
- case K_ZTK_CONFLICT:
- case INVALID_LABEL:
- case ADD_NEW_TRIGGER:
- case VAL_TOO_LONG:
- case KEY_TOO_LONG:
- return result;
- default:
- retval = result;
+ /* Process -OPTIONS */
+ result = add_trigger_options_attributes(trigvn, trigvn_len, trigger_index, trig_options, values, value_len);
+ assert((NO_OPTIONS_CHANGE == result) || (ADD_UPDATE_OPTIONS == result) /* 0 or 0x04 */
+ || (INVALID_LABEL == result) || (VAL_TOO_LONG == result) || (KEY_TOO_LONG == result)); /* < 0 */
+ if (0 > result)
+ return result;
+ assert((NO_OPTIONS_CHANGE == result) || (ADD_UPDATE_OPTIONS == result));
+ if (NO_OPTIONS_CHANGE != result)
+ { /* Check if specified list of commands matches commands in database. If not cannot proceed */
+ if (tf_cmd_bm != db_cmd_bm)
+ return OPTIONS_CMDS_CONFLICT;
}
+ retval = result;
+ /* Process -NAME */
result = update_trigger_name(trigvn, trigvn_len, trigger_index, trig_name, values[TRIGNAME_SUB],
value_len[TRIGNAME_SUB]);
- if ((INVALID_LABEL == result) || (VAL_TOO_LONG == result) || (KEY_TOO_LONG == result))
+ assert((NO_NAME_CHANGE == result) || (ADD_UPDATE_NAME == result) /* 0 or 0x01 */
+ || (INVALID_LABEL == result) || (VAL_TOO_LONG == result) || (KEY_TOO_LONG == result)); /* < 0 */
+ if (0 > result)
return result;
+ assert((NO_NAME_CHANGE == result) || (ADD_UPDATE_NAME == result));
+ if (NO_NAME_CHANGE != result)
+ { /* Check if specified list of commands contains commands in database. If not cannot proceed */
+ if ((tf_cmd_bm &db_cmd_bm) != db_cmd_bm)
+ return NAME_CMDS_CONFLICT;
+ }
retval |= result;
- result = add_trigger_options_attributes(trigvn, trigvn_len, trigger_index, trig_options, values, value_len);
- if ((INVALID_LABEL == result) || (VAL_TOO_LONG == result) || (KEY_TOO_LONG == result))
+ /* Process -CMD */
+ result = add_trigger_cmd_attributes(trigvn, trigvn_len, trigger_index, trig_cmds, values, value_len,
+ db_matched_set, db_matched_kill, kill_hash, set_hash, db_cmd_bm, tf_cmd_bm);
+ assert((NO_CMD_CHANGE == result) || (ADD_UPDATE_CMDS == result) /* 0 or 0x02 */
+ || (ADD_SET_MODIFY_KILL_TRIG == result) || (ADD_SET_NOCHNG_KILL_TRIG == result) /* < 0 */
+ || (INVALID_LABEL == result) || (K_ZTK_CONFLICT == result) /* < 0 */
+ || (VAL_TOO_LONG == result) || (KEY_TOO_LONG == result)); /* < 0 */
+ if (0 > result)
return result;
+ assert((NO_CMD_CHANGE == result) || (ADD_UPDATE_CMDS == result));
retval |= result;
} else
{
name_matches = (0 == value_len[TRIGNAME_SUB])
- || ((value_len[TRIGNAME_SUB] == (STRLEN(trig_name) - 1))
- && (0 == memcmp(values[TRIGNAME_SUB], trig_name, value_len[TRIGNAME_SUB])));
- if (name_matches)
+ || ((value_len[TRIGNAME_SUB] == (STRLEN(trig_name) - 1))
+ && (0 == memcmp(values[TRIGNAME_SUB], trig_name, value_len[TRIGNAME_SUB])));
+ if (!name_matches)
+ return 0;
+ memcpy(db_cmds, trig_cmds, SIZEOF(trig_cmds));
+ sub_cmds = subtract_trigger_cmd_attributes(trigvn, trigvn_len, trig_cmds, values, value_len,
+ db_matched_set, kill_hash, set_hash, trigger_index, db_cmd_bm, tf_cmd_bm);
+ /* options are ignored in case of deletes so no need for "subtract_trigger_options_attributes()" */
+ if (!sub_cmds)
+ return 0;
+ if (0 == trig_cmds[0])
{
- retval = SUB_UPDATE_NAME;
- memcpy(db_cmds, trig_cmds, SIZEOF(trig_cmds));
- retval |= subtract_trigger_cmd_attributes(trigvn, trigvn_len, trig_cmds, values, value_len, set_compare,
- kill_hash, set_hash);
- retval |= subtract_trigger_options_attributes(trigvn, trigvn_len, trig_options, values[OPTIONS_SUB]);
+ result = trigger_delete(trigvn, trigvn_len, trigger_count, trigger_index);
+ assert((VAL_TOO_LONG == result) || (KEY_TOO_LONG == result) /* < 0 */
+ || (PUT_SUCCESS == result)); /* == 0 */
+ if (0 > result)
+ return result;
+ return DELETE_REC;
}
- if ((0 != (retval & SUB_UPDATE_NAME)) && (0 != (retval & SUB_UPDATE_OPTIONS)) && (0 != (retval & SUB_UPDATE_CMDS)))
+ retval = 0;
+ if (sub_cmds)
{
- if ((0 == trig_cmds[0]) && (0 == trig_options[0]))
- {
- result = trigger_delete(trigvn, trigvn_len, trigger_count, trigger_index);
- if ((VAL_TOO_LONG == result) || (KEY_TOO_LONG == result))
- return result;
- retval = DELETE_REC;
- } else
- {
- retval = 0;
- if (0 != trig_cmds[0])
- {
- result = update_commands(trigvn, trigvn_len, trigger_index, trig_cmds, db_cmds);
- if (SUB_UPDATE_CMDS != result)
- return result;
- retval |= result;
- }
- if (0 != trig_options[0])
- {
- result = update_options(trigvn, trigvn_len, trigger_index, trig_options,
- values[OPTIONS_SUB]);
- if (SUB_UPDATE_OPTIONS != result)
- return result;
- if (0 != value_len[OPTIONS_SUB])
- retval |= result;
- }
- }
+ result = update_commands(trigvn, trigvn_len, trigger_index, trig_cmds, db_cmds);
+ if (SUB_UPDATE_CMDS != result)
+ return result;
+ retval |= result;
}
- else
- retval = SUB_UPDATE_NOCHANGE;
}
return retval;
}
@@ -961,102 +1039,83 @@ STATICFNDEF int4 gen_trigname_sequence(char *trigvn, int trigvn_len, mval *trigg
char *ptr1;
int rndm_int;
int seq_num;
- gv_key save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
- gd_region *save_gv_cur_region;
- gv_namehead *save_gv_target;
- sgm_info *save_sgm_info_ptr;
int4 result;
char *seq_ptr, *uniq_ptr;
char trig_name[MAX_USER_TRIGNAME_LEN + 1];
- uint4 trigname_len;
+ uint4 trigname_len, uniq_ptr_len;
char unique_seq_str[NUM_TRIGNAME_SEQ_CHARS + 1];
mval val, *val_ptr;
char val_str[MAX_DIGITS_IN_INT + 1];
- int var_count;
+ int var_count, max_seq_num;
+ mval label, *label_mv;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
assert(MAX_USER_TRIGNAME_LEN >= user_trigname_len);
- uniq_ptr = unique_seq_str;
- seq_num = 1;
+ 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 */
if (0 == user_trigname_len)
- { /* autogenerated name -- might be long */
+ { /* autogenerated name -- might be long so take MIN */
trigname_len = MIN(trigvn_len, MAX_AUTO_TRIGNAME_LEN);
strncpy(trig_name, trigvn, trigname_len);
- } else
- { /* user supplied name */
- trigname_len = user_trigname_len;
- strncpy(trig_name, user_trigname_str, user_trigname_len);
- }
- SAVE_TRIGGER_REGION_INFO(save_currkey);
- SWITCH_TO_DEFAULT_REGION;
- if (gv_cur_region->read_only)
- rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(gv_cur_region));
- INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
- if (0 == user_trigname_len)
- { /* autogenerated name */
val_ptr = &val;
- if (0 != gv_target->root)
- {
- /* $get(^#t("#TNAME",GVN,"#SEQCOUNT")) */
- BUILD_HASHT_SUB_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trig_name, trigname_len,
- LITERAL_HASHSEQNUM, STRLEN(LITERAL_HASHSEQNUM));
+ if (gv_target->root)
+ { /* $get(^#t("#TNAME",GVN,"#SEQNUM")) */
+ BUILD_HASHT_SUB_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STR_LIT_LEN(LITERAL_HASHTNAME), trig_name, trigname_len,
+ LITERAL_HASHSEQNUM, STR_LIT_LEN(LITERAL_HASHSEQNUM));
seq_num = gvcst_get(val_ptr) ? mval2i(val_ptr) + 1 : 1;
- if (MAX_TRIGNAME_SEQ_NUM < seq_num)
- {
- RESTORE_TRIGGER_REGION_INFO(save_currkey);
+ max_seq_num = MAX_TRIGNAME_SEQ_NUM;
+ /* If dbg & white-box test then reduce limit to 1000 (instead of 1 million) auto-generated trigger names */
+ if (WBTEST_ENABLED(WBTEST_MAX_TRIGNAME_SEQ_NUM))
+ max_seq_num = 999;
+ if (max_seq_num < seq_num)
return TOO_MANY_TRIGGERS;
- }
+ } else
+ {
+ /* Set ^#t("#LABEL")=3 */
+ label_mv = &label;
+ MV_FORCE_MVAL(label_mv, 3);
+ SET_TRIGGER_GLOBAL_SUB_MVAL(LITERAL_HASHLABEL, STRLEN(LITERAL_HASHLABEL), label, result);
+ seq_num = 1;
}
+ uniq_ptr = unique_seq_str;
INT2STR(seq_num, uniq_ptr);
- /* set ^#t("#TNAME",GVN,"#SEQCOUNT")++ via unique_seq_str which came from seq_num*/
- SET_TRIGGER_GLOBAL_SUB_SUB_SUB_STR(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trig_name, trigname_len,
- LITERAL_HASHSEQNUM, STRLEN(LITERAL_HASHSEQNUM), unique_seq_str, STRLEN(unique_seq_str), result);
+ uniq_ptr_len = STRLEN(uniq_ptr);
+ /* set ^#t("#TNAME",GVN,"#SEQNUM")++ */
+ SET_TRIGGER_GLOBAL_SUB_SUB_SUB_STR(LITERAL_HASHTNAME, STR_LIT_LEN(LITERAL_HASHTNAME), trig_name, trigname_len,
+ LITERAL_HASHSEQNUM, STR_LIT_LEN(LITERAL_HASHSEQNUM), uniq_ptr, uniq_ptr_len, result);
if (PUT_SUCCESS != result)
- {
- RESTORE_TRIGGER_REGION_INFO(save_currkey);
return result;
- }
/* set ^#t("#TNAME",GVN,"#TNCOUNT")++ */
- BUILD_HASHT_SUB_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trig_name, trigname_len,
- LITERAL_HASHTNCOUNT, STRLEN(LITERAL_HASHTNCOUNT));
+ BUILD_HASHT_SUB_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STR_LIT_LEN(LITERAL_HASHTNAME), trig_name, trigname_len,
+ LITERAL_HASHTNCOUNT, STR_LIT_LEN(LITERAL_HASHTNCOUNT));
var_count = gvcst_get(val_ptr) ? mval2i(val_ptr) + 1 : 1;
i2mval(&val, var_count);
- SET_TRIGGER_GLOBAL_SUB_SUB_SUB_MVAL(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trig_name, trigname_len,
- LITERAL_HASHTNCOUNT, STRLEN(LITERAL_HASHTNCOUNT), val, result);
+ SET_TRIGGER_GLOBAL_SUB_SUB_SUB_MVAL(LITERAL_HASHTNAME, STR_LIT_LEN(LITERAL_HASHTNAME), trig_name, trigname_len,
+ LITERAL_HASHTNCOUNT, STR_LIT_LEN(LITERAL_HASHTNCOUNT), val, result);
if (PUT_SUCCESS != result)
- {
- RESTORE_TRIGGER_REGION_INFO(save_currkey);
return result;
- }
- } else
- *uniq_ptr = '\0'; /* user supplied name */
- seq_ptr = user_trigname_str;
- memcpy(seq_ptr, trig_name, trigname_len);
- seq_ptr += trigname_len;
- if (0 == user_trigname_len)
- { /* Autogenerated */
+ seq_ptr = user_trigname_str;
+ memcpy(seq_ptr, trig_name, trigname_len);
+ seq_ptr += trigname_len;
*seq_ptr++ = TRIGNAME_SEQ_DELIM;
- memcpy(seq_ptr, unique_seq_str, STRLEN(unique_seq_str));
- seq_ptr += STRLEN(unique_seq_str);
- }
- *seq_ptr = '\0';
+ memcpy(seq_ptr, uniq_ptr, uniq_ptr_len);
+ seq_ptr += uniq_ptr_len;
+ user_trigname_len = trigname_len + 1 + uniq_ptr_len;
+ } else
+ seq_ptr = user_trigname_str + user_trigname_len;
ptr1 = name_and_index;
memcpy(ptr1, trigvn, trigvn_len);
ptr1 += trigvn_len;
*ptr1++ = '\0';
MV_FORCE_STR(trigger_count);
memcpy(ptr1, trigger_count->str.addr, trigger_count->str.len);
- SET_TRIGGER_GLOBAL_SUB_SUB_STR(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), user_trigname_str, STRLEN(user_trigname_str),
+ SET_TRIGGER_GLOBAL_SUB_SUB_STR(LITERAL_HASHTNAME, STR_LIT_LEN(LITERAL_HASHTNAME), user_trigname_str, user_trigname_len,
name_and_index, trigvn_len + 1 + trigger_count->str.len, result);
if (PUT_SUCCESS != result)
- {
- RESTORE_TRIGGER_REGION_INFO(save_currkey);
return result;
- }
- *seq_ptr++ = TRIGNAME_SEQ_DELIM;
+ *seq_ptr++ = TRIGNAME_SEQ_DELIM; /* all trigger names end with a hash mark, so append one */
*seq_ptr = '\0';
- RESTORE_TRIGGER_REGION_INFO(save_currkey);
return SEQ_SUCCESS;
}
@@ -1065,43 +1124,30 @@ boolean_t trigger_update_rec(char *trigger_rec, uint4 len, boolean_t noprompt, u
{
char add_delete;
char ans[2];
- sgmnt_addrs *csa;
- boolean_t cmd_modified;
char db_trig_name[MAX_USER_TRIGNAME_LEN + 1];
- boolean_t full_match;
+ boolean_t multiline_parse_fail;
mname_entry gvname;
- boolean_t kill_cmp;
int4 max_len;
boolean_t multi_line, multi_line_xecute;
- mval mv_hash;
- boolean_t new_name;
- int num;
- int4 offset;
- char *ptr1;
int4 rec_len;
int4 rec_num;
- boolean_t result;
- gv_namehead *save_gvtarget;
- boolean_t set_cmp;
- boolean_t skip_set_trigger;
boolean_t status;
- int sub_indx;
char tcount[MAX_DIGITS_IN_INT];
char tfile_rec_val[MAX_BUFF_SIZE];
char trig_cmds[MAX_COMMANDS_LEN + 1];
- mval *trig_cnt_ptr;
- char trig_name[MAX_USER_TRIGNAME_LEN + 2]; /* One spot for '#' delimiter and one for trailing '\0' */
char trig_options[MAX_OPTIONS_LEN + 1];
char trigvn[MAX_MIDENT_LEN + 1];
- mval trigger_count;
+ char disp_trigvn[MAX_MIDENT_LEN + SPANREG_REGION_LITLEN + MAX_RN_LEN + 1 + 1];
+ /* SPANREG_REGION_LITLEN for " (region ", MAX_RN_LEN for region name,
+ * 1 for ")" and 1 for trailing '\0'.
+ */
+ int disp_trigvn_len;
int trigvn_len;
- int trigindx, kill_index = -1;
- int4 updates = 0;
- char *values[NUM_SUBS];
- uint4 value_len[NUM_SUBS];
+ char *values[NUM_SUBS], *save_values[NUM_SUBS];
+ uint4 value_len[NUM_SUBS], save_value_len[NUM_SUBS];
stringkey kill_trigger_hash, set_trigger_hash;
- char tmp_str[MAX_HASH_INDEX_LEN + 1 + MAX_DIGITS_IN_INT];
- char xecute_buffer[MAX_BUFF_SIZE + MAX_XECUTE_LEN];
+ char tmp_str[MAX_HASH_LEN + 1];
+ char xecute_buffer[MAX_BUFF_SIZE + MAX_XECUTE_LEN], dispbuff[MAX_TRIG_DISPLEN];
mval xecute_index, xecute_size;
mval reportname, reportnamealt;
mval trigjrec;
@@ -1110,18 +1156,35 @@ boolean_t trigger_update_rec(char *trigger_rec, uint4 len, boolean_t noprompt, u
io_pair io_save_device;
int4 max_xecute_size;
boolean_t no_error;
- boolean_t newtrigger;
gvnh_reg_t *gvnh_reg;
+ char utilprefix[1024];
+ int utilprefixlen, displen;
+ int reg_index, min_reg_index, max_reg_index;
+ boolean_t first_gtmio;
+ boolean_t jnl_format_done, new_name_check_done, new_name, first_error;
+ trig_stats_t this_trig_status, overall_trig_status;
+ gv_namehead *gvt;
+ gvnh_spanreg_t *gvspan;
+ hash128_state_t set_hash_state, kill_hash_state;
+ uint4 set_hash_totlen, kill_hash_totlen;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
+ /* We are going to operate on the ^#t global which does not span regions. Reset gd_targ_gvnh_reg
+ * leftover from previous GV_BIND_SUBSNAME_IF_GVSPAN call to not affect any op_zprevious etc.
+ * (e.g. invocation trigger_update_rec -> trigupdrec_reg -> add_trigger_hash_entry -> op_zprevious)
+ * so it focuses on gvcst_zprevious instead of gvcst_spr_zprevious for the ^#t global.
+ * It is okay not to restore TREF(gd_targ_gvnh_reg) since it will be initialized as part of the
+ * next op_gv* call done by the caller (be it mumps or mupip).
+ */
+ TREF(gd_targ_gvnh_reg) = NULL;
assert(dollar_tlevel);
assert(0 > memcmp(LITERAL_HASHLABEL, LITERAL_MAXHASHVAL, MIN(STRLEN(LITERAL_HASHLABEL), STRLEN(LITERAL_MAXHASHVAL))));
assert(0 > memcmp(LITERAL_HASHCOUNT, LITERAL_MAXHASHVAL, MIN(STRLEN(LITERAL_HASHCOUNT), STRLEN(LITERAL_MAXHASHVAL))));
assert(0 > memcmp(LITERAL_HASHCYCLE, LITERAL_MAXHASHVAL, MIN(STRLEN(LITERAL_HASHCYCLE), STRLEN(LITERAL_MAXHASHVAL))));
assert(0 > memcmp(LITERAL_HASHTNAME, LITERAL_MAXHASHVAL, MIN(STRLEN(LITERAL_HASHTNAME), STRLEN(LITERAL_MAXHASHVAL))));
assert(0 > memcmp(LITERAL_HASHTNCOUNT, LITERAL_MAXHASHVAL, MIN(STRLEN(LITERAL_HASHTNCOUNT), STRLEN(LITERAL_MAXHASHVAL))));
- rec_num = ((NULL == record_num)? 0 : *record_num);
+ rec_num = (NULL == record_num) ? 0 : *record_num;
gvinit();
trigjrec.mvtype = MV_STR;
trigjrec.str.len = len;
@@ -1139,8 +1202,10 @@ boolean_t trigger_update_rec(char *trigger_rec, uint4 len, boolean_t noprompt, u
return TRIG_SUCCESS;
if (('-' != *trigger_rec) && ('+' != *trigger_rec))
{
- trig_stats[STATS_ERROR]++;
- util_out_print_gtmio("missing +/- at start of line: !AD", FLUSH, len, trigger_rec);
+ trig_stats[STATS_ERROR_TRIGFILE]++;
+ displen = MAX_TRIG_DISPLEN;
+ format2disp(trigger_rec, len, dispbuff, &displen); /* returns displayable string in "dispbuff" */
+ util_out_print_gtmio("Error : missing +/- at start of line: !AD", FLUSH, displen, dispbuff);
return TRIG_FAILURE;
}
add_delete = *trigger_rec++;
@@ -1151,8 +1216,8 @@ boolean_t trigger_update_rec(char *trigger_rec, uint4 len, boolean_t noprompt, u
{
if ((NULL == trigfile_device) && (NULL != trigjrecptr))
{
- util_out_print_gtmio("Newline not allowed in trigger name for delete operation", FLUSH);
- trig_stats[STATS_ERROR]++;
+ util_out_print_gtmio("Error : Newline not allowed in trigger name for delete operation", FLUSH);
+ trig_stats[STATS_ERROR_TRIGFILE]++;
return TRIG_FAILURE;
}
if (!noprompt)
@@ -1166,44 +1231,44 @@ boolean_t trigger_update_rec(char *trigger_rec, uint4 len, boolean_t noprompt, u
return TRIG_SUCCESS;
}
}
- trigger_delete_all(--trigger_rec, len + 1);
+ trigger_delete_all(--trigger_rec, len + 1, trig_stats); /* updates trig_stats[] appropriately */
return TRIG_SUCCESS;
} else if ((0 == len) || ('^' != *trigger_rec))
{ /* if the length < 0 let trigger_delete_name respond with the error message */
if ((NULL == trigfile_device) && (NULL != trigjrecptr))
{
- util_out_print_gtmio("Newline not allowed in trigger name for delete operation", FLUSH);
- trig_stats[STATS_ERROR]++;
+ util_out_print_gtmio("Error : Newline not allowed in trigger name for delete operation", FLUSH);
+ trig_stats[STATS_ERROR_TRIGFILE]++;
return TRIG_FAILURE;
}
- if (TRIG_FAILURE == (status = trigger_delete_name(--trigger_rec, len + 1, trig_stats)))
- trig_stats[STATS_ERROR]++;
+ status = trigger_delete_name(--trigger_rec, len + 1, trig_stats); /* updates trig_stats[] appropriately */
return status;
}
}
values[GVSUBS_SUB] = tfile_rec_val; /* GVSUBS will be the first entry set so initialize it */
max_len = (int4)SIZEOF(tfile_rec_val);
multi_line_xecute = FALSE;
- no_error = TRUE;
if (!trigger_parse(trigger_rec, len, trigvn, values, value_len, &max_len, &multi_line_xecute))
{
- if (multi_line_xecute)
- no_error = FALSE;
- else
- {
- trig_stats[STATS_ERROR]++;
- return TRIG_FAILURE;
- }
+ trig_stats[STATS_ERROR_TRIGFILE]++;
+ return TRIG_FAILURE;
}
trigvn_len = STRLEN(trigvn);
- set_trigger_hash.str.addr = tmp_str;
- set_trigger_hash.str.len = SIZEOF(tmp_str);
+ set_trigger_hash.str.addr = &tmp_str[0];
+ set_trigger_hash.str.len = MAX_HASH_LEN;
build_set_cmp_str(trigvn, trigvn_len, values, value_len, &set_trigger_hash.str, multi_line_xecute);
- COMPUTE_HASH_STR(&set_trigger_hash);
- kill_trigger_hash.str.addr = tmp_str;
- kill_trigger_hash.str.len = SIZEOF(tmp_str);
+ /* Note that we are going to compute the hash of the trigger string in bits and pieces.
+ * So use the STR_PHASH* macros (the progressive variants), not the STR_HASH macros.
+ */
+ STR_PHASH_INIT(set_hash_state, set_hash_totlen);
+ STR_PHASH_PROCESS(set_hash_state, set_hash_totlen, set_trigger_hash.str.addr, set_trigger_hash.str.len);
+ kill_trigger_hash.str.addr = &tmp_str[0];
+ kill_trigger_hash.str.len = MAX_HASH_LEN;
build_kill_cmp_str(trigvn, trigvn_len, values, value_len, &kill_trigger_hash.str, multi_line_xecute);
- COMPUTE_HASH_STR(&kill_trigger_hash);
+ STR_PHASH_INIT(kill_hash_state, kill_hash_totlen);
+ STR_PHASH_PROCESS(kill_hash_state, kill_hash_totlen, kill_trigger_hash.str.addr, kill_trigger_hash.str.len);
+ first_gtmio = TRUE;
+ utilprefixlen = ARRAYSIZE(utilprefix);
if (multi_line_xecute)
{
if (NULL != trigfile_device)
@@ -1225,28 +1290,81 @@ boolean_t trigger_update_rec(char *trigger_rec, uint4 len, boolean_t noprompt, u
io_save_device = io_curr_device;
io_curr_device = *trigfile_device;
multi_line = multi_line_xecute;
- while (multi_line && (0 <= (rec_len = file_input_get(&trigger_rec))))
+ /* We are in a multi-line trigger definition. Each trigger line should now correspond to an M source line.
+ * The GT.M compiler does not accept any M source line > MAX_SRCLINE bytes. So issue error right away in
+ * case source line is > MAX_SRCLINE. No point reading the full line and then issuing the error.
+ * Note that MAX_SRCLINE also includes the newline at end of line hence the MAX_SRCLINE - 1 usage below.
+ */
+ multiline_parse_fail = FALSE;
+ while (multi_line)
{
- rec_num++;
+ rec_len = file_input_get(&trigger_rec, MAX_SRCLINE - 1);
+ if (!io_curr_device.in->dollar.x)
+ rec_num++;
+ if (0 > rec_len)
+ {
+ assert((FILE_INPUT_GET_LINE2LONG == rec_len) || (FILE_INPUT_GET_ERROR == rec_len));
+ if (FILE_INPUT_GET_ERROR == rec_len)
+ break;
+ do
+ { /* Read the remainder of the long line in as many MAX_SRCLINE chunks as needed */
+ rec_len = file_input_get(&trigger_rec, MAX_SRCLINE - 1);
+ if (!io_curr_device.in->dollar.x)
+ rec_num++;
+ if (0 <= rec_len)
+ break; /* reached end of line */
+ assert((FILE_INPUT_GET_LINE2LONG == rec_len) || (FILE_INPUT_GET_ERROR == rec_len));
+ if (FILE_INPUT_GET_ERROR == rec_len)
+ break;
+ } while (TRUE);
+ if (FILE_INPUT_GET_ERROR == rec_len)
+ break;
+ if (!multiline_parse_fail)
+ {
+ UTIL_PRINT_PREFIX_IF_NEEDED(first_gtmio, utilprefix, &utilprefixlen);
+ util_out_print_gtmio("Error : Multi-line trigger -XECUTE exceeds maximum "
+ "M source line length of !UL", FLUSH, MAX_SRCLINE);
+ value_len[XECUTE_SUB] = 1;
+ values[XECUTE_SUB][0] = ' ';
+ max_xecute_size = SIZEOF(xecute_buffer);
+ }
+ multiline_parse_fail = TRUE;
+ }
io_curr_device = io_save_device; /* In case we have to write an error message */
- no_error &= trigger_parse(trigger_rec, (uint4)rec_len, trigvn, values, value_len,
- &max_xecute_size, &multi_line);
+ no_error = trigger_parse(trigger_rec, (uint4)rec_len, trigvn, values, value_len,
+ &max_xecute_size, &multi_line);
io_curr_device = *trigfile_device;
+ if (!no_error)
+ { /* An error occurred (e.g. Trigger definition too long etc.).
+ * Consume remainder of multi-line trigger definition before moving on.
+ * But before that replace XECUTE string constructed till now with a dummy one.
+ */
+ assert(!multi_line);
+ multi_line = TRUE;
+ multiline_parse_fail = TRUE;
+ }
+ if (multiline_parse_fail)
+ {
+ value_len[XECUTE_SUB] = 1;
+ values[XECUTE_SUB][0] = ' ';
+ max_xecute_size = SIZEOF(xecute_buffer);
+ }
}
trigjrec.str.len = trigjreclen + value_len[XECUTE_SUB];
if (NULL != record_num)
*record_num = rec_num;
- if (!no_error)
+ if (0 > rec_len)
{
+ assert(FILE_INPUT_GET_ERROR == rec_len);
io_curr_device = io_save_device;
- trig_stats[STATS_ERROR]++;
+ util_out_print_gtmio("Error : Multi-line trigger -XECUTE is not properly terminated", FLUSH);
+ trig_stats[STATS_ERROR_TRIGFILE]++;
return TRIG_FAILURE;
}
- if (0 > rec_len)
- {
+ if (multiline_parse_fail)
+ { /* error message has already been issued */
io_curr_device = io_save_device;
- util_out_print_gtmio("Multi-line trigger -XECUTE is not properly terminated", FLUSH);
- trig_stats[STATS_ERROR]++;
+ trig_stats[STATS_ERROR_TRIGFILE]++;
return TRIG_FAILURE;
}
io_curr_device = io_save_device;
@@ -1256,20 +1374,20 @@ boolean_t trigger_update_rec(char *trigger_rec, uint4 len, boolean_t noprompt, u
value_len[XECUTE_SUB] = trigjrec.str.addr + trigjrec.str.len - (trigjrecptr + 1);
if ('\n' != values[XECUTE_SUB][value_len[XECUTE_SUB] - 1])
{
- util_out_print_gtmio("Multi-line xecute in $ztrigger ITEM must end in newline", FLUSH);
- trig_stats[STATS_ERROR]++;
+ util_out_print_gtmio("Error : Multi-line xecute in $ztrigger ITEM must end in newline", FLUSH);
+ trig_stats[STATS_ERROR_TRIGFILE]++;
return TRIG_FAILURE;
}
if (!process_xecute(values[XECUTE_SUB], &value_len[XECUTE_SUB], TRUE))
{
- CONV_STR_AND_PRINT("Error parsing XECUTE string: ", value_len[XECUTE_SUB], values[XECUTE_SUB]);
- trig_stats[STATS_ERROR]++;
+ CONV_STR_AND_PRINT("Error : Parsing XECUTE string: ", value_len[XECUTE_SUB], values[XECUTE_SUB]);
+ trig_stats[STATS_ERROR_TRIGFILE]++;
return TRIG_FAILURE;
}
/* trigjrec is already properly set up */
}
- STR_HASH(values[XECUTE_SUB], value_len[XECUTE_SUB], set_trigger_hash.hash_code, set_trigger_hash.hash_code);
- STR_HASH(values[XECUTE_SUB], value_len[XECUTE_SUB], kill_trigger_hash.hash_code, kill_trigger_hash.hash_code);
+ STR_PHASH_PROCESS(kill_hash_state, kill_hash_totlen, values[XECUTE_SUB], value_len[XECUTE_SUB]);
+ STR_PHASH_PROCESS(set_hash_state, set_hash_totlen, values[XECUTE_SUB], value_len[XECUTE_SUB]);
} else if ((NULL == trigfile_device) && (NULL != trigjrecptr))
{ /* If this is a not a multi-line xecute string, we dont expect newlines. The only exception is if it is
* the last byte in the string.
@@ -1277,324 +1395,557 @@ boolean_t trigger_update_rec(char *trigger_rec, uint4 len, boolean_t noprompt, u
*trigjrecptr++;
if (trigjrecptr != (trigjrec.str.addr + trigjrec.str.len))
{
- util_out_print_gtmio("Newline allowed only inside multi-line xecute in $ztrigger ITEM", FLUSH);
- trig_stats[STATS_ERROR]++;
+ util_out_print_gtmio("Error : Newline allowed only inside multi-line xecute in $ztrigger ITEM", FLUSH);
+ trig_stats[STATS_ERROR_TRIGFILE]++;
return TRIG_FAILURE;
}
}
+ STR_PHASH_RESULT(set_hash_state, set_hash_totlen, set_trigger_hash.hash_code);
+ STR_PHASH_RESULT(kill_hash_state, kill_hash_totlen, kill_trigger_hash.hash_code);
gvname.var_name.addr = trigvn;
gvname.var_name.len = trigvn_len;
COMPUTE_HASH_MNAME(&gvname);
GV_BIND_NAME_ONLY(gd_header, &gvname, gvnh_reg);
- /* Trigger updates are not currently supported for globals spanning multiple regions */
- if (NULL != gvnh_reg->gvspan)
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TRIGNOSPANGBL, 2, trigvn_len, trigvn);
- /* Now that we know this is not a spanning global, there is no need to do a GV_BIND_SUBSNAME* macro call.
- * gv_cur_region/gv_target already point to the correct region.
- */
+ gvspan = gvnh_reg->gvspan;
+ if (NULL != gvspan)
+ {
+ gvnh_spanreg_subs_gvt_init(gvnh_reg, gd_header, NULL);
+ reg_index = gvspan->min_reg_index;
+ min_reg_index = gvspan->min_reg_index;
+ max_reg_index = gvspan->max_reg_index;
+ assert(0 <= reg_index);
+ assert(reg_index < gd_header->n_regions);
+ gvt = GET_REAL_GVT(gvspan->gvt_array[reg_index - min_reg_index]);
+ assert(NULL != gvt);
+ gv_target = gvt;
+ gv_cur_region = gd_header->regions + reg_index;
+ change_reg();
+ SET_DISP_TRIGVN(gv_cur_region, disp_trigvn, disp_trigvn_len, trigvn, trigvn_len);
+ /* Save values[] and value_len[] arrays since they might be overwritten inside "trigupdrec_reg"
+ * but we need the unmodified values for each call to that function.
+ */
+ assert(SIZEOF(value_len) == SIZEOF(save_value_len));
+ memcpy(save_value_len, value_len, SIZEOF(value_len));
+ assert(SIZEOF(values) == SIZEOF(save_values));
+ memcpy(save_values, values, SIZEOF(values));
+ } else
+ {
+ memcpy(disp_trigvn, trigvn, trigvn_len);
+ disp_trigvn_len = trigvn_len;
+ disp_trigvn[disp_trigvn_len] = '\0'; /* null terminate just in case */
+ }
+ jnl_format_done = FALSE;
+ new_name_check_done = FALSE;
+ first_error = TRUE;
+ overall_trig_status = STATS_UNCHANGED_TRIGFILE;
+ do
+ { /* At this point gv_cur_region/cs_addrs/gv_target already point to the correct region.
+ * For a spanning global, they point to one of the spanned regions in each iteration of the do-while loop below.
+ */
+ this_trig_status = trigupdrec_reg(trigvn, trigvn_len, &jnl_format_done, &trigjrec,
+ &new_name_check_done, &new_name, &values[0], &value_len[0], add_delete,
+ &kill_trigger_hash, &set_trigger_hash, &disp_trigvn[0], disp_trigvn_len, trig_stats,
+ &first_gtmio, utilprefix, &utilprefixlen);
+ assert((STATS_UNCHANGED_TRIGFILE == this_trig_status) || (STATS_NOERROR_TRIGFILE == this_trig_status)
+ || (STATS_ERROR_TRIGFILE == this_trig_status));
+ if (STATS_ERROR_TRIGFILE == this_trig_status)
+ {
+ if (first_error)
+ {
+ trig_stats[STATS_ERROR_TRIGFILE]++;
+ first_error = FALSE;
+ }
+ overall_trig_status = STATS_ERROR_TRIGFILE;
+ } else if (STATS_UNCHANGED_TRIGFILE == overall_trig_status)
+ overall_trig_status = this_trig_status;
+ /* else if (STATS_NOERROR_TRIGFILE == overall_trig_status) : it is already what it should be */
+ /* else if (STATS_ERROR_TRIGFILE == overall_trig_status) : it is already what it should be */
+ if (NULL == gvspan)
+ break;
+ if (reg_index >= max_reg_index)
+ break;
+ do
+ {
+ reg_index++;
+ assert(reg_index <= max_reg_index);
+ assert(reg_index < gd_header->n_regions);
+ gvt = GET_REAL_GVT(gvspan->gvt_array[reg_index - min_reg_index]);
+ if (NULL == gvt)
+ {
+ assert(reg_index < max_reg_index);
+ continue;
+ }
+ gv_target = gvt;
+ gv_cur_region = gd_header->regions + reg_index;
+ change_reg();
+ SET_DISP_TRIGVN(gv_cur_region, disp_trigvn, disp_trigvn_len, trigvn, trigvn_len);
+ /* Restore values[] and value_len[] before next call to "trigupdrec_reg" */
+ assert(SIZEOF(value_len) == SIZEOF(save_value_len));
+ memcpy(value_len, save_value_len, SIZEOF(save_value_len));
+ assert(SIZEOF(values) == SIZEOF(save_values));
+ memcpy(values, save_values, SIZEOF(save_values));
+ break;
+ } while (TRUE);
+ } while (TRUE);
+ if ((STATS_UNCHANGED_TRIGFILE == overall_trig_status) || (STATS_NOERROR_TRIGFILE == overall_trig_status))
+ {
+ trig_stats[overall_trig_status]++;
+ return TRIG_SUCCESS;
+ } else
+ {
+ assert(STATS_ERROR_TRIGFILE == overall_trig_status);
+ return TRIG_FAILURE;
+ }
+}
+
+STATICFNDEF trig_stats_t trigupdrec_reg(char *trigvn, int trigvn_len, boolean_t *jnl_format_done, mval *trigjrec,
+ boolean_t *new_name_check_done, boolean_t *new_name_ptr, char **values, uint4 *value_len, char add_delete,
+ stringkey *kill_trigger_hash, stringkey *set_trigger_hash, char *disp_trigvn, int disp_trigvn_len, uint4 *trig_stats,
+ boolean_t *first_gtmio, char *utilprefix, int *utilprefixlen)
+{
+ mval trigname[NUM_OPRS]; /* names of matching kill and/or set trigger */
+ boolean_t new_name;
+ sgmnt_addrs *csa;
+ mval dummymval;
+ boolean_t skip_set_trigger, trigger_exists;
+ mval trigger_count;
+ boolean_t newtrigger;
+ int set_index, kill_index, tmp_index;
+ boolean_t db_matched_kill, db_matched_set, tmp_matched_kill, tmp_matched_set;
+ boolean_t full_match, new_match;
+ boolean_t kill_cmp, set_cmp;
+ boolean_t is_set;
+ int oprtype, oprstart, oprend, set_kill_bitmask;
+ char *oprname[] = { "Non-SET", "SET", "SET and/or Non-SET"}; /* index 0 corresponds to OPR_KILL,
+ * 1 to OPR_SET,
+ * 2 if OPR_SETKILL
+ */
+ char *opname;
+ int4 updates;
+ uint4 trigload_status;
+ mval *trig_cnt_ptr;
+ int num;
+ boolean_t result;
+ int sub_indx;
+ int4 max_len;
+ mval xecute_index, xecute_size;
+ int4 offset;
+ char *ptr1;
+ mval mv_hash;
+ char trig_name[MAX_USER_TRIGNAME_LEN + 2]; /* One spot for '#' delimiter and one for trailing '\0' */
+
+ csa = cs_addrs;
+ if (NULL == csa) /* Remote region */
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_REMOTEDBNOTRIG, 4, trigvn_len, trigvn, REG_LEN_STR(gv_cur_region));
if (gv_cur_region->read_only)
- rts_error_csa(CSA_ARG(gv_target->gd_csa) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(gv_cur_region));
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(gv_cur_region));
assert(cs_addrs == gv_target->gd_csa);
- csa = cs_addrs;
- /* Now that the gv_target of the global the trigger refers to is setup, check if we are attempting to modify/delete a
- * trigger for a global that has already had a trigger fire in this transaction. For these single-region (at a time)
- * checks, we can do them all the time as they are cheap.
- */
- if (gv_target->trig_local_tn == local_tn)
- rts_error_csa(CSA_ARG(csa) VARLSTCNT(1) ERR_TRIGMODINTP);
csa->incr_db_trigger_cycle = TRUE; /* so that we increment csd->db_trigger_cycle at commit time */
if (dollar_ztrigger_invoked)
- { /* increment db_dztrigger_cycle so that next gvcst_put/gvcst_kill in this transaction, on this region, will re-read
- * triggers. Note that the below increment happens for every record added. So, even if a single trigger file loaded
- * multiple triggers on the same region, db_dztrigger_cycle will be incremented more than one for same transaction.
- * This is considered okay since we only need db_dztrigger_cycle to be equal to a different value than
- * gvt->db_dztrigger_cycle
+ { /* increment db_dztrigger_cycle so that next gvcst_put/gvcst_kill in this transaction, on this region,
+ * will re-read triggers. Note that the below increment happens for every record added. So, even if a
+ * single trigger file loaded multiple triggers on the same region, db_dztrigger_cycle will be incremented
+ * more than one for same transaction. This is considered okay since we only need db_dztrigger_cycle to
+ * be equal to a different value than gvt->db_dztrigger_cycle.
*/
csa->db_dztrigger_cycle++;
}
- if (JNL_WRITE_LOGICAL_RECS(csa))
- {
- assert(!gv_cur_region->read_only);
- /* Attach to jnlpool. Normally SET or KILL of the ^#t records take care of this but in case this is a NO-OP
- * trigger operation that wont happen and we still want to write a TLGTRIG/ULGTRIG journal record. Hence
- * the need to do this.
+ if (!*jnl_format_done && JNL_WRITE_LOGICAL_RECS(csa))
+ { /* Attach to jnlpool if replication is turned on. Normally SET or KILL of the ^#t records take care of this
+ * but in case this is a NO-OP trigger operation that wont happen and we still want to write a
+ * TLGTRIG/ULGTRIG journal record. Hence the need to do this. Also write a LGTRIG record in just one region
+ * in case this is a global spanning multiple regions.
*/
JNLPOOL_INIT_IF_NEEDED(csa, csa->hdr, csa->nl);
assert(dollar_tlevel);
T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_TRIGLOADFAIL); /* needed to set update_trans TRUE on this region
* even if NO db updates happen to ^#t nodes. */
- jnl_format(JNL_LGTRIG, NULL, &trigjrec, 0);
+ jnl_format(JNL_LGTRIG, NULL, trigjrec, 0);
+ *jnl_format_done = TRUE;
}
SET_GVTARGET_TO_HASHT_GBL(csa);
INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
- new_name = check_unique_trigger_name(trigvn, trigvn_len, values[TRIGNAME_SUB], value_len[TRIGNAME_SUB]);
- cmd_modified = skip_set_trigger = newtrigger = FALSE;
- trigindx = 1;
+ if (csa->hdr->hasht_upgrade_needed)
+ { /* ^#t needs to be upgraded first before reading/updating it. Cannot proceed. */
+ if (0 == gv_target->root)
+ {
+ csa->hdr->hasht_upgrade_needed = FALSE; /* Reset now that we know there is no ^#t global in this db.
+ * Note: It is safe to do so even if we dont hold crit.
+ */
+ } else
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_NEEDTRIGUPGRD, 2, DB_LEN_STR(gv_cur_region));
+ }
+ if (!*new_name_check_done)
+ { /* Make sure below call is done only ONCE for a global spanning multiple regions since this call goes
+ * through all regions in the gld to figure out if a user-defined trigger name is unique.
+ */
+ new_name = check_unique_trigger_name_full(values, value_len, &dummymval, &new_match,
+ trigvn, trigvn_len, set_trigger_hash, kill_trigger_hash);
+ *new_name_ptr = new_name;
+ *new_name_check_done = TRUE;
+ } else
+ new_name = *new_name_ptr;
+ skip_set_trigger = FALSE;
assert(('+' == add_delete) || ('-' == add_delete)); /* Has to be + or - */
- if (0 != gv_target->root)
+ if (gv_target->root)
{
BUILD_HASHT_SUB_SUB_CURRKEY(trigvn, trigvn_len, LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT));
if (gvcst_get(&trigger_count))
{
- if (trigger_already_exists(trigvn, trigvn_len, values, value_len, &trigindx, &kill_index, &set_cmp,
- &kill_cmp, &full_match, &set_trigger_hash, &kill_trigger_hash,
- &reportname, &reportnamealt))
+ trigger_exists = trigger_already_exists(trigvn, trigvn_len, values, value_len,
+ set_trigger_hash, kill_trigger_hash,
+ &set_index, &kill_index,
+ &db_matched_set, &db_matched_kill, &full_match,
+ &trigname[OPR_SET], &trigname[OPR_KILL]);
+ newtrigger = FALSE;
+ } else
+ {
+ newtrigger = TRUE;
+ trigger_exists = FALSE;
+ }
+ } else
+ {
+ newtrigger = TRUE;
+ trigger_exists = FALSE;
+ }
+ set_cmp = (NULL != strchr(values[CMD_SUB], 'S'));
+ kill_cmp = ((NULL != strchr(values[CMD_SUB], 'K')) || (NULL != strchr(values[CMD_SUB], 'R')));
+ updates = 0;
+ trigload_status = STATS_UNCHANGED_TRIGFILE;
+ if (trigger_exists)
+ {
+ if ((-1 != kill_index) && (set_index || set_cmp) && value_len[TRIGNAME_SUB])
+ { /* Cannot match two different triggers (corresponding to "kill_index" and "set_index")
+ * with the same user defined name. Note that it is possible if set_index==0 that the
+ * set type trigger does not exist yet but will be created by this call to trigger_update_rec.
+ * Treat that case too as if the separate set trigger existed.
+ */
+ UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+ if (set_index)
+ util_out_print_gtmio("Error : Input trigger on ^!AD with trigger name !AD" \
+ " cannot match two different triggers named !AD and !AD at the same time",
+ FLUSH, disp_trigvn_len, disp_trigvn,
+ value_len[TRIGNAME_SUB], values[TRIGNAME_SUB],
+ trigname[OPR_KILL].str.len, trigname[OPR_KILL].str.addr,
+ trigname[OPR_SET].str.len, trigname[OPR_SET].str.addr);
+ else
+ util_out_print_gtmio("Error : Input trigger on ^!AD with trigger name !AD" \
+ " cannot match a trigger named !AD and a to-be-created SET trigger" \
+ " at the same time", FLUSH, disp_trigvn_len, disp_trigvn,
+ value_len[TRIGNAME_SUB], values[TRIGNAME_SUB],
+ trigname[OPR_KILL].str.len, trigname[OPR_KILL].str.addr);
+ return STATS_ERROR_TRIGFILE;
+ }
+ assert(new_name || !new_match || full_match);
+ if (!new_name && ('+' == add_delete) && !full_match)
+ {
+ opname = (!set_cmp ? oprname[OPR_KILL] : (!kill_cmp ? oprname[OPR_SET] : oprname[OPR_SETKILL]));
+ TRIGGER_SAME_NAME_EXISTS_ERROR(opname, disp_trigvn_len, disp_trigvn);
+ }
+ oprstart = (-1 != kill_index) ? OPR_KILL : (OPR_KILL + 1);
+ oprend = (0 != set_index) ? (OPR_SET + 1) : OPR_SET;
+ assert(NUM_OPRS == (OPR_SET + 1));
+ assert(ARRAYSIZE(oprname) == (OPR_SET + 2));
+ set_kill_bitmask = OPR_SETKILL;
+ for (oprtype = oprstart; oprtype < oprend; oprtype++)
+ {
+ assert((OPR_KILL == oprtype) || (OPR_SET == oprtype));
+ if (OPR_KILL == oprtype)
+ {
+ tmp_matched_set = FALSE;
+ tmp_matched_kill = TRUE;
+ tmp_index = kill_index;
+ is_set = FALSE;
+ if (0 != set_index)
+ { /* SET & KILL triggers are separate. This is the KILL trigger only invocation */
+ assert(set_cmp);
+ assert(kill_cmp);
+ set_kill_bitmask = OPR_KILL;
+ }
+ opname = oprname[OPR_KILL];
+ } else
+ {
+ tmp_matched_set = db_matched_set;
+ tmp_matched_kill = db_matched_kill;
+ tmp_index = set_index;
+ is_set = TRUE;
+ if (OPR_KILL == oprstart)
+ {
+ assert(set_cmp);
+ assert(kill_cmp);
+ set_kill_bitmask = OPR_SET;
+ }
+ opname = oprname[OPR_SET];
+ }
+ updates = modify_record(trigvn, trigvn_len, add_delete, tmp_index, values, value_len,
+ &trigger_count, tmp_matched_set, tmp_matched_kill,
+ kill_trigger_hash, set_trigger_hash, set_kill_bitmask);
+ if (0 > updates)
{
- if (!new_name && ('+' == add_delete) && (!full_match))
+ switch (updates)
{
- TRIGGER_SAME_NAME_EXISTS_ERROR;
+ case INVALID_LABEL:
+ UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+ util_out_print_gtmio("Error : Current trigger format not compatible to update " \
+ "the trigger on ^!AD named !AD", FLUSH, disp_trigvn_len, disp_trigvn,
+ trigname[oprtype].str.len, trigname[oprtype].str.addr);
+ return STATS_ERROR_TRIGFILE;
+ case KEY_TOO_LONG:
+ UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+ util_out_print_gtmio("Error : ^!AD trigger - key larger than max key size", FLUSH,
+ disp_trigvn_len, disp_trigvn);
+ return STATS_ERROR_TRIGFILE;
+ case VAL_TOO_LONG:
+ UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+ util_out_print_gtmio("Error : ^!AD trigger - value larger than record size", FLUSH,
+ disp_trigvn_len, disp_trigvn);
+ return STATS_ERROR_TRIGFILE;
+ case K_ZTK_CONFLICT:
+ UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+ util_out_print_gtmio("Error : Command options !AD incompatible with trigger on " \
+ "^!AD named !AD", FLUSH, value_len[CMD_SUB], values[CMD_SUB],
+ disp_trigvn_len, disp_trigvn,
+ trigname[oprtype].str.len, trigname[oprtype].str.addr);
+ return STATS_ERROR_TRIGFILE;
+ case ADD_SET_NOCHNG_KILL_TRIG:
+ assert(!is_set);
+ UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+ util_out_print_gtmio("!AZ trigger on ^!AD already present in trigger named !AD" \
+ " - no action taken", FLUSH, opname,
+ disp_trigvn_len, disp_trigvn,
+ trigname[oprtype].str.len, trigname[oprtype].str.addr);
+ /* kill trigger is unchanged but set trigger (if present in a different trigger)
+ * needs to be processed separately.
+ */
+ break;
+ case ADD_SET_MODIFY_KILL_TRIG:
+ assert(!is_set);
+ UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+ util_out_print_gtmio("Modified !AZ trigger on ^!AD named !AD",
+ FLUSH, opname, disp_trigvn_len, disp_trigvn,
+ trigname[oprtype].str.len, trigname[oprtype].str.addr);
+ trig_stats[STATS_MODIFIED]++;
+ trigload_status = STATS_NOERROR_TRIGFILE;
+ break;
+ case OPTIONS_CMDS_CONFLICT:
+ UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+ util_out_print_gtmio("Error : Specified options and commands cannot both be different" \
+ " from those in trigger on ^!AD named !AD", FLUSH, disp_trigvn_len, disp_trigvn,
+ trigname[oprtype].str.len, trigname[oprtype].str.addr);
+ return STATS_ERROR_TRIGFILE;
+ case NAME_CMDS_CONFLICT:
+ UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+ util_out_print_gtmio("Error : Specified name !AD different from that of trigger" \
+ " on ^!AD named !AD but specified commands do not contain those in trigger",
+ FLUSH, value_len[TRIGNAME_SUB], values[TRIGNAME_SUB],
+ disp_trigvn_len, disp_trigvn,
+ trigname[oprtype].str.len, trigname[oprtype].str.addr);
+ return STATS_ERROR_TRIGFILE;
+ default:
+ assertpro(FALSE && updates);
+ break;
}
- if (-1 != kill_index)
+ } else
+ {
+ skip_set_trigger = is_set;
+ if ((updates & (ADD_UPDATE_NAME | ADD_UPDATE_CMDS | ADD_UPDATE_OPTIONS))
+ || (updates & (SUB_UPDATE_NAME | SUB_UPDATE_CMDS)))
{
- if (0 != value_len[TRIGNAME_SUB])
- { /* can't match two different trigger with a user defined name */
- trig_stats[STATS_ERROR]++;
- util_out_print_gtmio("Conflicting trigger definition for global ^!AD. Definition " \
- "matches trigger named !AD and attempts to create a new trigger named !AD",
- FLUSH, trigvn_len, trigvn, reportnamealt.str.len, reportnamealt.str.addr,
- value_len[TRIGNAME_SUB], values[TRIGNAME_SUB]);
- return TRIG_FAILURE;
+ trig_stats[STATS_MODIFIED]++;
+ trigload_status = STATS_NOERROR_TRIGFILE;
+ if (0 == trig_stats[STATS_ERROR_TRIGFILE])
+ {
+ if (-1 == kill_index)
+ opname = (!set_cmp ? oprname[OPR_KILL]
+ : (!kill_cmp ? oprname[OPR_SET] : oprname[OPR_SETKILL]));
+ UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+ util_out_print_gtmio("Modified !AZ trigger on ^!AD named !AD", FLUSH,
+ opname, disp_trigvn_len, disp_trigvn,
+ trigname[oprtype].str.len, trigname[oprtype].str.addr);
}
- updates = modify_record(trigvn, trigvn_len, add_delete, kill_index, values, value_len,
- &trigger_count, FALSE, TRUE, &kill_trigger_hash, &set_trigger_hash);
- switch (updates)
+ } else if (updates & DELETE_REC)
+ {
+ trig_stats[STATS_DELETED]++;
+ trigload_status = STATS_NOERROR_TRIGFILE;
+ if (0 == trig_stats[STATS_ERROR_TRIGFILE])
{
- case INVALID_LABEL:
- trig_stats[STATS_ERROR]++;
- util_out_print_gtmio("Current trigger format not compatible to update " \
- "the trigger on ^!AD named !AD", FLUSH, trigvn_len, trigvn,
- reportnamealt.str.len, reportnamealt.str.addr);
- return TRIG_FAILURE;
- case VAL_TOO_LONG:
- trig_stats[STATS_ERROR]++;
- util_out_print_gtmio("^!AD trigger - value larger than record size", FLUSH,
- trigvn_len, trigvn);
- return TRIG_FAILURE;
- case K_ZTK_CONFLICT:
- trig_stats[STATS_ERROR]++;
- util_out_print_gtmio("Command options !AD incompatible with trigger on " \
- "^!AD named !AD", FLUSH, value_len[CMD_SUB], values[CMD_SUB],
- trigvn_len, trigvn, reportnamealt.str.len, reportnamealt.str.addr);
- return TRIG_FAILURE;
- default:
- if ((0 != (updates & ADD_UPDATE_CMDS)) ||
- (0 != (updates & SUB_UPDATE_CMDS)))
- {
- if (0 == trig_stats[STATS_ERROR])
- util_out_print_gtmio("Updated trigger on ^!AD named " \
- "!AD and ", NOFLUSH, trigvn_len,
- trigvn, reportnamealt.str.len,
- reportnamealt.str.addr);
- trig_stats[STATS_MODIFIED]++;
- } else if ((0 != (updates & ADD_UPDATE_NAME)) ||
- (0 != (updates & SUB_UPDATE_NAME)) ||
- (0 != (updates & SUB_UPDATE_OPTIONS)) ||
- (0 != (updates & ADD_UPDATE_OPTIONS)))
- { /* NAME and OPTIONS cannot change on K-type match */
- assertpro(FALSE);
- } else if (0 != (updates & DELETE_REC))
- {
- if (0 == trig_stats[STATS_ERROR])
- util_out_print_gtmio("Deleted trigger on ^!AD named "\
- "!AD and ", NOFLUSH, trigvn_len,
- trigvn, reportnamealt.str.len,
- reportnamealt.str.addr);
- trig_stats[STATS_DELETED]++;
- /* if trigger deleted, search for possible new SET trigger index */
- if(kill_index < trigindx &&
- !(trigger_already_exists(trigvn, trigvn_len, values, value_len,
- &trigindx, &kill_index,
- &set_cmp, &kill_cmp, &full_match,
- &set_trigger_hash, &kill_trigger_hash,
- &reportname, &reportnamealt)))
- { /* SET trigger found previously is not found again */
- if (CDB_STAGNATE > t_tries)
- t_retry(cdb_sc_triggermod);
- else
- {
- assert(WBTEST_HELPOUT_TRIGDEFBAD == \
- gtm_white_box_test_case_number);
- trig_stats[STATS_ERROR]++;
- util_out_print_gtmio("Previously found trigger on" \
- "^!AD ,named !AD but cannot " \
- "find it again",
- FLUSH, trigvn_len, trigvn,
- reportnamealt.str.len,
- reportnamealt.str.addr);
- }
- return TRIG_FAILURE;
- }
- } else
- {
- util_out_print_gtmio("Trigger on ^!AD already present " \
- "-- same as trigger named !AD and ",
- NOFLUSH, trigvn_len, trigvn,
- reportname.str.len, reportname.str.addr);
- trig_stats[STATS_UNCHANGED]++;
- }
+ if (-1 == kill_index)
+ opname = (!set_cmp ? oprname[OPR_KILL]
+ : (!kill_cmp ? oprname[OPR_SET] : oprname[OPR_SETKILL]));
+ UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+ util_out_print_gtmio("Deleted !AZ trigger on ^!AD named !AD",
+ FLUSH, opname, disp_trigvn_len, disp_trigvn,
+ trigname[oprtype].str.len, trigname[oprtype].str.addr);
}
- }
- updates = modify_record(trigvn, trigvn_len, add_delete, trigindx, values, value_len,
- &trigger_count, set_cmp, kill_cmp, &kill_trigger_hash, &set_trigger_hash);
- switch (updates)
+ /* if KILL trigger deleted, search for possible new SET trigger index */
+ if (!is_set && (kill_index < set_index)
+ && !(trigger_already_exists(trigvn, trigvn_len, values, value_len,
+ set_trigger_hash, kill_trigger_hash, &set_index,
+ &tmp_index, &db_matched_set, &db_matched_kill,
+ &full_match, &trigname[oprtype], &trigname[oprtype])))
+ { /* SET trigger found previously is not found again */
+ if (CDB_STAGNATE > t_tries)
+ t_retry(cdb_sc_triggermod);
+ assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
+ util_out_print_gtmio("Error : Previously found SET trigger " \
+ "on ^!AD, named !AD but cannot find it again",
+ FLUSH, disp_trigvn_len, disp_trigvn,
+ trigname[oprtype].str.len, trigname[oprtype].str.addr);
+ return STATS_ERROR_TRIGFILE;
+ }
+ } else if ('+' == add_delete)
{
- case ADD_NEW_TRIGGER:
- if (0 != value_len[TRIGNAME_SUB])
- { /* can't add a new trigger when you already matched on a name */
- trig_stats[STATS_ERROR]++;
- util_out_print_gtmio("Conflicting trigger definition for global ^!AD." \
- " Definition matches trigger named !AD and attempts" \
- " to create a new trigger named !AD", FLUSH,
- trigvn_len, trigvn,
- reportname.str.len, reportname.str.addr,
- value_len[TRIGNAME_SUB], values[TRIGNAME_SUB]);
- return TRIG_FAILURE;
- }
- cmd_modified = TRUE;
- trig_cnt_ptr = &trigger_count;
- num = mval2i(trig_cnt_ptr);
- trigindx = ++num;
- i2mval(&trigger_count, num);
- break;
- case INVALID_LABEL:
- trig_stats[STATS_ERROR]++;
- util_out_print_gtmio("Current trigger format not compatible to update " \
- "the trigger on ^!AD named !AD", FLUSH, trigvn_len, trigvn,
- reportname.str.len, reportname.str.addr);
- return TRIG_FAILURE;
- case VAL_TOO_LONG:
- trig_stats[STATS_ERROR]++;
- util_out_print_gtmio("^!AD trigger - value larger than record size", FLUSH,
- trigvn_len, trigvn);
- return TRIG_FAILURE;
- case K_ZTK_CONFLICT:
- trig_stats[STATS_ERROR]++;
- util_out_print_gtmio("Command options !AD incompatible with trigger on " \
- "^!AD named !AD", FLUSH, value_len[CMD_SUB], values[CMD_SUB],
- trigvn_len, trigvn, reportname.str.len, reportname.str.addr);
- return TRIG_FAILURE;
- default:
- skip_set_trigger = TRUE;
- if ((0 != (updates & ADD_UPDATE_NAME)) || (0 != (updates & ADD_UPDATE_CMDS))
- || (0 != (updates & ADD_UPDATE_OPTIONS)))
- {
- i2mval(&trigger_count, trigindx);
- trig_stats[STATS_MODIFIED]++;
- if (0 == trig_stats[STATS_ERROR])
- util_out_print_gtmio("Updated trigger on ^!AD named !AD", FLUSH,
- trigvn_len, trigvn, reportname.str.len,
- reportname.str.addr);
- } else if (0 != (updates & DELETE_REC))
- {
- trig_stats[STATS_DELETED]++;
- if (0 == trig_stats[STATS_ERROR])
- util_out_print_gtmio("Deleted trigger on ^!AD named !AD",
- FLUSH, trigvn_len, trigvn,
- reportname.str.len, reportname.str.addr);
- } else if ((0 != (updates & SUB_UPDATE_NAME)) || (0 != (updates & SUB_UPDATE_CMDS))
- || (0 != (updates & SUB_UPDATE_OPTIONS)))
- {
- trig_stats[STATS_MODIFIED]++;
- if (0 == trig_stats[STATS_ERROR])
- util_out_print_gtmio("Updated trigger on ^!AD named !AD", FLUSH,
- trigvn_len, trigvn, reportname.str.len,
- reportname.str.addr);
- } else if ('+' == add_delete)
- {
- if (0 == trig_stats[STATS_ERROR])
- {
- util_out_print_gtmio("Trigger on ^!AD already present -- same" \
- " as trigger named !AD", FLUSH, trigvn_len, trigvn,
- reportname.str.len, reportname.str.addr);
- trig_stats[STATS_UNCHANGED]++;
- }
+ assert(0 == updates);
+ if (0 == trig_stats[STATS_ERROR_TRIGFILE])
+ {
+ if (-1 == kill_index)
+ opname = (!set_cmp ? oprname[OPR_KILL]
+ : (!kill_cmp ? oprname[OPR_SET] : oprname[OPR_SETKILL]));
+ UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+ util_out_print_gtmio("!AZ trigger on ^!AD already present " \
+ "in trigger named !AD - no action taken",
+ FLUSH, opname, disp_trigvn_len, disp_trigvn,
+ trigname[oprtype].str.len, trigname[oprtype].str.addr);
+ }
+ } else
+ {
+ assert(0 == updates);
+ if (0 == trig_stats[STATS_ERROR_TRIGFILE])
+ {
+ if (-1 == kill_index)
+ opname = (!set_cmp ? oprname[OPR_KILL]
+ : (!kill_cmp ? oprname[OPR_SET] : oprname[OPR_SETKILL]));
+ UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+ if (!value_len[TRIGNAME_SUB]
+ || ((trigname[oprtype].str.len == value_len[TRIGNAME_SUB])
+ && !memcmp(values[TRIGNAME_SUB], trigname[oprtype].str.addr,
+ value_len[TRIGNAME_SUB])))
+ { /* Trigger name matches input name or name was not specified (in which
+ * case name is considered to match). So the command specified
+ * does not exist for deletion.
+ */
+ util_out_print_gtmio("!AZ trigger on ^!AD not present in trigger " \
+ "named !AD - no action taken", FLUSH, opname,
+ disp_trigvn_len, disp_trigvn,
+ trigname[oprtype].str.len, trigname[oprtype].str.addr);
} else
{
- if (0 == trig_stats[STATS_ERROR])
- {
- util_out_print_gtmio("Trigger on ^!AD does not exist - " \
- "no action taken", FLUSH, trigvn_len, trigvn);
- trig_stats[STATS_UNCHANGED]++;
- }
+ util_out_print_gtmio("!AZ trigger on ^!AD matches trigger " \
+ "named !AD but not with specified name !AD " \
+ "- no action taken", FLUSH, opname,
+ disp_trigvn_len, disp_trigvn,
+ trigname[oprtype].str.len, trigname[oprtype].str.addr,
+ value_len[TRIGNAME_SUB], values[TRIGNAME_SUB]);
}
+ }
}
- } else if ('+' == add_delete)
- {
- assert(0 == trigindx);
- if (!new_name)
- {
- TRIGGER_SAME_NAME_EXISTS_ERROR;
- }
- trig_cnt_ptr = &trigger_count;
- num = mval2i(trig_cnt_ptr);
- trigindx = ++num;
- i2mval(&trigger_count, num);
- } else
- { /* '-' == add_delete */
- if (0 == trig_stats[STATS_ERROR])
- {
- trig_stats[STATS_UNCHANGED]++;
- util_out_print_gtmio("Trigger on ^!AD does not exist - no action taken", FLUSH,
- trigvn_len, trigvn);
- }
- skip_set_trigger = TRUE;
}
- } else
- newtrigger = TRUE;
- } else
- newtrigger = TRUE;
- if (newtrigger)
+ }
+ if (0 == set_index)
+ {
+ if (set_cmp)
+ { /* SET was specified in the CMD list but no trigger was found, so treat this
+ * as a trigger not existing case for both '+' and '-' cases of add_delete.
+ */
+ trigger_exists = FALSE;
+ assert(!newtrigger);
+ } else if (-1 != kill_index)
+ skip_set_trigger = TRUE;
+ }
+ }
+ if (newtrigger || !trigger_exists)
{
if ('-' == add_delete)
{
- if (0 == trig_stats[STATS_ERROR])
- util_out_print_gtmio("Trigger on ^!AD does not exist - no action taken",
- FLUSH, trigvn_len, trigvn);
- else
- trig_stats[STATS_DELETED]++;
+ if (0 == trig_stats[STATS_ERROR_TRIGFILE])
+ {
+ if (newtrigger)
+ opname = (!set_cmp ? oprname[OPR_KILL]
+ : (!kill_cmp ? oprname[OPR_SET] : oprname[OPR_SETKILL]));
+ else if (-1 == kill_index)
+ opname = (!set_cmp ? oprname[OPR_KILL]
+ : (!kill_cmp ? oprname[OPR_SET] : oprname[OPR_SETKILL]));
+ else
+ opname = oprname[OPR_SET];
+ UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+ /* At this point SET or KILL or both triggers specified might not exist hence the "and/or" */
+ util_out_print_gtmio("!AZ trigger on ^!AD does not exist - no action taken",
+ FLUSH, opname, disp_trigvn_len, disp_trigvn);
+ }
skip_set_trigger = TRUE;
} else
{
- if (!new_name)
+ if (!new_name && !new_match)
{
- TRIGGER_SAME_NAME_EXISTS_ERROR;
+ opname = (!set_cmp ? oprname[OPR_KILL] : (!kill_cmp ? oprname[OPR_SET] : oprname[OPR_SETKILL]));
+ TRIGGER_SAME_NAME_EXISTS_ERROR(opname, disp_trigvn_len, disp_trigvn);
+ }
+ if (newtrigger)
+ {
+ trigger_count = literal_one;
+ set_index = 1;
+ } else
+ {
+ assert(!trigger_exists);
+ assert(0 == set_index);
+ trig_cnt_ptr = &trigger_count;
+ num = mval2i(trig_cnt_ptr);
+ set_index = ++num;
+ i2mval(&trigger_count, num);
}
- trigger_count = literal_one;
}
}
/* Since a specified trigger name will grow by 1, copy it to a long enough array */
- if (((0 != (updates & ADD_UPDATE_NAME)) && ('-' != add_delete)) || !skip_set_trigger)
+ if (((updates & ADD_UPDATE_NAME) && ('+' == add_delete)) || !skip_set_trigger)
{
memcpy(trig_name, values[TRIGNAME_SUB], value_len[TRIGNAME_SUB] + 1);
values[TRIGNAME_SUB] = trig_name;
- result = gen_trigname_sequence(trigvn, trigvn_len, &trigger_count, values[TRIGNAME_SUB],
- value_len[TRIGNAME_SUB]);
+ result = gen_trigname_sequence(trigvn, trigvn_len, &trigger_count, values[TRIGNAME_SUB], value_len[TRIGNAME_SUB]);
if (SEQ_SUCCESS != result)
{
if (TOO_MANY_TRIGGERS == result)
- util_out_print_gtmio("^!AD trigger - Too many triggers", FLUSH, trigvn_len, trigvn);
- else
+ {
+ UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+ util_out_print_gtmio("Error : ^!AD trigger - Too many triggers", FLUSH,
+ disp_trigvn_len, disp_trigvn);
+ } else
{
TOO_LONG_REC_KEY_ERROR_MSG;
}
- trig_stats[STATS_ERROR]++;
- return TRIG_FAILURE;
+ return STATS_ERROR_TRIGFILE;
}
}
- if (!skip_set_trigger && (0 == trig_stats[STATS_ERROR]))
+ if (trig_stats[STATS_ERROR_TRIGFILE])
+ {
+ if ('+' == add_delete)
+ {
+ trig_stats[STATS_ADDED]++;
+ trigload_status = STATS_NOERROR_TRIGFILE;
+ }
+ UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+ util_out_print_gtmio("No errors processing trigger for global ^!AD", FLUSH, disp_trigvn_len, disp_trigvn);
+ } else if (!skip_set_trigger)
{
+ if (!newtrigger && (-1 != kill_index))
+ { /* KILL commands were separately processed in KILL trigger. So consider only SET as being specified */
+ value_len[CMD_SUB] = 1;
+ values[CMD_SUB][1] = '\0';
+ assert('S' == values[CMD_SUB][0]);
+ }
value_len[TRIGNAME_SUB] = STRLEN(values[TRIGNAME_SUB]);
values[CHSET_SUB] = (gtm_utf8_mode) ? UTF8_NAME : LITERAL_M;
value_len[CHSET_SUB] = STRLEN(values[CHSET_SUB]);
- /* set ^#t(GVN,"#LABEL") = "2" */
+ /* set ^#t(GVN,"#LABEL") = "3" */
SET_TRIGGER_GLOBAL_SUB_SUB_STR(trigvn, trigvn_len, LITERAL_HASHLABEL, STRLEN(LITERAL_HASHLABEL),
HASHT_GBL_CURLABEL, STRLEN(HASHT_GBL_CURLABEL), result);
IF_ERROR_THEN_TOO_LONG_ERROR_MSG_AND_RETURN_FAILURE(result);
- trigger_incr_cycle(trigvn, trigvn_len);
/* set ^#t(GVN,"#COUNT") = trigger_count */
SET_TRIGGER_GLOBAL_SUB_SUB_MVAL(trigvn, trigvn_len, LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT),
trigger_count, result);
IF_ERROR_THEN_TOO_LONG_ERROR_MSG_AND_RETURN_FAILURE(result);
+ /* Assert that BHASH and LHASH are not part of NUM_SUBS calculation (confirms the -2 done in #define of NUM_SUBS) */
+ assert(BHASH_SUB == NUM_SUBS);
+ assert(LHASH_SUB == (NUM_SUBS + 1));
for (sub_indx = 0; sub_indx < NUM_SUBS; sub_indx++)
{
if (0 >= value_len[sub_indx]) /* subscript index length is zero (no longer used), skip it */
@@ -1628,8 +1979,7 @@ boolean_t trigger_update_rec(char *trigger_rec, uint4 len, boolean_t noprompt, u
i2mval(&xecute_index, ++num);
BUILD_HASHT_SUB_MSUB_SUB_MSUB_CURRKEY(trigvn, trigvn_len, trigger_count,
trigger_subs[sub_indx], STRLEN(trigger_subs[sub_indx]), xecute_index);
- offset = MIN(gv_cur_region->max_rec_size - (gv_currkey->end + 1 + SIZEOF(rec_hdr)),
- max_len);
+ offset = MIN(gv_cur_region->max_rec_size, max_len);
/* set ^#t(GVN,trigger_count,"XECUTE",num) = xecute string[offset] */
SET_TRIGGER_GLOBAL_SUB_MSUB_SUB_MSUB_STR(trigvn, trigvn_len, trigger_count,
trigger_subs[sub_indx], STRLEN(trigger_subs[sub_indx]), xecute_index,
@@ -1641,31 +1991,31 @@ boolean_t trigger_update_rec(char *trigger_rec, uint4 len, boolean_t noprompt, u
}
}
}
- result = add_trigger_hash_entry(trigvn, trigvn_len, values[CMD_SUB], trigindx, TRUE, &kill_trigger_hash,
- &set_trigger_hash);
+ result = add_trigger_hash_entry(trigvn, trigvn_len, values[CMD_SUB], set_index, TRUE, kill_trigger_hash,
+ set_trigger_hash);
IF_ERROR_THEN_TOO_LONG_ERROR_MSG_AND_RETURN_FAILURE(result);
- MV_FORCE_UMVAL(&mv_hash, kill_trigger_hash.hash_code);
+ MV_FORCE_UMVAL(&mv_hash, kill_trigger_hash->hash_code);
SET_TRIGGER_GLOBAL_SUB_MSUB_SUB_MVAL(trigvn, trigvn_len, trigger_count,
trigger_subs[LHASH_SUB], STRLEN(trigger_subs[LHASH_SUB]), mv_hash, result);
IF_ERROR_THEN_TOO_LONG_ERROR_MSG_AND_RETURN_FAILURE(result);
- MV_FORCE_UMVAL(&mv_hash, set_trigger_hash.hash_code);
+ MV_FORCE_UMVAL(&mv_hash, set_trigger_hash->hash_code);
SET_TRIGGER_GLOBAL_SUB_MSUB_SUB_MVAL(trigvn, trigvn_len, trigger_count, trigger_subs[BHASH_SUB],
STRLEN(trigger_subs[BHASH_SUB]), mv_hash, result);
IF_ERROR_THEN_TOO_LONG_ERROR_MSG_AND_RETURN_FAILURE(result);
+ trigload_status = STATS_NOERROR_TRIGFILE;
trig_stats[STATS_ADDED]++;
- if (cmd_modified)
- util_out_print_gtmio("Modified commands of the trigger on ^!AD named !AD", FLUSH, trigvn_len, trigvn,
- value_len[TRIGNAME_SUB], values[TRIGNAME_SUB]);
- else
- util_out_print_gtmio("Added trigger on ^!AD named !AD", FLUSH, trigvn_len, trigvn,
- value_len[TRIGNAME_SUB], values[TRIGNAME_SUB]);
- } else if (0 != trig_stats[STATS_ERROR])
- {
- if ('+' == add_delete)
- trig_stats[STATS_ADDED]++;
- util_out_print_gtmio("No errors", FLUSH);
+ UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+ /* Recompute set_cmp and kill_cmp in case values[CMD_SUB] was modified above */
+ set_cmp = (NULL != strchr(values[CMD_SUB], 'S'));
+ kill_cmp = ((NULL != strchr(values[CMD_SUB], 'K')) || (NULL != strchr(values[CMD_SUB], 'R')));
+ opname = (!set_cmp ? oprname[OPR_KILL] : (!kill_cmp ? oprname[OPR_SET] : oprname[OPR_SETKILL]));
+ util_out_print_gtmio("Added !AZ trigger on ^!AD named !AD", FLUSH, opname, disp_trigvn_len, disp_trigvn,
+ value_len[TRIGNAME_SUB] - 1, values[TRIGNAME_SUB]); /* -1 to remove # from tail of name */
}
- return TRIG_SUCCESS;
+ assert((STATS_UNCHANGED_TRIGFILE == trigload_status) || (STATS_NOERROR_TRIGFILE == trigload_status));
+ if ((0 == trig_stats[STATS_ERROR_TRIGFILE]) && (STATS_NOERROR_TRIGFILE == trigload_status))
+ trigger_incr_cycle(trigvn, trigvn_len); /* ^#t records changed in this function, increment cycle */
+ return trigload_status;
}
STATICFNDEF boolean_t trigger_update_rec_helper(char *trigger_rec, uint4 len, boolean_t noprompt, uint4 *trig_stats)
@@ -1686,6 +2036,8 @@ STATICFNDEF boolean_t trigger_update_rec_helper(char *trigger_rec, uint4 len, bo
{ /* Record cannot be committed - undo everything */
assert(donot_INVOKE_MUMTSTART);
DEBUG_ONLY(donot_INVOKE_MUMTSTART = FALSE);
+ /* Print $ztrigger/mupip-trigger output before rolling back TP */
+ TP_ZTRIGBUFF_PRINT;
OP_TROLLBACK(-1); /* returns but kills implicit transaction */
}
REVERT;
@@ -1718,7 +2070,7 @@ boolean_t trigger_update(char *trigger_rec, uint4 len)
* below after a successful op_tcommit of the $ZTRIGGER operation. We cannot check that dollar_tlevel is zero
* since the op_tstart done below can be a nested sub-transaction
*/
- op_tstart((IMPLICIT_TSTART + IMPLICIT_TRIGGER_TSTART), TRUE, &ts_mv, 0); /* 0 ==> save no locals but RESTART OK */
+ op_tstart(IMPLICIT_TSTART, TRUE, &ts_mv, 0); /* 0 ==> save no locals but RESTART OK */
/* The following for loop structure is similar to that in module trigger_trgfile.c (function
* "trigger_trgfile_tpwrap") and module gv_trigger.c (function gvtr_db_tpwrap) so any changes here
* might need to be reflected there as well.
@@ -1743,8 +2095,6 @@ boolean_t trigger_update(char *trigger_rec, uint4 len)
* trigger load logic already takes care of doing INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED before doing the
* actual trigger load
*/
- util_out_print_gtmio("RESTART has invalidated this transaction's previous output. New output follows.",
- FLUSH);
/* We expect the above function to return with either op_tcommit or a tp_restart invoked.
* In the case of op_tcommit, we expect dollar_tlevel to be 0 and if so we break out of the loop.
* In the tp_restart case, we expect a maximum of 4 tries/retries and much lesser usually.
diff --git a/sr_unix/trigger_update_protos.h b/sr_unix/trigger_update_protos.h
index d312ad6..a6a6c58 100644
--- a/sr_unix/trigger_update_protos.h
+++ b/sr_unix/trigger_update_protos.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2011 Fidelity Information Services, Inc *
+ * Copyright 2010, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -12,34 +12,41 @@
#ifndef TRIGGER_UPDATE_PROTOS_H_INCLUDED
#define TRIGGER_UPDATE_PROTOS_H_INCLUDED
-STATICFNDCL boolean_t check_unique_trigger_name(char *trigvn, int trigvn_len, char *trigger_name, uint4 trigger_name_len);
-STATICFNDEF boolean_t trigger_already_exists(char *trigvn, int trigvn_len, char **values, uint4 *value_len, int *set_index,
- int *kill_index, boolean_t *set_cmp_result, boolean_t *kill_cmp_result,
- boolean_t *full_match, stringkey *set_trigger_hash, stringkey *kill_trigger_hash,
- mval *setname, mval *killname);
+STATICFNDEF boolean_t trigger_already_exists(char *trigvn, int trigvn_len, char **values, uint4 *value_len, /* input parm */
+ stringkey *set_trigger_hash, stringkey *kill_trigger_hash, /* input parm */
+ int *set_index, int *kill_index, boolean_t *set_cmp_result, /* output parm */
+ boolean_t *kill_cmp_result, boolean_t *full_match, /* output parm */
+ mval *setname, mval *killname); /* output parm */
STATICFNDCL int4 modify_record(char *trigvn, int trigvn_len, char add_delete, int trigger_index, char **values, uint4 *value_len,
- mval *trigger_count, boolean_t set_compare, boolean_t kill_compare, stringkey *kill_hash,
- stringkey *set_hash);
-STATICFNDCL int4 gen_trigname_sequence(char *trigvn, int trigvn_len, mval *trigger_count, char *trigname_seq_str,
- uint4 seq_len);
+ mval *trigger_count, boolean_t db_matched_set, boolean_t db_matched_kill, stringkey *kill_hash,
+ stringkey *set_hash, int set_kill_bitmask);
+STATICFNDCL int4 gen_trigname_sequence(char *trigvn, int trigvn_len, mval *trigger_count, char *trigname_seq_str, uint4 seq_len);
STATICFNDCL int4 add_trigger_hash_entry(char *trigvn, int trigvn_len, char *cmd_value, int trigindx, boolean_t add_kill_hash,
stringkey *kill_hash, stringkey *set_hash);
STATICFNDCL int4 add_trigger_cmd_attributes(char *trigvn, int trigvn_len, int trigger_index, char *trig_cmds, char **values,
- uint4 *value_len, boolean_t set_compare, boolean_t kill_compare, stringkey *kill_hash,
- stringkey *set_hash);
+ uint4 *value_len, boolean_t db_matched_set, boolean_t db_matched_kill,
+ stringkey *kill_hash, stringkey *set_hash, uint4 db_cmd_bm, uint4 tf_cmd_bm);
STATICFNDCL int4 add_trigger_options_attributes(char *trigvn, int trigvn_len, int trigger_index, char *trig_options, char **values,
uint4 *value_len);
STATICFNDCL boolean_t subtract_trigger_cmd_attributes(char *trigvn, int trigvn_len, char *trig_cmds, char **values,
uint4 *value_len, boolean_t set_cmp, stringkey *kill_hash,
- stringkey *set_hash);
-STATICFNDCL boolean_t subtract_trigger_options_attributes(char *trigvn, int trigvn_len, char *trig_options, char *option_value);
+ stringkey *set_hash, int trigger_index, uint4 db_cmd_bm, uint4 tf_cmd_bm);
STATICFNDCL boolean_t validate_label(char *trigvn, int trigvn_len);
STATICFNDCL int4 update_commands(char *trigvn, int trigvn_len, int trigger_index, char *new_trig_cmds, char *orig_db_cmds);
-STATICFNDCL int4 update_options(char *trigvn, int trigvn_len, int trigger_index, char *trig_options, char *option_value);
STATICFNDCL int4 update_trigger_name(char *trigvn, int trigvn_len, int trigger_index, char *db_trig_name, char *tf_trig_name,
uint4 tf_trig_name_len);
STATICFNDCL boolean_t trigger_update_rec_helper(char *trigger_rec, uint4 len, boolean_t noprompt, uint4 *trig_stats);
+
+boolean_t trigger_name_search(char *trigger_name, uint4 trigger_name_len, mval *val, gd_region **found_reg);
+boolean_t check_unique_trigger_name_full(char **values, uint4 *value_len, mval *val, boolean_t *new_match,
+ char *trigvn, int trigvn_len, stringkey *kill_trigger_hash, stringkey *set_trigger_hash);
boolean_t trigger_update_rec(char *trigger_rec, uint4 len, boolean_t noprompt, uint4 *trig_stats, io_pair *trigfile_device,
int4 *record_num);
+
+STATICFNDCL trig_stats_t trigupdrec_reg(char *trigvn, int trigvn_len, boolean_t *jnl_format_done, mval *trigjrec,
+ boolean_t *new_name_check_done, boolean_t *new_name_ptr, char **values, uint4 *value_len, char add_delete,
+ stringkey *kill_trigger_hash, stringkey *set_trigger_hash, char *disp_trigvn, int disp_trigvn_len, uint4 *trig_stats,
+ boolean_t *first_gtmio, char *utilprefix, int *utilprefixlen);
+
boolean_t trigger_update(char *trigger_rec, uint4 len);
#endif
diff --git a/sr_unix/trigger_upgrade.c b/sr_unix/trigger_upgrade.c
new file mode 100644
index 0000000..3eccd46
--- /dev/null
+++ b/sr_unix/trigger_upgrade.c
@@ -0,0 +1,542 @@
+/****************************************************************
+ * *
+ * Copyright 2014 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#ifdef GTM_TRIGGER
+#include "gdsroot.h" /* for gdsfhead.h */
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h" /* for gdsfhead.h */
+#include "gdsfhead.h"
+#include "gdsblk.h"
+#include "filestruct.h"
+#include "trigger.h"
+#include <rtnhdr.h> /* needed for gv_trigger.h */
+#include "gv_trigger.h"
+#include "gtm_trigger.h"
+#include "gv_trigger_protos.h"
+#include "trigger_upgrade_protos.h"
+#include "tp_restart.h"
+#include "change_reg.h"
+#include "targ_alloc.h"
+#include "mv_stent.h"
+#include "op.h"
+#include "tp_frame.h"
+#include "gvcst_protos.h"
+#include "gvsub2str.h"
+#include "mvalconv.h"
+#include "op_tcommit.h"
+#include "format_targ_key.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "gdscc.h" /* needed for tp.h */
+#include "gdskill.h" /* needed for tp.h */
+#include "buddy_list.h" /* needed for tp.h */
+#include "hashtab_int4.h" /* needed for tp.h */
+#include "jnl.h" /* for jnl_format prototype and for tp.h */
+#include "tp.h" /* needed for T_BEGIN_SETORKILL_NONTP_OR_TP */
+#include "t_begin.h"
+#include "repl_sp.h" /* for F_CLOSE (used by JNL_FD_CLOSE) */
+#include "gtmio.h" /* for CLOSEFILE_RESET macro */
+
+GBLREF gd_region *gv_cur_region;
+GBLREF uint4 dollar_tlevel;
+GBLREF gv_key *gv_currkey;
+GBLREF unsigned int t_tries;
+#ifdef DEBUG
+GBLREF boolean_t is_replicator;
+GBLREF boolean_t donot_INVOKE_MUMTSTART;
+#endif
+
+error_def(ERR_TRIGLOADFAIL);
+
+LITREF mval literal_batch;
+LITREF mval literal_hashlabel;
+LITREF mval literal_hashcycle;
+LITREF mval literal_hashcount;
+#define TRIGGER_SUBSDEF(SUBSTYPE, SUBSNAME, LITMVALNAME, TRIGFILEQUAL, PARTOFHASH) LITREF mval LITMVALNAME;
+#include "trigger_subs_def.h"
+#undef TRIGGER_SUBSDEF
+
+DEFINE_NSB_CONDITION_HANDLER(trigger_upgrade_ch)
+
+STATICFNDCL void gvtr_set_hasht_gblsubs(mval *subs_mval, mval *set_mval);
+STATICFNDEF void gvtr_set_hashtrhash(char *trigvn, int trigvn_len, uint4 hash_code, int trigindx);
+
+STATICFNDEF void gvtr_set_hasht_gblsubs(mval *subs_mval, mval *set_mval)
+{
+ uint4 curend;
+ boolean_t was_null = FALSE, is_null = FALSE;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ curend = gv_currkey->end; /* note down gv_currkey->end before changing it so we can restore it before function returns */
+ assert(KEY_DELIMITER == gv_currkey->base[curend]);
+ assert(gv_target->gd_csa == cs_addrs);
+ COPY_SUBS_TO_GVCURRKEY(subs_mval, gv_cur_region, gv_currkey, was_null, is_null); /* updates gv_currkey */
+ MV_FORCE_STR(set_mval);
+ gvcst_put(set_mval);
+ gv_currkey->end = curend; /* reset gv_currkey->end to what it was at function entry */
+ gv_currkey->base[curend] = KEY_DELIMITER; /* restore terminator for entire key so key is well-formed */
+ return;
+}
+
+/* Set ^#t(<gbl>,"#TRHASH",hash_code,nnn)=<gbl>_$c(0)_trigindx where gv_currkey is ^#t(<gbl>).
+ * Note: This routine has code very similar to that in "add_trigger_hash_entry". There is just
+ * not enough commonality to justify merging the two.
+ */
+STATICFNDEF void gvtr_set_hashtrhash(char *trigvn, int trigvn_len, uint4 hash_code, int trigindx)
+{
+ uint4 curend;
+ boolean_t was_null = FALSE, is_null = FALSE;
+ mval tmpmval, mv_indx, *mv_indx_ptr;
+ mval mv_hash;
+ int hash_indx, num_len;
+ char name_and_index[MAX_MIDENT_LEN + 1 + MAX_DIGITS_IN_INT];
+ char *ptr;
+ char indx_str[MAX_DIGITS_IN_INT];
+ uint4 len;
+ int4 result;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ curend = gv_currkey->end; /* note down gv_currkey->end before changing it so we can restore it before function returns */
+ assert(KEY_DELIMITER == gv_currkey->base[curend]);
+ assert(gv_target->gd_csa == cs_addrs);
+ /* Set ^#t(<gvn>,"#TRHASH",kill_hash_code,i). To do that, first determine the
+ * highest i such that ^#t(<gvn>,"#TRHASH",kill_hash_code,i) exists. Set
+ * ^#t(<gvn>,"#TRHASH",kill_hash_code,i+1)=kill_hash_code in that case.
+ */
+ MV_FORCE_UMVAL(&mv_hash, hash_code);
+ BUILD_HASHT_SUB_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, "", 0);
+ op_zprevious(&mv_indx);
+ mv_indx_ptr = &mv_indx;
+ hash_indx = (0 == mv_indx.str.len) ? 1 : (mval2i(mv_indx_ptr) + 1);
+ i2mval(mv_indx_ptr, hash_indx);
+ MV_FORCE_STR(mv_indx_ptr);
+ /* Prepare the value of the SET */
+ num_len = 0;
+ I2A(indx_str, num_len, trigindx);
+ assert(MAX_MIDENT_LEN >= trigvn_len);
+ memcpy(name_and_index, trigvn, trigvn_len);
+ ptr = name_and_index + trigvn_len;
+ *ptr++ = '\0';
+ memcpy(ptr, indx_str, num_len);
+ len = trigvn_len + 1 + num_len;
+ /* Do the SET */
+ SET_TRIGGER_GLOBAL_SUB_SUB_MSUB_MSUB_STR(trigvn, trigvn_len,
+ LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, mv_indx, name_and_index, len, result);
+ assert(PUT_SUCCESS == result);
+ gv_currkey->end = curend; /* reset gv_currkey->end to what it was at function entry */
+ gv_currkey->base[curend] = KEY_DELIMITER; /* restore terminator for entire key so key is well-formed */
+ return;
+}
+
+/* Upgrade ^#t global in "reg" region */
+void trigger_upgrade(gd_region *reg)
+{
+ boolean_t trigger_status = TRIG_FAILURE;
+ boolean_t est_first_pass, do_upgrade, is_defined;
+ boolean_t was_null = FALSE, is_null = FALSE;
+ int loopcnt;
+ int seq_num, trig_seq_num;
+ DEBUG_ONLY(unsigned int lcl_t_tries;)
+ enum cdb_sc failure;
+ mval label, *label_mv;
+ mval tmpmval, xecuteimval, gvname, *tmpmv, *tmpmv2;
+ int4 result, tmpint4;
+ uint4 curend, gvname_prev, xecute_curend;
+ uint4 hash_code, kill_hash_code;
+ int count, i, xecutei, tncount;
+ char *trigname, *trigindex, *ptr;
+ char name_and_index[MAX_MIDENT_LEN + 1 + MAX_DIGITS_IN_INT];
+ char trigvn[MAX_MIDENT_LEN + 1 + MAX_DIGITS_IN_INT], nullbyte[1];
+ uint4 trigname_len, name_index_len;
+ int ilen;
+ sgmnt_addrs *csa;
+ jnl_private_control *jpc;
+ uint4 sts;
+ int close_res;
+ mval trigjrec;
+ char trigger_rec[] = "; ^#t physical upgrade from #LABEL 2 to #LABEL 3 (no logical change)";
+ hash128_state_t hash_state, kill_hash_state;
+ uint4 hash_totlen, kill_hash_totlen;
+# ifdef DEBUG
+ int save_dollar_tlevel;
+# endif
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ assert(gv_cur_region == reg);
+ assert(!dollar_tlevel); /* caller should have ensured this. this is needed as otherwise things get complicated. */
+ assert(!is_replicator); /* caller should have ensured this. this is needed so we dont bump jnl_seqno (if replicating) */
+ csa = &FILE_INFO(reg)->s_addrs;
+ assert(csa->hdr->hasht_upgrade_needed);
+ /* If before-image journaling is turned on in this region (does not matter if replication is turned on or not),
+ * once this transaction is done, we need to switch to new journal file and cut the back link because
+ * otherwise it is possible for backward journal recovery (or rollback) or source server to encounter
+ * the journal records generated in this ^#t-upgrade-transaction in which case they dont know to handle
+ * it properly (e.g. rollback or backward recovery does not know to restore csa->hdr->hasht_upgrade_needed
+ * if it rolls back this transaction). To achieve this, we set hold_onto_crit to TRUE and do the jnl link
+ * cut AFTER the transaction commits but before anyone else can sneak in to do any more updates.
+ * Since most often we expect databases to be journaled, we do this hold_onto_crit even for the non-journaled case.
+ */
+ grab_crit(reg);
+ csa->hold_onto_crit = TRUE;
+ DEBUG_ONLY(save_dollar_tlevel = dollar_tlevel);
+ assert(!donot_INVOKE_MUMTSTART);
+ DEBUG_ONLY(donot_INVOKE_MUMTSTART = TRUE);
+ op_tstart(IMPLICIT_TSTART, TRUE, &literal_batch, 0); /* 0 ==> save no locals but RESTART OK */
+ ESTABLISH_NORET(trigger_upgrade_ch, est_first_pass);
+ /* On a TP restart anywhere down below, this line is where the restart resumes execution from */
+ assert(donot_INVOKE_MUMTSTART); /* Make sure still set for every try/retry of TP transaction */
+ change_reg(); /* TP_CHANGE_REG wont work as we need to set sgm_info_ptr */
+ assert(NULL != cs_addrs);
+ assert(csa == cs_addrs);
+ SET_GVTARGET_TO_HASHT_GBL(csa); /* sets up gv_target */
+ assert(NULL != gv_target);
+ INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED; /* Needed to do every retry in case restart was due to an online rollback.
+ * This also sets up gv_currkey */
+ /* Do actual upgrade of ^#t global.
+ *
+ * Below is a sample layout of the pre-upgrade ^#t global
+ * -------------------------------------------------------
+ * ^#t("#TNAME","x")="a"_$C(0)_"1"
+ * ^#t("#TRHASH",89771515,1)="a"_$C(0)_"1"
+ * ^#t("#TRHASH",106937755,1)="a"_$C(0)_"1"
+ * ^#t("a",1,"BHASH")="106937755"
+ * ^#t("a",1,"CHSET")="M"
+ * ^#t("a",1,"CMD")="S"
+ * ^#t("a",1,"LHASH")="89771515"
+ * ^#t("a",1,"TRIGNAME")="x#"
+ * ^#t("a",1,"XECUTE")=" do ^twork"
+ * ^#t("a","#COUNT")="1"
+ * ^#t("a","#CYCLE")="1"
+ * ^#t("a","#LABEL")="2"
+ *
+ * Below is the upgraded layout of the same ^#t global
+ * -------------------------------------------------------
+ * ^#t("#LABEL")="3"
+ * ^#t("#TNAME","x")="a"_$C(0)_"1"
+ * ^#t("a",1,"BHASH")="71945627"
+ * ^#t("a",1,"CHSET")="M"
+ * ^#t("a",1,"CMD")="S"
+ * ^#t("a",1,"LHASH")="71945627"
+ * ^#t("a",1,"TRIGNAME")="x#"
+ * ^#t("a",1,"XECUTE")=" do ^twork"
+ * ^#t("a","#COUNT")="1"
+ * ^#t("a","#CYCLE")="2"
+ * ^#t("a","#LABEL")="3"
+ * ^#t("a","#TRHASH",71945627,1)="a"_$C(0)_"1"
+ *
+ * Key aspects of the format change
+ * ----------------------------------
+ * 1) New ^#t("#LABEL")="3" to indicate the format of the ^#t global. This is in addition to
+ * ^#t("a","#LABEL") etc. which is already there. This way we have a #LABEL for not just the installed
+ * triggers but also for the name information stored in the #TNAME nodes.
+ * 2) In the BHASH and LHASH fields. The hash computation is different so there are more chances of BHASH and LHASH
+ * matching in which case we store only one #TRHASH entry (instead of two). So thre is fewer ^#t records in the new
+ * format in most cases.
+ * 3) ^#t("a","#LABEL") bumps from 2 to 3. Similarly ^#t("a","#CYCLE") bumps by one (to make sure triggers for this
+ * global get re-read if and when we implement an -ONLINE upgrade).
+ * 4) DEFAULT used to have ^#t("#TNAME",...) nodes corresponding to triggers across ALL regions in the gbldir and
+ * other regions used to have NO ^#t("#TNAME",...) nodes whereas after the upgrade every region will have
+ * ^#t("#TNAME",...) nodes corresponding to triggers installed in that region. So it is safer to kill ^#t("#TNAME")
+ * nodes and add them as needed.
+ * 5) #TRHASH has moved from ^#t() to ^#t(<gbl>). So it is safer to kill ^#t("#TRHASH") nodes and add them as needed.
+ */
+ tmpmv = &tmpmval; /* At all points maintain this relationship. The two are used interchangeably below */
+ if (0 == gv_target->root)
+ do_upgrade = FALSE;
+ else
+ { /* Check if ^#t("#LABEL") exists. If so, upgrade already done. No need to do it again. */
+ is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_hashlabel, tmpmv);
+ assert(!is_defined
+ || (MV_IS_STRING(tmpmv) && (tmpmval.str.len == STR_LIT_LEN(HASHT_GBL_CURLABEL))
+ && !MEMCMP_LIT(tmpmval.str.addr, HASHT_GBL_CURLABEL)));
+ do_upgrade = !is_defined;
+ }
+ /* The below logic assumes ^#t global does not have any integrity errors */
+ assert(do_upgrade); /* caller should have not invoked us otherwise */
+ if (do_upgrade)
+ { /* kill ^#t("#TRHASH") and ^#t("#TNAME") first. These will be generated again as we process ^#t(<gbl>,...) nodes */
+ csa->incr_db_trigger_cycle = TRUE; /* so that we increment csd->db_trigger_cycle at commit time.
+ * this will force concurrent processes to read upgraded triggers.
+ */
+ if (JNL_WRITE_LOGICAL_RECS(csa))
+ { /* Note that the ^#t upgrade is a physical layout change. But it has no logical change (i.e. users
+ * will see the same MUPIP TRIGGER -SELECT output as before). So write only a dummy LGTRIG journal
+ * record for this operation. Hence write a string that starts with a trigger comment character ";".
+ */
+ assert(!gv_cur_region->read_only);
+ trigjrec.mvtype = MV_STR;
+ trigjrec.str.len = STRLEN(&trigger_rec[0]);
+ trigjrec.str.addr = &trigger_rec[0];
+ jnl_format(JNL_LGTRIG, NULL, &trigjrec, 0);
+ }
+ BUILD_HASHT_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME));
+ if (0 != gvcst_data())
+ gvcst_kill(TRUE);
+ BUILD_HASHT_SUB_CURRKEY(LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH));
+ if (0 != gvcst_data())
+ gvcst_kill(TRUE);
+ /* Loop through all global names for which ^#t(<gvn>) exists. The only first-level subscripts of ^#t starting
+ * with # are #TNAME and #TRHASH in collation order. So after #TRHASH we expect to find subscripts that are
+ * global names. Hence the HASHTRHASH code is placed AFTER the HASHTNAME code above.
+ */
+ TREF(gd_targ_gvnh_reg) = NULL; /* needed so op_gvorder below goes through gvcst_order (i.e. focuses only
+ * on the current region) and NOT through gvcst_spr_order (which does not
+ * apply anyways in the case of ^#t).
+ */
+ nullbyte[0] = '\0';
+ do
+ {
+ op_gvorder(&gvname);
+ if (0 == gvname.str.len)
+ break;
+ assert(ARRAYSIZE(trigvn) > gvname.str.len);
+ memcpy(&trigvn[0], gvname.str.addr, gvname.str.len);
+ gvname.str.addr = &trigvn[0]; /* point away from stringpool to avoid stp_gcol issues */
+ /* Save gv_currkey->prev so it is restored before next call to op_gvorder (which cares about this field).
+ * gv_currkey->prev gets tampered with in the for loop below (e.g. BUILD_HASHT_SUB_CURRKEY macro).
+ * No need to do this for gv_currkey->end since the body of the for loop takes care of restoring it.
+ */
+ gvname_prev = gv_currkey->prev;
+ BUILD_HASHT_SUB_CURRKEY(gvname.str.addr, gvname.str.len);
+ /* At this point, gv_currkey is ^#t(<gvn>) */
+ /* Increment ^#t(<gvn>,"#CYCLE") */
+ is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_hashcycle, tmpmv);
+ assert(is_defined);
+ tmpint4 = mval2i(tmpmv);
+ tmpint4++;
+ i2mval(tmpmv, tmpint4);
+ gvtr_set_hasht_gblsubs((mval *)&literal_hashcycle, tmpmv);
+ /* Read ^#t(<gvn>,"#COUNT") */
+ is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_hashcount, tmpmv);
+ if (is_defined)
+ {
+ tmpint4 = mval2i(tmpmv);
+ count = tmpint4;
+ } else
+ count = 0;
+ /* Set ^#t(<gvn>,"#LABEL")=3 */
+ tmpmval.mvtype = MV_STR;
+ tmpmval.str.addr = HASHT_GBL_CURLABEL;
+ tmpmval.str.len = STRLEN(HASHT_GBL_CURLABEL);
+ gvtr_set_hasht_gblsubs((mval *)&literal_hashlabel, tmpmv);
+ /* At this point, gv_currkey is ^#t(<gvn>) */
+ for (i = 1; i <= count; i++)
+ {
+ /* At this point, gv_currkey is ^#t(<gvn>) */
+ curend = gv_currkey->end; /* note gv_currkey->end before changing it so we can restore it later */
+ assert(KEY_DELIMITER == gv_currkey->base[curend]);
+ assert(gv_target->gd_csa == cs_addrs);
+ i2mval(tmpmv, i);
+ COPY_SUBS_TO_GVCURRKEY(tmpmv, gv_cur_region, gv_currkey, was_null, is_null);
+ /* At this point, gv_currkey is ^#t(<gvn>,i) */
+ /* Compute new LHASH and BHASH hash values.
+ * LHASH uses : GVSUBS, XECUTE
+ * BHASH uses : GVSUBS, XECUTE, DELIM, ZDELIM, PIECES
+ * So reach each of these pieces and compute hash along the way.
+ */
+ STR_PHASH_INIT(hash_state, hash_totlen);
+ STR_PHASH_PROCESS(hash_state, hash_totlen, gvname.str.addr, gvname.str.len);
+ STR_PHASH_PROCESS(hash_state, hash_totlen, nullbyte, 1);
+ /* Read in ^#t(<gvn>,i,"GVSUBS") */
+ is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_gvsubs, tmpmv);
+ if (is_defined)
+ {
+ STR_PHASH_PROCESS(hash_state, hash_totlen, tmpmval.str.addr, tmpmval.str.len);
+ STR_PHASH_PROCESS(hash_state, hash_totlen, nullbyte, 1);
+ }
+ /* Copy over SET hash state (2-tuple <state,totlen>) to KILL hash state before adding
+ * the PIECES, DELIM, ZDELIM portions (those are only part of the SET hash).
+ */
+ kill_hash_state = hash_state;
+ kill_hash_totlen = hash_totlen;
+ /* Read in ^#t(<gvn>,i,"PIECES") */
+ is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_pieces, tmpmv);
+ if (is_defined)
+ {
+ STR_PHASH_PROCESS(hash_state, hash_totlen, tmpmval.str.addr, tmpmval.str.len);
+ STR_PHASH_PROCESS(hash_state, hash_totlen, nullbyte, 1);
+ }
+ /* Read in ^#t(<gvn>,i,"DELIM") */
+ is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_delim, tmpmv);
+ if (is_defined)
+ {
+ STR_PHASH_PROCESS(hash_state, hash_totlen, tmpmval.str.addr, tmpmval.str.len);
+ STR_PHASH_PROCESS(hash_state, hash_totlen, nullbyte, 1);
+ }
+ /* Read in ^#t(<gvn>,i,"ZDELIM") */
+ is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_zdelim, tmpmv);
+ if (is_defined)
+ {
+ STR_PHASH_PROCESS(hash_state, hash_totlen, tmpmval.str.addr, tmpmval.str.len);
+ STR_PHASH_PROCESS(hash_state, hash_totlen, nullbyte, 1);
+ }
+ /* Read in ^#t(<gvn>,i,"XECUTE").
+ * Note: The XECUTE portion of the trigger definition is used in SET and KILL hash.
+ * But since we have started maintaining "hash_state" and "kill_hash_state" separately
+ * (due to PIECES, DELIM, ZDELIM) we need to update the hash for both using same input string.
+ */
+ is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_xecute, tmpmv);
+ if (is_defined)
+ {
+ STR_PHASH_PROCESS(hash_state, hash_totlen, tmpmval.str.addr, tmpmval.str.len);
+ STR_PHASH_PROCESS(kill_hash_state, kill_hash_totlen, tmpmval.str.addr, tmpmval.str.len);
+ } else
+ { /* Multi-line XECUTE string */
+ /* At this point, gv_currkey is ^#t(<gvn>,i) */
+ xecute_curend = gv_currkey->end; /* note gv_currkey->end so we can restore it later */
+ assert(KEY_DELIMITER == gv_currkey->base[xecute_curend]);
+ tmpmv2 = (mval *)&literal_xecute;
+ COPY_SUBS_TO_GVCURRKEY(tmpmv2, gv_cur_region, gv_currkey, was_null, is_null);
+ xecutei = 1;
+ do
+ {
+ i2mval(&xecuteimval, xecutei);
+ is_defined = gvtr_get_hasht_gblsubs(&xecuteimval, tmpmv);
+ if (!is_defined)
+ break;
+ STR_PHASH_PROCESS(hash_state, hash_totlen, tmpmval.str.addr, tmpmval.str.len);
+ STR_PHASH_PROCESS(kill_hash_state, kill_hash_totlen,
+ tmpmval.str.addr, tmpmval.str.len);
+ xecutei++;
+ } while (TRUE);
+ /* Restore gv_currkey to ^#t(<gvn>,i) */
+ gv_currkey->end = xecute_curend;
+ gv_currkey->base[xecute_curend] = KEY_DELIMITER;
+ }
+ STR_PHASH_RESULT(hash_state, hash_totlen, hash_code);
+ STR_PHASH_RESULT(kill_hash_state, kill_hash_totlen, kill_hash_code);
+ /* Set ^#t(<gvn>,i,"LHASH") */
+ i2mval(tmpmv, kill_hash_code);
+ gvtr_set_hasht_gblsubs((mval *)&literal_lhash, tmpmv);
+ /* Set ^#t(<gvn>,i,"BHASH") */
+ i2mval(tmpmv, hash_code);
+ gvtr_set_hasht_gblsubs((mval *)&literal_bhash, tmpmv);
+ /* Read in ^#t(<gvn>,i,"TRIGNAME") to determine if #SEQNUM/#TNCOUNT needs to be maintained */
+ is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_trigname, tmpmv);
+ assert(is_defined);
+ assert('#' == tmpmval.str.addr[tmpmval.str.len - 1]);
+ tmpmval.str.len--;
+ if (NULL != (ptr = memchr(tmpmval.str.addr, '#', tmpmval.str.len)))
+ { /* Auto-generated name. Need to maintain #SEQNUM/#TNCOUNT */
+ /* Take copy of trigger name into non-stringpool location to avoid stp_gcol issues */
+ trigname_len = ptr - tmpmval.str.addr;
+ ptr++;
+ name_index_len = (tmpmval.str.addr + tmpmval.str.len) - ptr;
+ assert(ARRAYSIZE(name_and_index) >= (trigname_len + 1 + name_index_len));
+ trigname = &name_and_index[0];
+ trigindex = ptr;
+ memcpy(trigname, tmpmval.str.addr, tmpmval.str.len);
+ A2I(ptr, ptr + name_index_len, trig_seq_num);
+ /* At this point, gv_currkey is ^#t(<gvn>,i) */
+ /* $get(^#t("#TNAME",GVN,"#SEQNUM")) */
+ BUILD_HASHT_SUB_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STR_LIT_LEN(LITERAL_HASHTNAME),
+ trigname, trigname_len, LITERAL_HASHSEQNUM, STR_LIT_LEN(LITERAL_HASHSEQNUM));
+ seq_num = gvcst_get(tmpmv) ? mval2i(tmpmv) : 0;
+ if (trig_seq_num > seq_num)
+ { /* Set ^#t("#TNAME",GVN,"#SEQNUM") = trig_seq_num */
+ SET_TRIGGER_GLOBAL_SUB_SUB_SUB_STR(LITERAL_HASHTNAME,
+ STR_LIT_LEN(LITERAL_HASHTNAME), trigname, trigname_len,
+ LITERAL_HASHSEQNUM, STR_LIT_LEN(LITERAL_HASHSEQNUM),
+ trigindex, name_index_len, result);
+ assert(PUT_SUCCESS == result);
+ }
+ /* set ^#t("#TNAME",GVN,"#TNCOUNT")++ */
+ BUILD_HASHT_SUB_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STR_LIT_LEN(LITERAL_HASHTNAME),
+ trigname, trigname_len, LITERAL_HASHTNCOUNT, STR_LIT_LEN(LITERAL_HASHTNCOUNT));
+ tncount = gvcst_get(tmpmv) ? mval2i(tmpmv) + 1 : 1;
+ i2mval(tmpmv, tncount);
+ SET_TRIGGER_GLOBAL_SUB_SUB_SUB_MVAL(LITERAL_HASHTNAME, STR_LIT_LEN(LITERAL_HASHTNAME),
+ trigname, trigname_len, LITERAL_HASHTNCOUNT, STR_LIT_LEN(LITERAL_HASHTNCOUNT),
+ tmpmval, result);
+ trigname_len += 1 + name_index_len; /* in preparation for ^#t("#TNAME") set below */
+ assert(PUT_SUCCESS == result);
+ BUILD_HASHT_SUB_CURRKEY(gvname.str.addr, gvname.str.len);
+ /* At this point, gv_currkey is ^#t(<gvn>) */
+ } else
+ {
+ /* Take copy of trigger name into non-stringpool location to avoid stp_gcol issues */
+ trigname = &name_and_index[0];
+ trigname_len = tmpmval.str.len; /* in preparation for ^#t("#TNAME") set below */
+ assert(ARRAYSIZE(name_and_index) > trigname_len);
+ memcpy(trigname, tmpmval.str.addr, trigname_len);
+ /* Restore gv_currkey to what it was at beginning of for loop iteration */
+ gv_currkey->end = curend;
+ gv_currkey->base[curend] = KEY_DELIMITER;
+ }
+ /* At this point, gv_currkey is ^#t(<gvn>) */
+ if (kill_hash_code != hash_code)
+ gvtr_set_hashtrhash(gvname.str.addr, gvname.str.len, kill_hash_code, i);
+ /* Set ^#t(<gvn>,"#TRHASH",hash_code,i) */
+ gvtr_set_hashtrhash(gvname.str.addr, gvname.str.len, hash_code, i);
+ /* Set ^#t("#TNAME",<trigname>)=<gvn>_$c(0)_<trigindx> */
+ /* The upgrade assumes that the region does not contain two triggers with the same name.
+ * V62000 and before could potentially have this out of design case. Once implemented
+ * the trigger integrity check will warn users of this edge case */
+ ptr = &trigvn[gvname.str.len];
+ *ptr++ = '\0';
+ ilen = 0;
+ I2A(ptr, ilen, i);
+ ptr += ilen;
+ assert(ptr <= ARRAYTOP(trigvn));
+ SET_TRIGGER_GLOBAL_SUB_SUB_STR(LITERAL_HASHTNAME, STR_LIT_LEN(LITERAL_HASHTNAME),
+ trigname, trigname_len, trigvn, ptr - gvname.str.addr, result);
+ assert(PUT_SUCCESS == result);
+ BUILD_HASHT_SUB_CURRKEY(gvname.str.addr, gvname.str.len);
+ /* At this point, gv_currkey is ^#t(<gvn>) */
+ }
+ /* At this point, gv_currkey is ^#t(<gvn>) i.e. gv_currkey->end is correct but gv_currkey->prev
+ * might have been tampered with. Restore it to proper value first.
+ */
+ gv_currkey->prev = gvname_prev;
+ } while (TRUE);
+ /* set ^#t("#LABEL")=3 */
+ label_mv = &label;
+ MV_FORCE_MVAL(label_mv, 3);
+ SET_TRIGGER_GLOBAL_SUB_MVAL(LITERAL_HASHLABEL, STRLEN(LITERAL_HASHLABEL), label, result);
+ assert(PUT_SUCCESS == result); /* Size of count can only get shorter or stay the same */
+ }
+ op_tcommit();
+ REVERT; /* remove our condition handler */
+ DEBUG_ONLY(donot_INVOKE_MUMTSTART = FALSE;)
+ if (csa->hold_onto_crit)
+ {
+ assert(csa->now_crit); /* we should still hold crit */
+ /* Switch to new journal file and cut previous link if we did ^#t upgrade on a journaled region */
+ if (do_upgrade && JNL_WRITE_LOGICAL_RECS(csa))
+ {
+ sts = set_jnl_file_close(0);
+ assert(SS_NORMAL == sts); /* because we should have done jnl_ensure_open already
+ * in which case set_jnl_file_close has no way of erroring out.
+ */
+ sts = jnl_file_open_switch(reg, 0);
+ if (sts)
+ {
+ jpc = csa->jnl;
+ if (NOJNL != jpc->channel)
+ JNL_FD_CLOSE(jpc->channel, close_res); /* sets jpc->channel to NOJNL */
+ assert(NOJNL == jpc->channel);
+ jnl_send_oper(jpc, sts);
+ }
+ }
+ csa->hold_onto_crit = FALSE;
+ } else
+ grab_crit(reg);
+ csa->hdr->hasht_upgrade_needed = FALSE;
+ rel_crit(reg);
+ return; /* if any errors happen during upgrade (e.g. TRANS2BIG), we will not reach here */
+}
+#endif /* GTM_TRIGGER */
diff --git a/sr_unix/do_shmat.h b/sr_unix/trigger_upgrade_protos.h
similarity index 69%
copy from sr_unix/do_shmat.h
copy to sr_unix/trigger_upgrade_protos.h
index c4143a7..c694422 100644
--- a/sr_unix/do_shmat.h
+++ b/sr_unix/trigger_upgrade_protos.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * Copyright 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -9,9 +9,9 @@
* *
****************************************************************/
-#ifndef __DO_SHMAT_H__
-#define __DO_SHMAT_H__
+#ifndef TRIGGER_UPGRADE_PROTOS_H_INCLUDED
+#define TRIGGER_UPGRADE_PROTOS_H_INCLUDED
-void *do_shmat(int4 shmid, const void *shmaddr, int4 shmflg);
+void trigger_upgrade(gd_region *reg);
#endif
diff --git a/sr_unix/util_out_print_gtmio.c b/sr_unix/util_out_print_gtmio.c
new file mode 100644
index 0000000..a9b476a
--- /dev/null
+++ b/sr_unix/util_out_print_gtmio.c
@@ -0,0 +1,134 @@
+/****************************************************************
+ * *
+ * Copyright 2014 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#ifdef GTM_TRIGGER
+#include "gtm_string.h"
+
+#include "util.h" /* for FLUSH and util_out_print */
+#include "util_out_print_vaparm.h"
+#include "op.h" /* for op_write prototype */
+#include "io.h" /* needed for io_pair typedef */
+#include "gtmimagename.h" /* for IS_MCODE_RUNNING */
+
+GBLREF uint4 dollar_tlevel;
+
+#define ZTRIGBUFF_INIT_ALLOC 1024 /* start at 1K */
+#define ZTRIGBUFF_INIT_MAX_GEOM_ALLOC 1048576 /* stop geometric growth at this value */
+
+/* Used by MUPIP TRIGGER or $ZTRIGGER routines to buffer trigger output until TCOMMIT time
+ * (as otherwise we might display stale output due to a restarted try).
+ */
+void util_out_print_gtmio(caddr_t message, int flush, ...)
+{
+ va_list var;
+ char *src, *dst, *newdst;
+ int srclen, dstlen, dstalloc, newlen, ptrlen;
+ caddr_t msg;
+ int4 msglen;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ /* we expect all trigger operations (SELECT, LOAD, etc.) to happen inside TP. exceptions should set TREF variable */
+ assert(dollar_tlevel || TREF(gtmio_skip_tlevel_assert));
+ va_start(var, flush);
+ /* If "!AD" has been specified as the message, skip the util_out_print_vaparm call as it is possible
+ * the input string length is > the maximum length util_out_* routines are designed to handle.
+ * In that case, we dont need the parameter substitution anyways so do a memcpy instead.
+ */
+ if (STRCMP(message, "!AD") || (FLUSH != flush))
+ {
+ util_out_print_vaparm(message, NOFLUSH, var, MAXPOSINT4);
+ src = TREF(util_outbuff_ptr);
+ assert(NULL != TREF(util_outptr));
+ srclen = INTCAST(TREF(util_outptr) - src) + 1; /* 1 is for '\n' */
+ assert(OUT_BUFF_SIZE >= srclen);
+ } else
+ {
+ srclen = (int)va_arg(var, int4) + 1;
+ src = (char *)va_arg(var, caddr_t);
+ }
+ if (FLUSH == flush)
+ {
+ dstalloc = TREF(ztrigbuffAllocLen);
+ dstlen = TREF(ztrigbuffLen);
+ /* Leave room for terminating '\0' (after the \n) for later use in FPRINTF in tp_ztrigbuff_print.
+ * Hence the use of "<=" instead of a "<" in the "if (dstalloc <= (dstlen + srclen))" check below.
+ */
+ if (dstalloc <= (dstlen + srclen))
+ { /* reallocate */
+ dst = TREF(ztrigbuff);
+ do
+ {
+ if (!dstalloc)
+ dstalloc = ZTRIGBUFF_INIT_ALLOC; /* Allocate a 1K buffer at start */
+ else if (ZTRIGBUFF_INIT_MAX_GEOM_ALLOC <= dstalloc)
+ dstalloc += ZTRIGBUFF_INIT_MAX_GEOM_ALLOC;
+ else
+ dstalloc = dstalloc * 2; /* grow geometrically until a limit and linearly after that */
+ } while (dstalloc <= (dstlen + srclen));
+ newdst = malloc(dstalloc);
+ if (dstlen)
+ memcpy(newdst, dst, dstlen);
+ TREF(ztrigbuff) = newdst;
+ TREF(ztrigbuffAllocLen) = dstalloc;
+ if (NULL != dst)
+ free(dst);
+ }
+ dst = TREF(ztrigbuff);
+ memcpy(dst + dstlen, src, srclen - 1);
+ dst[dstlen + srclen - 1] = '\n';
+ TREF(ztrigbuffLen) += srclen;
+ TREF(util_outptr) = TREF(util_outbuff_ptr); /* Signal text is flushed */
+ }
+ va_end(TREF(last_va_list_ptr));
+ va_end(var);
+}
+
+void tp_ztrigbuff_print(void)
+{
+ mval flushtxt;
+ char *ptr, *ptrtop, *ptr2;
+ int len;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ /* If mumps process doing trigger operations, use GTM IO routines. If not use util_out_print. The only
+ * exception is if the MUPIP caller wants to use current IO device (i.e. it has it all set up). In that
+ * case the TREF ztrig_use_io_curr_device would have been set to TRUE.
+ */
+ if (IS_MCODE_RUNNING || TREF(ztrig_use_io_curr_device))
+ {
+ ptr = TREF(ztrigbuff);
+ assert('\n' == ptr[TREF(ztrigbuffLen) - 1]);
+ ptrtop = ptr + TREF(ztrigbuffLen);
+ flushtxt.mvtype = MV_STR;
+ do
+ {
+ len = INTCAST(ptrtop - ptr);
+ ptr2 = memchr(ptr, '\n', len);
+ assert(NULL != ptr2);
+ flushtxt.str.addr = ptr;
+ flushtxt.str.len = ptr2 - ptr;
+ op_write(&flushtxt);
+ op_wteol(1);
+ ptr = ptr2 + 1;
+ } while (ptr < ptrtop);
+ } else
+ { /* Use util_out_print but since you pass TRUE for flush, use -1 to prevent duplicate newline */
+ assert('\n' == (TREF(ztrigbuff))[TREF(ztrigbuffLen) - 1]);
+ assert(TREF(ztrigbuffLen) < TREF(ztrigbuffAllocLen));
+ (TREF(ztrigbuff))[TREF(ztrigbuffLen)] = '\0';
+ FPRINTF(stderr, "%s", TREF(ztrigbuff));
+ }
+}
+#endif
diff --git a/sr_unix/util_output.c b/sr_unix/util_output.c
index be3899a..1ad3804 100644
--- a/sr_unix/util_output.c
+++ b/sr_unix/util_output.c
@@ -65,12 +65,13 @@ GBLREF boolean_t is_updproc;
GBLREF boolean_t is_updhelper;
GBLREF recvpool_addrs recvpool;
GBLREF uint4 process_id;
-GBLREF void (*op_write_ptr)(mval *v);
-GBLREF void (*op_wteol_ptr)(int4 n);
error_def(ERR_REPLINSTACC);
error_def(ERR_TEXT);
+#define ZTRIGBUFF_INIT_ALLOC 1024 /* start at 1K */
+#define ZTRIGBUFF_INIT_MAX_GEOM_ALLOC 1048576 /* stop geometric growth at this value */
+
#define GETFAOVALDEF(faocnt, var, type, result, defval) \
if (faocnt > 0) {result = (type)va_arg(var, type); faocnt--;} else result = defval;
@@ -739,8 +740,7 @@ void util_out_print_vaparm(caddr_t message, int flush, va_list var, int faocnt)
SETUP_THREADGBL_ACCESS;
if (IS_GTMSECSHR_IMAGE && (FLUSH == flush))
flush = OPER; /* All gtmsecshr origin msgs go to operator log */
- if (NULL == TREF(util_outptr))
- TREF(util_outptr) = TREF(util_outbuff_ptr);
+ assert(NULL != TREF(util_outptr));
if (NULL != message)
{
util_avail_len = INTCAST(TREF(util_outbuff_ptr) + OUT_BUFF_SIZE - TREF(util_outptr) - 2);
@@ -798,7 +798,6 @@ void util_out_print_vaparm(caddr_t message, int flush, va_list var, int faocnt)
case FLUSH:
if (use_stdio)
{
- assert(NULL != op_write_ptr);
flushtxt.addr = fmt_buff;
flushtxt.len = INTCAST(TREF(util_outptr) - TREF(util_outbuff_ptr));
save_io_curr_device = io_curr_device;
@@ -848,36 +847,29 @@ void util_out_print(caddr_t message, int flush, ...)
va_end(var);
}
-/* Used primarily by MUPIP in the MUPIP TRIGGER routines where output can either be output "normally" there or
- * when the same trigger parsing/loading functions are called from within GTM, the output is done with GTM IO
- * routines.
+/* Saves a copy of the current unflushed buffer in util_outbuff_ptr into dst.
+ * The length of the allocated buffer at "dst" is passed in as *dst_len.
+ * If that length is not enough to store the unflushed buffer, FALSE is returned right away.
+ * If not, the length of the unflushed buffer is stored in dst_len, the actual unflushed buffer
+ * is copeid over to "dst", and a TRUE is returned.
*/
-void util_out_print_gtmio(caddr_t message, int flush, ...)
+boolean_t util_out_save(char *dst, int *dstlen_ptr)
{
- int flush_it;
- boolean_t usestdio;
- va_list var;
- mval flushtxt;
+ int srclen, dstlen;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
- va_start(var, flush);
- usestdio = IS_MCODE_RUNNING;
- assert((FLUSH == flush) || (NOFLUSH == flush));
- flush_it = ((FLUSH == flush) && !usestdio) ? FLUSH : NOFLUSH;
- util_out_print_vaparm(message, flush_it, var, MAXPOSINT4);
- if (usestdio && (FLUSH == flush))
- { /* Message should be in buffer and we just need to flush it */
- assert(NULL != op_write_ptr);
- flushtxt.mvtype = MV_STR;
- flushtxt.str.addr = TREF(util_outbuff_ptr);
- flushtxt.str.len = INTCAST(TREF(util_outptr) - TREF(util_outbuff_ptr));
- (*op_write_ptr)(&flushtxt);
- (*op_wteol_ptr)(1);
- TREF(util_outptr) = TREF(util_outbuff_ptr); /* Signal text is flushed */
- }
- va_end(TREF(last_va_list_ptr));
- va_end(var);
+ assert(NULL != TREF(util_outptr));
+ srclen = INTCAST(TREF(util_outptr) - TREF(util_outbuff_ptr));
+ assert(0 <= srclen);
+ assert(OUT_BUFF_SIZE >= srclen);
+ dstlen = *dstlen_ptr;
+ assert(0 <= dstlen);
+ if (srclen > dstlen)
+ return FALSE;
+ *dstlen_ptr = srclen;
+ memcpy(dst, TREF(util_outbuff_ptr), srclen);
+ return TRUE;
}
/* If $x of the standard output device is non-zero, and we are going to flush a buffer,
diff --git a/sr_unix/wcs_flu.c b/sr_unix/wcs_flu.c
index 0daea70..79e038a 100644
--- a/sr_unix/wcs_flu.c
+++ b/sr_unix/wcs_flu.c
@@ -47,15 +47,15 @@
#include "anticipatory_freeze.h"
#include "eintr_wrappers.h"
-GBLREF gd_region *gv_cur_region;
-GBLREF uint4 process_id;
-GBLREF sgmnt_addrs *cs_addrs;
-GBLREF volatile int4 db_fsync_in_prog; /* for DB_FSYNC macro usage */
-GBLREF jnl_gbls_t jgbl;
-GBLREF bool in_backup;
+GBLREF bool in_backup;
+GBLREF gd_region *gv_cur_region;
+GBLREF sgmnt_addrs *cs_addrs;
+GBLREF uint4 process_id;
+GBLREF volatile int4 db_fsync_in_prog; /* for DB_FSYNC macro usage */
+GBLREF jnl_gbls_t jgbl;
#ifdef DEBUG
-GBLREF boolean_t in_mu_rndwn_file;
-GBLREF boolean_t mupip_jnl_recover;
+GBLREF boolean_t in_mu_rndwn_file;
+GBLREF boolean_t mupip_jnl_recover;
#endif
error_def(ERR_DBFILERR);
@@ -151,6 +151,7 @@ error_def(ERR_WRITERSTUCK);
#define REL_CRIT_BEFORE_RETURN \
{ \
+ cnl->doing_epoch = FALSE; \
cnl->wcsflu_pid = 0; \
if (!was_crit) \
rel_crit(gv_cur_region); \
@@ -215,8 +216,15 @@ boolean_t wcs_flu(uint4 options)
if (jnl_enabled)
{
jb = jpc->jnl_buff;
- /* Assert that we aren't trying to flush a completed journal file */
- assert(!jb->last_eof_written);
+ /* If we are trying to flush a completed journal file, make sure there is nothing else to do and return. */
+ if (jb->last_eof_written)
+ {
+ assert(jb->fsync_dskaddr == jb->freeaddr);
+ assert((dba_bg != csd->acc_meth)
+ || (!cnl->wcs_active_lvl && !csa->acc_meth.bg.cache_state->cacheq_active.fl));
+ REL_CRIT_BEFORE_RETURN;
+ return TRUE;
+ }
/* Assert that we never flush the cache in the midst of a database commit. The only exception is MUPIP RUNDOWN */
assert((csa->ti->curr_tn == csa->ti->early_tn) || in_mu_rndwn_file);
if (!jgbl.dont_reset_gbl_jrec_time)
@@ -246,6 +254,7 @@ boolean_t wcs_flu(uint4 options)
if (jnl_enabled)
{
assert(SS_NORMAL == jnl_status);
+ cnl->doing_epoch = sync_epoch || write_epoch;
epoch_already_current = (jb->post_epoch_freeaddr == jb->freeaddr); /* crit held, so this stays valid */
if (return_early = (speedup_nobefore && !csd->jnl_before_image))
{ /* Finish easiest option first. This database has NOBEFORE image journaling and caller has asked for
@@ -444,6 +453,7 @@ boolean_t wcs_flu(uint4 options)
* will get confused (see explanation above where variable "in_commit" gets set).
*/
assert(was_crit); /* so dont need to rel_crit */
+ cnl->doing_epoch = FALSE;
cnl->wcsflu_pid = 0;
return FALSE;
}
diff --git a/sr_unix/zhist.c b/sr_unix/zhist.c
index 3e333a7..af4fd11 100644
--- a/sr_unix/zhist.c
+++ b/sr_unix/zhist.c
@@ -15,10 +15,9 @@
#include "min_max.h"
#include <rtnhdr.h>
-#include "zhist.h"
#include "gtmlink.h"
-#ifdef USHBIN_SUPPORTED /* This entire file */
+#ifdef AUTORELINK_SUPPORTED /* This entire file */
/* Routine called from op_rhd_ext() to determine if the routine being called needs to be relinked. To return TRUE,
* the following conditions must be met:
@@ -37,77 +36,100 @@
boolean_t need_relink(rhdtyp *rtnhdr, zro_hist *zhist)
{
zro_validation_entry *iter;
- uint4 cur_cycle;
+ uint4 cur_cycle, rtnnmlen;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
- assert(NULL != zhist); /* Should be called unless relinking is possible */
+ assert(NULL != zhist); /* Shouldn't be called unless relinking is possible */
/* TODO: Do this check second, if below logic would return TRUE */
if ((LINK_NORECURSIVE == TREF(relink_allowed)) && on_stack(rtnhdr, NULL))
return FALSE; /* can't relink, or else we'll get LOADRUNNING */
- /* If SET=$ZRO cycle has changed since validation list was compiled, recreate the list.... just fully relink */
- /* TODO: Only relink when absolutely necessary. If routine has same hash in same location, don't relink */
+ /* If $ZROUTINES cycle has changed since validation list was created, signal relink but the relink only
+ * actually happens if the file op_zlink() locates has a different object hashcode than the currently
+ * linked routine - else it just rebuilds the history and calls it good.
+ */
if (zhist->zroutines_cycle != TREF(set_zroutines_cycle))
return TRUE;
/* Traverse list corresponding to zro entries */
for (iter = &zhist->base[0]; iter != zhist->end; iter++)
{
- /* TODO: assert routine name near cycle_reladdr == current routine invocation */
- cur_cycle = RELINKCTL_CYCLE_READ(iter->relinkctl_bkptr, iter->cycle_loc);
+ DEBUG_ONLY(rtnnmlen = mid_len(&iter->relinkrec->rtnname_fixed));
+ assert((rtnnmlen == rtnhdr->routine_name.len) /* Verify have the right entry - compare names */
+ && (0 == memcmp(&iter->relinkrec->rtnname_fixed, rtnhdr->routine_name.addr, rtnnmlen)));
+ cur_cycle = iter->relinkrec->cycle;
if (cur_cycle != iter->cycle)
return TRUE;
}
return FALSE;
}
-/* Routine called from zro_search()
- * zro_zhist_saverecent
- * INPUT:
- * array of history entries created during zro_search()
- * OUTPUT:
- * global variable TREF(recent_zhist), which is then "passed" to incr_link, which associates this history with routine hdr
+/* Routine called from zro_search_hist() to copy a given search history block from stack memory to malloc'd memory
+ * so it can be attached to the routine header of the linked routine.
+ *
+ * Parameters:
+ * zhist_valent - Last search history entry + 1
+ * zhist_valent_base - First search history entry
+ *
+ * Return value:
+ * Malloc'd block of search history header (zro_hist *) followed by the array of search history entries for
+ * the given routine.
*/
-void zro_zhist_saverecent(zro_validation_entry *zhent, zro_validation_entry *zhent_base)
+zro_hist *zro_zhist_saverecent(zro_search_hist_ent *zhist_valent_end, zro_search_hist_ent *zhist_valent_base)
{
- int hist_len;
- zro_hist *lcl_recent_zhist;
+ int hist_len;
+ relinkrec_t *rec;
+ zro_hist *lcl_recent_zhist;
+ zro_validation_entry *zhent;
+ zro_search_hist_ent *zhist_valent;
+ mstr rtnname;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
- /* Malloc and save zhist copy */
- assert(NULL != zhent);
- assert(NULL != zhent_base);
- hist_len = zhent - zhent_base;
- lcl_recent_zhist = (zro_hist *)malloc(SIZEOF(zro_hist) + SIZEOF(zro_validation_entry) * hist_len);
+ /* Malloc and return zhist copy */
+ assert(NULL != zhist_valent_end);
+ assert(NULL != zhist_valent_base);
+ hist_len = zhist_valent_end - zhist_valent_base;
+ lcl_recent_zhist = (zro_hist *)malloc(SIZEOF(zro_hist) + (SIZEOF(zro_validation_entry) * hist_len));
lcl_recent_zhist->zroutines_cycle = TREF(set_zroutines_cycle);
lcl_recent_zhist->end = &lcl_recent_zhist->base[0] + hist_len;
- memcpy((char *)&lcl_recent_zhist->base[0], (char *)zhent_base, SIZEOF(zro_validation_entry) * hist_len);
- TREF(recent_zhist) = lcl_recent_zhist;
+ for (zhist_valent = zhist_valent_base, zhent = &lcl_recent_zhist->base[0];
+ 0 < hist_len;
+ zhist_valent++, zhent++, hist_len--)
+ {
+ rtnname.addr = zhist_valent->rtnname.c;
+ rtnname.len = zhist_valent->rtnname_len;
+ assert(NULL != zhist_valent->zro_valent.relinkctl_bkptr);
+ rec = relinkctl_insert_record(zhist_valent->zro_valent.relinkctl_bkptr, &rtnname);
+ assert(NULL != rec);
+ zhist_valent->zro_valent.relinkrec = rec;
+ zhist_valent->zro_valent.cycle = rec->cycle;
+ memcpy((char *)zhent, (char *)&zhist_valent->zro_valent, SIZEOF(zro_validation_entry));
+ }
+ return lcl_recent_zhist;
}
-/*
- * zro_record_zhist
- * INPUT:
- * routine name
- * $ZROUTINES entry identifier
- * OUTPUT:
- * cycle_addr
- * current value at cycle_addr
- * NOTE: both saved into current history entry, "zhent"
+/* Routine called from zro_search_hist() to add a $ZROUTINES entry to the (local) search history for a given object file.
+ *
+ * Parameters:
+ * zhist_valent - $ZROUTINES search history entry to be filled in.
+ * obj_container - $ZROUTINES entry for a given object directory.
+ * rtnname - mstr addr containing name of the routine.
+ *
*/
-void zro_record_zhist(zro_validation_entry *zhent, zro_ent *obj_container, mstr *rtnname)
+void zro_record_zhist(zro_search_hist_ent *zhist_valent, zro_ent *obj_container, mstr *rtnname)
{
open_relinkctl_sgm *linkctl;
- relinkrec_loc_t rec;
int len;
assert(NULL != obj_container);
linkctl = obj_container->relinkctl_sgmaddr;
assert(NULL != linkctl);
- zhent->relinkctl_bkptr = linkctl;
- assert(NULL != zhent);
- rec = relinkctl_insert_record(linkctl, rtnname);
- zhent->cycle_loc = rec;
- zhent->cycle = RELINKCTL_CYCLE_READ(linkctl, zhent->cycle_loc);
+ zhist_valent->zro_valent.relinkctl_bkptr = linkctl;
+ assert(NULL != zhist_valent);
+ assert(rtnname->len < SIZEOF(mident_fixed));
+ memcpy(zhist_valent->rtnname.c, rtnname->addr, rtnname->len);
+ zhist_valent->rtnname_len = rtnname->len;
+ if (SIZEOF(zhist_valent->rtnname) > rtnname->len)
+ memset((zhist_valent->rtnname.c + rtnname->len), '\0', SIZEOF(zhist_valent->rtnname) - rtnname->len);
}
-#endif /* USHBIN_SUPPORTED */
+#endif /* AUTORELINK_SUPPORTED */
diff --git a/sr_unix/zhist.h b/sr_unix/zhist.h
deleted file mode 100644
index c2dc801..0000000
--- a/sr_unix/zhist.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/****************************************************************
- * *
- * Copyright 2013, 2014 Fidelity Information Services, Inc *
- * *
- * This source code contains the intellectual property *
- * of its copyright holder(s), and is made available *
- * under a license. If you do not know the terms of *
- * the license, please stop and do not read further. *
- * *
- ****************************************************************/
-
-#ifndef ZHIST_H_INCLUDED
-#define ZHIST_H_INCLUDED
-
-#include "relinkctl.h"
-#include "zroutinessp.h"
-
-/*
- * Suppose, for example, $ZROUTINES="dir1 dir2 dir3".
- * TODO: explain validation logic............
- */
-
-typedef struct
-{
- uint4 cycle; /* private copy */
- relinkrec_loc_t cycle_loc; /* location of record containing shared copy */
- open_relinkctl_sgm *relinkctl_bkptr;
- /* backpointer to zro_ent? any reason for that? maybe debugging? */
-} zro_validation_entry;
-
-typedef struct
-{
- uint4 zroutines_cycle; /* compare to set_zroutines_cycle */
- zro_validation_entry *end; /* end - &base[0] = size of allocated validation array */
- zro_validation_entry base[1]; /* base of allocated validation array */
-} zro_hist;
-
-boolean_t need_relink(rhdtyp *rtnhdr, zro_hist *zhist);
-void zro_zhist_saverecent(zro_validation_entry *zhent, zro_validation_entry *zhent_base);
-void zro_record_zhist(zro_validation_entry *zhent, zro_ent *obj_container, mstr *rtnname);
-
-#endif /* ZHIST_H_INCLUDED */
diff --git a/sr_unix/zro_gettok.c b/sr_unix/zro_gettok.c
index ad132ac..3097dcc 100644
--- a/sr_unix/zro_gettok.c
+++ b/sr_unix/zro_gettok.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2007 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -10,6 +10,9 @@
****************************************************************/
#include "mdef.h"
+#ifdef AUTORELINK_SUPPORTED
+# include "rtnhdr.h"
+#endif
#include "zroutines.h"
int zro_gettok (char **lp, char *top, mstr *tok)
@@ -19,29 +22,29 @@ int zro_gettok (char **lp, char *top, mstr *tok)
if (*lp >= top)
toktyp = ZRO_EOL;
else
- switch (**lp)
- {
- case ZRO_DEL:
+ switch (**lp)
+ {
+ case ZRO_DEL:
- toktyp = ZRO_DEL;
- while (*lp < top && **lp == ZRO_DEL)
- (*lp)++;
- break;
- case ZRO_LBR:
- toktyp = ZRO_LBR;
- (*lp)++;
- break;
- case ZRO_RBR:
- toktyp = ZRO_RBR;
- (*lp)++;
- break;
- default:
- tok->addr = *lp;
- while (*lp < top && **lp != ZRO_DEL && **lp != ZRO_LBR && **lp != ZRO_RBR)
- (*lp)++;
- toktyp = ZRO_IDN;
- tok->len = INTCAST(*lp - tok->addr);
- break;
- }
+ toktyp = ZRO_DEL;
+ while (*lp < top && **lp == ZRO_DEL)
+ (*lp)++;
+ break;
+ case ZRO_LBR:
+ toktyp = ZRO_LBR;
+ (*lp)++;
+ break;
+ case ZRO_RBR:
+ toktyp = ZRO_RBR;
+ (*lp)++;
+ break;
+ default:
+ tok->addr = *lp;
+ while (*lp < top && **lp != ZRO_DEL && **lp != ZRO_LBR && **lp != ZRO_RBR)
+ (*lp)++;
+ toktyp = ZRO_IDN;
+ tok->len = INTCAST(*lp - tok->addr);
+ break;
+ }
return toktyp;
}
diff --git a/sr_unix/zro_load.c b/sr_unix/zro_load.c
index 85cd19b..43e38cf 100644
--- a/sr_unix/zro_load.c
+++ b/sr_unix/zro_load.c
@@ -23,7 +23,6 @@
#include "eintr_wrappers.h"
#include "error.h"
#include "zro_shlibs.h"
-#include "zhist.h"
#include "gtm_limits.h"
#define GETTOK zro_gettok(&lp, top, &tok)
@@ -62,6 +61,7 @@ void zro_load(mstr *str)
SETUP_THREADGBL_ACCESS;
(TREF(set_zroutines_cycle))++; /* Signal need to recompute zroutines histories for each linked routine */
+ ARLINK_ONLY(TREF(arlink_enabled) = FALSE); /* Set if any zro entry is enabled for autorelink */
memset(array, 0, SIZEOF(array));
lp = str->addr;
top = lp + str->len;
@@ -73,7 +73,7 @@ void zro_load(mstr *str)
pblk.buffer = tranbuf;
toktyp = GETTOK;
if (ZRO_EOL == toktyp)
- { /* Null string - set default */
+ { /* Null string - set default - implies current working directory only */
array[0].count = 1;
array[1].type = ZRO_TYPE_OBJECT;
array[1].str.len = 0;
@@ -96,18 +96,18 @@ void zro_load(mstr *str)
* user desires this directory to have auto-relink capability.
*/
enable_autorelink = FALSE;
-# ifdef USHBIN_SUPPORTED
- /* Only shared binary platforms recognize the auto-relink indicator. Specifying "*" at end of other
- * directories causes an error further downstream (FILEPARSE) when the "*" is not stipped off the file
- * name - unless someone has managed to create a directory with a "*" suffix.
+ /* All platforms allow the auto-relink indicator on object directories but only autorelink able platforms
+ * (#ifdef AUTORELINK_SUPPORTED is set) do anything with it. Other platforms just ignore it. Specifying
+ * "*" at end of non-object directories causes an error further downstream (FILEPARSE) when the "*" is
+ * not stripped off the file name - unless someone has managed to create a directory with a "*" suffix.
*/
if (ZRO_ALF == *(tok.addr + tok.len - 1))
{ /* Auto-relink is indicated */
enable_autorelink = TRUE;
+ TREF(arlink_enabled) = TRUE;
--tok.len; /* Remove indicator from name so we can use it */
assert(0 <= tok.len);
}
-# endif
if (SIZEOF(tranbuf) <= tok.len)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZROSYNTAX, 2, str->len, str->addr,
ERR_FILEPARSE, 2, tok.len, tok.addr);
@@ -140,7 +140,17 @@ void zro_load(mstr *str)
array[oi].type = ZRO_TYPE_OBJECT;
array[oi + 1].type = ZRO_TYPE_COUNT;
si = oi + 2;
-# ifdef USHBIN_SUPPORTED
+# ifdef AUTORELINK_SUPPORTED
+# ifdef DEBUG
+ /* If env var gtm_test_autorelink_always is set in dbg version, treat every
+ * object directory specified in $zroutines as if * has been additionally specified.
+ */
+ if (TREF(gtm_test_autorelink_always))
+ {
+ enable_autorelink = TRUE;
+ TREF(arlink_enabled) = TRUE;
+ }
+# endif
if (enable_autorelink)
{ /* Only setup autorelink struct if it is enabled */
transtr.addr = tranbuf;
@@ -228,8 +238,8 @@ void zro_load(mstr *str)
assert((TREF(zro_root))->type == ZRO_TYPE_COUNT);
oi = (TREF(zro_root))->count;
assert(oi);
- for (op = TREF(zro_root) + 1; oi-- > 0; )
- { /* release space held by translated entries */
+ for (op = TREF(zro_root) + 1; 0 < oi--;)
+ { /* Release space held by translated entries */
assert((ZRO_TYPE_OBJECT == op->type) || (ZRO_TYPE_OBJLIB == op->type));
if (op->str.len)
free(op->str.addr);
@@ -237,7 +247,7 @@ void zro_load(mstr *str)
continue; /* i.e. no sources for shared library */
assert(ZRO_TYPE_COUNT == op->type);
si = (op++)->count;
- for ( ; si-- > 0; op++)
+ for (; si-- > 0; op++)
{
assert(ZRO_TYPE_SOURCE == op->type);
if (op->str.len)
@@ -248,10 +258,10 @@ void zro_load(mstr *str)
}
TREF(zro_root) = (zro_ent *)malloc(total_ents * SIZEOF(zro_ent));
memcpy((uchar_ptr_t)TREF(zro_root), (uchar_ptr_t)array, total_ents * SIZEOF(zro_ent));
- assert((TREF(zro_root))->type == ZRO_TYPE_COUNT);
+ assert(ZRO_TYPE_COUNT == (TREF(zro_root))->type);
oi = (TREF(zro_root))->count;
assert(oi);
- for (op = TREF(zro_root) + 1; oi-- > 0; )
+ for (op = TREF(zro_root) + 1; 0 < oi--;)
{
assert((ZRO_TYPE_OBJECT == op->type) || (ZRO_TYPE_OBJLIB == op->type));
if (op->str.len)
@@ -270,7 +280,7 @@ void zro_load(mstr *str)
continue;
assert(ZRO_TYPE_COUNT == op->type);
si = (op++)->count;
- for ( ; si-- > 0; op++)
+ for (; 0 < si--; op++)
{
assert(ZRO_TYPE_SOURCE == op->type);
if (op->str.len)
diff --git a/sr_unix/zro_search.c b/sr_unix/zro_search.c
index a8690f6..3ada824 100644
--- a/sr_unix/zro_search.c
+++ b/sr_unix/zro_search.c
@@ -16,68 +16,94 @@
#include "gtm_limits.h"
#include <errno.h>
-#include "zroutines.h"
#include "eintr_wrappers.h"
#include "error.h"
-#include "lv_val.h" /* needed for "fgncal.h" */
+#include "lv_val.h" /* Needed for "fgncal.h" */
#include "fgncal.h"
#include "min_max.h"
-#ifdef USHBIN_SUPPORTED
-#include <rtnhdr.h> /* needed for "zhist.h" */
-#include "zhist.h"
+#ifdef AUTORELINK_SUPPORTED
+# include "rtnhdr.h" /* Defines zro_hist * type for return */
+# include "parse_file.h" /* Needed for zro_search_hist() */
+#endif
+#ifdef DEBUG
+#include "toktyp.h" /* Needed for "valid_mname.h" */
+#include "valid_mname.h"
#endif
+#include "zroutines.h"
+#include "arlinkdbg.h"
-error_def (ERR_ZFILENMTOOLONG);
-error_def (ERR_SYSCALL);
+error_def(ERR_FILEPARSE);
+error_def(ERR_SYSCALL);
+error_def(ERR_WILDCARD);
+error_def(ERR_ZFILENMTOOLONG);
+error_def(ERR_ZLINKFILE);
-/* TODO: description
- * mstr *objstr; If NULL, do not search for object, else pointer to object file text string.
- * zro_ent **objdir; NULL if objstr is NULL, otherwise, return pointer to associated object directory.
- * Note objdir is NULL if object directory is not found.
- * mstr *srcstr; Like objstr, except for associated source program.
- * zro_ent **srcdir; Like objdir, except for associated source program directory.
- * boolean_t skip; If TRUE, skip over shared libraries. If FALSE, probe shared libraries.
+/* Routine to perform a search of the $ZROUTINES structures (zro_ent) for a given routine source and/or object.
+ *
+ * Run through the zro_ent structures (source and/or object depending on which args have values). If looking for
+ * both, find a related pair (i.e. we don't find objects for unrelated sources or vice versa). The zro_ent
+ * structure list is in the following format:
+ * a. An object directory (which itself can be the source directory too if no source directories explicitly
+ * specified - example a zro_ent such as "obj(src)" has one object and one source dir where a spec such as
+ * "dir" is both an object and source directory).
+ * b. 0 or more related source directories
+ * This then repeats until the end of the list (the ZRO_TYPE_COUNT records tell how many records exist of the given
+ * type).
+ *
+ * Parameters:
+ * objstr - If NULL, do not search for object, else pointer to object file text string.
+ * objdir - NULL if objstr is NULL, otherwise is return pointer to associated object directory
+ * (Note objdir is set to NULL if object directory is not found).
+ * srcstr - Like objstr, except for associated source program.
+ * srcdir - Like objdir, except for associated source program directory.
+ * skip_shlib - If TRUE, skip over shared libraries. If FALSE, probe shared libraries.
+ *
+ * No return value.
*/
-void zro_search(mstr *objstr, zro_ent **objdir, mstr *srcstr, zro_ent **srcdir, boolean_t skip)
+void zro_search(mstr *objstr, zro_ent **objdir, mstr *srcstr, zro_ent **srcdir, boolean_t skip_shlib)
{
- uint4 status;
- zro_ent *op, *sp, *op_result, *sp_result;
- char objfn[PATH_MAX], srcfn[PATH_MAX], *obp, *sbp;
- int objcnt, srccnt;
- struct stat outbuf;
- int stat_res;
- mstr rtnname;
-# ifdef USHBIN_SUPPORTED
- zro_validation_entry zhent_base[ZRO_MAX_ENTS];
- zro_validation_entry *zhent;
-# endif
+ uint4 status;
+ zro_ent *op, *sp, *op_result, *sp_result;
+ char objfn[PATH_MAX], srcfn[PATH_MAX], *obp, *sbp, save_char;
+ int objcnt, srccnt;
+ struct stat outbuf;
+ int stat_res;
+ mstr rtnname;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
if (!TREF(zro_root))
zro_init();
- assert(objstr || srcstr); /* must search for object or source or both */
- assert(!objstr || objdir); /* if object text, then must have pointer for result */
- assert(!srcstr || srcdir); /* if source text, then must have pointer for result */
+ assert((NULL != objstr) || (NULL != srcstr)); /* Must search for object or source or both */
+ assert((NULL == objstr) || (NULL != objdir)); /* If object text, then must have pointer for result */
+ assert((NULL == srcstr) || (NULL != srcdir)); /* If source text, then must have pointer for result */
assert(ZRO_TYPE_COUNT == (TREF(zro_root))->type);
op_result = sp_result = NULL;
objcnt = (TREF(zro_root))->count;
- assert(objcnt);
- USHBIN_ONLY(zhent = &zhent_base[0]);
+ assert(0 < objcnt);
for (op = TREF(zro_root) + 1; !op_result && !sp_result && (0 < objcnt--); )
{
assert((ZRO_TYPE_OBJECT == op->type) || (ZRO_TYPE_OBJLIB == op->type));
- if (objstr)
+ if (NULL != objstr)
{
if (ZRO_TYPE_OBJLIB == op->type)
{
- if (!skip)
+ if (!skip_shlib)
{
assert(op->shrlib);
rtnname.len = objstr->len - (int)STR_LIT_LEN(DOTOBJ);
memcpy(objfn, objstr->addr, rtnname.len);
objfn[rtnname.len] = 0;
rtnname.addr = objfn;
+# ifdef DEBUG
+ save_char = rtnname.addr[0];
+ if ('_' == save_char)
+ rtnname.addr[0] = '%';
+ /* Temporary adjustment for "valid_mname" to not assert fail */
+ assert(valid_mname(&rtnname));
+ if ('_' == save_char)
+ rtnname.addr[0] = save_char; /* restore */
+# endif
if (NULL != (op->shrsym = (void *)fgn_getrtn(op->shrlib, &rtnname, SUCCESS)))
/* Note assignment above */
op_result = op;
@@ -105,31 +131,20 @@ void zro_search(mstr *objstr, zro_ent **objdir, mstr *srcstr, zro_ent **srcdir,
errno);
} else
op_result = op;
-# ifdef USHBIN_SUPPORTED
- if ((NULL != op) && (NULL != op->relinkctl_sgmaddr))
- { /* If this directory is auto-relink enabled, make sure to track the usages */
- rtnname.len = MIN(objstr->len - (int)STR_LIT_LEN(DOTOBJ), MAX_MIDENT_LEN);
- memcpy(objfn, objstr->addr, rtnname.len);
- objfn[rtnname.len] = '\0';
- rtnname.addr = objfn;
- zro_record_zhist(zhent++, op, &rtnname);
- }
-# endif
}
if (srcstr)
{
sp = op + 1;
if (ZRO_TYPE_OBJLIB == op->type)
{
- op = sp;
- continue;
+ op = sp; continue;
}
assert(ZRO_TYPE_COUNT == sp->type);
srccnt = (sp++)->count;
for ( ; !sp_result && srccnt-- > 0; sp++)
{
assert(sp->type == ZRO_TYPE_SOURCE);
- if (sp->str.len + srcstr->len + 2 > SIZEOF(srcfn)) /* extra 2 for '/' & null */
+ if (sp->str.len + srcstr->len + 2 > SIZEOF(srcfn)) /* Extra 2 for '/' & null */
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZFILENMTOOLONG, 2, sp->str.len, sp->str.addr);
sbp = &srcfn[0];
if (sp->str.len)
@@ -162,19 +177,121 @@ void zro_search(mstr *objstr, zro_ent **objdir, mstr *srcstr, zro_ent **srcdir,
op++;
}
}
-# ifdef USHBIN_SUPPORTED
- if ((NULL != op_result) && (NULL != op_result->relinkctl_sgmaddr))
- /* If this directory is auto-relink enabled, make sure to track the usages */
- zro_zhist_saverecent(zhent, &zhent_base[0]);
- else
- /* If didn't find a binary result, or we didn't find a relinkable routine, we have no "recent zhist" value
- * to return so just clear it.
- */
- TREF(recent_zhist) = NULL;
-# endif
- if (objdir)
+ if (NULL != objdir)
*objdir = op_result;
- if (srcdir)
+ if (NULL != srcdir)
*srcdir = sp_result;
return;
}
+
+#ifdef AUTORELINK_SUPPORTED
+/* Routine to take a given object file path and create the autorelink search history for that object and return the zro_ent
+ * structure associated with the object file with the following caveats:
+ * 1. If the file is in a $ZROUTINES entry that is not autorelink-enabled, no history is returned.
+ * 2. Directories that are not autorelink-enabled do not show up in the history.
+ * 3. If the directory is not one that is currently in $ZROUTINES, no history is returned (special case of #2).
+ *
+ * Parameters:
+ *
+ * objstr - Address of mstr containing full path of the object file
+ * objdir - Store *addr of the zroutines entry addr (if non-NULL). Stores NULL if not found.
+ *
+ * Return value:
+ *
+ * Address of search history block (if NULL, *objdir is also NULL)
+ */
+zro_hist *zro_search_hist(char *objnamebuf, zro_ent **objdir)
+{
+ uint4 status;
+ parse_blk pblk;
+ zro_ent *op, *op_result;
+ mstr objstr, dirpath, rtnname, zroentname;
+ int objcnt;
+ zro_search_hist_ent zhent_base[ZRO_MAX_ENTS];
+ zro_search_hist_ent *zhent;
+ zro_hist *recent_zhist;
+ char obj_file[MAX_FBUFF + 1];
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ objstr.addr = objnamebuf;
+ assert(NULL != objstr.addr);
+ objstr.len = STRLEN(objstr.addr);
+ assert(0 < objstr.len);
+ DBGARLNK((stderr, "/n/nzro_search_hist: Entered for %s\n", objnamebuf));
+ /* First parse our input string to isolate the directory name we will look up */
+ memset(&pblk, 0, SIZEOF(pblk));
+ pblk.buff_size = MAX_FBUFF;
+ pblk.buffer = obj_file;
+ pblk.fop = F_SYNTAXO; /* Just a syntax parse */
+ status = parse_file(&objstr, &pblk);
+ if (!(status & 1))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_FILEPARSE, 2, objstr.len, objstr.addr, status);
+ if (pblk.fnb & F_WILD)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZLINKFILE, 2, objstr.len, objstr.addr,
+ ERR_WILDCARD, 2, objstr.len, objstr.addr);
+ dirpath.len = pblk.b_dir; /* Create mstr describing the object file's dirpath */
+ dirpath.addr = pblk.l_dir;
+ /* Remove any trailing '/' in the directory name since the directories in the zro_ent blocks have none
+ * so we need to match their style. Note this means if for whatever unfathomable reason there is a
+ * zro_ent for the root directory, the length can be zero so allow for that.
+ */
+ if ('/' == *(dirpath.addr + dirpath.len - 1))
+ dirpath.len--;
+ assert((0 <= dirpath.len) && (NULL != dirpath.addr));
+ /* Build the routine-name mstr that contains only the routine name */
+ rtnname.addr = pblk.l_name;
+ rtnname.len = pblk.b_name;
+ assert((0 < rtnname.len) && (NULL != rtnname.addr));
+ CONVERT_FILENAME_TO_RTNNAME(rtnname);
+ assert(valid_mname(&rtnname));
+ DBGARLNK((stderr, "zro_search_hist: Looking for dir %.*s for routine %.*s\n", dirpath.len, dirpath.addr,
+ rtnname.len, rtnname.addr));
+ /* Now lets locate it in the parsed $ZROUTINES block list while creating some history */
+ if (!TREF(zro_root))
+ zro_init();
+ op_result = NULL;
+ objcnt = (TREF(zro_root))->count;
+ assert(0 < objcnt);
+ zhent = &zhent_base[0]; /* History initialization */
+ for (op = TREF(zro_root) + 1; (0 < objcnt--);)
+ { /* Once through each zro_ent block in our array only looking at object directory type entries */
+ assert((ZRO_TYPE_OBJECT == op->type) || (ZRO_TYPE_OBJLIB == op->type));
+ if (ZRO_TYPE_OBJLIB == op->type)
+ continue; /* We only deal with object directories in this loop */
+ /* If this directory is autorelink enabled, add it to the history */
+ if (NULL != op->relinkctl_sgmaddr)
+ zro_record_zhist(zhent++, op, &rtnname);
+ /* In order to properly match the entries, we need to normalize them. The zro_ent name may or may not
+ * have a trailing '/' in the name. The dirpath value won't have a trailing '/'.
+ */
+ zroentname = op->str;
+ DBGARLNK((stderr, "zro_search_hist: recsleft: %d current dirblk: %.*s\n", objcnt, zroentname.len,
+ zroentname.addr));
+ if ((0 < zroentname.len) && ('/' == *(zroentname.addr + zroentname.len - 1)))
+ zroentname.len--;
+ if (MSTR_EQ(&dirpath, &zroentname))
+ {
+ op_result = op;
+ break;
+ }
+ /* Bump past source entries to next object entry */
+ op++;
+ assert(ZRO_TYPE_COUNT == op->type);
+ op += op->count;
+ op++;
+ }
+ if (NULL != objdir)
+ *objdir = op_result;
+ /* If either of we didn't find the directory in the $ZROUTINES list (so it couldn't be auto-relink enabled or
+ * we found the directory but it wasn't auto-relink enabled, we need return no history or zro_ent value.
+ */
+ if ((NULL == op_result) || (NULL == op_result->relinkctl_sgmaddr))
+ return NULL;
+ /* We found the routine in an auto-relink enabled directory so create/return the history and the zro_ent
+ * structure we found it in.
+ */
+ recent_zhist = zro_zhist_saverecent(zhent, &zhent_base[0]);
+ return recent_zhist;
+}
+#endif
diff --git a/sr_unix/zroutinessp.h b/sr_unix/zroutinessp.h
index 474e06b..213f0dd 100644
--- a/sr_unix/zroutinessp.h
+++ b/sr_unix/zroutinessp.h
@@ -32,7 +32,7 @@ typedef struct zro_ent_type
{
uint4 type;
uint4 count;
- mstr str; /* Path name; str.addr is malloc'd TODO: why malloc'd?*/
+ mstr str; /* Path name */
void_ptr_t shrlib; /* Result of dlopen(), if a shared library */
void_ptr_t shrsym; /* Placeholder for result of fgn_getrtn(), which we pass from zro_search() to
* incr_link().
@@ -43,5 +43,8 @@ typedef struct zro_ent_type
int zro_gettok(char **lp, char *top, mstr *tok);
void zsrch_clr(int indx);
void zro_search(mstr *objstr, zro_ent **objdir, mstr *srcstr, zro_ent **srcdir, boolean_t skip);
+#ifdef AUTORELINK_SUPPORTED
+zro_hist *zro_search_hist(char *objnamebuf, zro_ent **objdir);
+#endif
#endif /* ZROUTINESSP_H_INCLUDED */
diff --git a/sr_unix/zshow_devices.c b/sr_unix/zshow_devices.c
index f2d315e..3c13138 100644
--- a/sr_unix/zshow_devices.c
+++ b/sr_unix/zshow_devices.c
@@ -60,8 +60,10 @@ LITREF zshow_index zshow_param_index[];
void zshow_devices(zshow_out *output)
{
io_log_name *l; /* logical name pointer */
+ io_log_name *savel; /* logical name pointer */
mval v;
mval m;
+ io_desc *tiod;
d_rm_struct *rm_ptr;
d_tt_struct *tt_ptr;
d_socket_struct *dsocketptr;
@@ -94,6 +96,7 @@ void zshow_devices(zshow_out *output)
static readonly char devop[] = "OPEN ";
static readonly char devcl[] = "CLOSED ";
static readonly char interrupt_text[] = "ZINTERRUPT ";
+ static readonly char stdout_text[] = "0-out";
/* gtmsocket specific */
static readonly char at_text[] = {'@'};
@@ -116,6 +119,7 @@ void zshow_devices(zshow_out *output)
static readonly char port_text[] = "PORT=";
static readonly char ichset_text[] = "ICHSET=";
static readonly char ochset_text[] = "OCHSET=";
+ static readonly char tls_text[] = "TLS ";
#ifdef __MVS__
static readonly char filetag_text[] = "FILETAG=";
static readonly char untagged_text[] = "UNTAGGED";
@@ -135,589 +139,636 @@ void zshow_devices(zshow_out *output)
char *charptr;
v.mvtype = MV_STR;
- for (l = io_root_log_name; l != 0; l = l->next)
+ savel = NULL;
+ for (l = io_root_log_name; ((l != 0) || (NULL != savel)); l = l->next)
{
+ /* If savel is set then process the output side of $principal */
+ if (NULL != savel)
+ {
+ l = savel;
+ }
if (l->iod->trans_name == l)
{
/* if it is an rm type we don't want to output the device if it is the stderr
device for a pipe device */
if ((rm_ptr = (d_rm_struct*)l->iod->dev_sp) && rm == l->iod->type && rm_ptr->pipe && rm_ptr->stderr_parent)
continue;
- v.str.addr = &l->dollar_io[0];
- v.str.len = l->len;
- zshow_output(output,&v.str);
+
+ if (l->iod->pair.in != l->iod->pair.out)
+ {
+ /* process the output side of $principal if savel is set */
+ if (NULL != savel)
+ {
+ tiod = l->iod->pair.out;
+ savel = NULL;
+ rm_ptr = (d_rm_struct*)tiod->dev_sp;
+ if ('&' == tiod->trans_name->dollar_io[0])
+ {
+ /* replace & with 0-out */
+ ZS_STR_OUT(&v, stdout_text);
+ } else
+ {
+ /* prepend with 0-out and a space */
+ ZS_STR_OUT(&v, stdout_text);
+ ZS_ONE_OUT(&v, space_text);
+ v.str.addr = &tiod->trans_name->dollar_io[0];
+ v.str.len = tiod->trans_name->len;
+ zshow_output(output,&v.str);
+ }
+ } else
+ {
+ /* plan to process the output side of $principal if it is std out*/
+
+ if (l->iod->pair.out == io_std_device->out)
+ savel = l;
+ tiod = l->iod;
+ v.str.addr = &l->dollar_io[0];
+ v.str.len = l->len;
+ zshow_output(output,&v.str);
+ }
+ } else
+ {
+ tiod = l->iod;
+ v.str.addr = &l->dollar_io[0];
+ v.str.len = l->len;
+ zshow_output(output,&v.str);
+ }
ZS_ONE_OUT(&v, space_text);
- if (l->iod->state == dev_open)
+ if (tiod->state == dev_open)
{
ZS_STR_OUT(&v, devop);
- switch(l->iod->type)
+ switch(tiod->type)
{
- case tt:
- ZS_STR_OUT(&v, terminal_text);
- tt_ptr = (d_tt_struct*)l->iod->dev_sp;
- if (!ctrlc_on && io_std_device->out == l->iod) /* and standard input */
- { ZS_PARM_SP(&v, zshow_nocene);
- }
- if (tt_ptr->enbld_outofbands.mask)
- { ZS_PARM_EQU(&v, zshow_ctra);
- ZS_STR_OUT(&v,dollarc_text);
- first = TRUE;
- for ( i = 1, j = 0; j < 32 ; j++,i = i * 2)
- { if (i & tt_ptr->enbld_outofbands.mask)
- { if (!first)
- { ZS_ONE_OUT(&v, comma_text);
- }else
- { first = FALSE;
- }
- MV_FORCE_MVAL(&m,j);
- mval_write(output,&m,FALSE);
+ case tt:
+ ZS_STR_OUT(&v, terminal_text);
+ tt_ptr = (d_tt_struct*)tiod->dev_sp;
+ if (!ctrlc_on && io_std_device->out == tiod) /* and standard input */
+ { ZS_PARM_SP(&v, zshow_nocene);
+ }
+ if (tt_ptr->enbld_outofbands.mask)
+ { ZS_PARM_EQU(&v, zshow_ctra);
+ ZS_STR_OUT(&v,dollarc_text);
+ first = TRUE;
+ for ( i = 1, j = 0; j < 32 ; j++,i = i * 2)
+ { if (i & tt_ptr->enbld_outofbands.mask)
+ { if (!first)
+ { ZS_ONE_OUT(&v, comma_text);
+ }else
+ { first = FALSE;
}
+ MV_FORCE_MVAL(&m,j);
+ mval_write(output,&m,FALSE);
}
- ZS_ONE_OUT(&v, rparen_text);
- ZS_ONE_OUT(&v, space_text);
- }
- if ((int4)(tt_ptr->term_ctrl) & TRM_NOECHO)
- {
- ZS_PARM_SP(&v, zshow_noecho);
- }
- if (tt_ptr->term_ctrl & TRM_PASTHRU)
- {
- ZS_PARM_SP(&v, zshow_past);
- } else
- {
- ZS_PARM_SP(&v, zshow_nopast);
- }
- if (!(tt_ptr->term_ctrl & TRM_ESCAPE))
- {
- ZS_PARM_SP(&v, zshow_noesca);
- }
- if (tt_ptr->term_ctrl & TRM_READSYNC)
- {
- ZS_PARM_SP(&v, zshow_reads);
- } else
- {
- ZS_PARM_SP(&v, zshow_noreads);
}
- if (tt_ptr->term_ctrl & TRM_NOTYPEAHD)
- {
- ZS_PARM_SP(&v, zshow_notype);
- } else
- {
- ZS_PARM_SP(&v, zshow_type);
- }
- if (!l->iod->wrap)
- {
- ZS_PARM_SP(&v, zshow_nowrap);
- }
- mask_out = &tt_ptr->mask_term;
- if (!tt_ptr->default_mask_term)
+ ZS_ONE_OUT(&v, rparen_text);
+ ZS_ONE_OUT(&v, space_text);
+ }
+ if ((int4)(tt_ptr->term_ctrl) & TRM_NOECHO)
+ {
+ ZS_PARM_SP(&v, zshow_noecho);
+ }
+ if (tt_ptr->term_ctrl & TRM_PASTHRU)
+ {
+ ZS_PARM_SP(&v, zshow_past);
+ } else
+ {
+ ZS_PARM_SP(&v, zshow_nopast);
+ }
+ if (!(tt_ptr->term_ctrl & TRM_ESCAPE))
+ {
+ ZS_PARM_SP(&v, zshow_noesca);
+ }
+ if (tt_ptr->term_ctrl & TRM_READSYNC)
+ {
+ ZS_PARM_SP(&v, zshow_reads);
+ } else
+ {
+ ZS_PARM_SP(&v, zshow_noreads);
+ }
+ if (tt_ptr->term_ctrl & TRM_NOTYPEAHD)
+ {
+ ZS_PARM_SP(&v, zshow_notype);
+ } else
+ {
+ ZS_PARM_SP(&v, zshow_type);
+ }
+ if (!tiod->wrap)
+ {
+ ZS_PARM_SP(&v, zshow_nowrap);
+ }
+ mask_out = &tt_ptr->mask_term;
+ if (!tt_ptr->default_mask_term)
+ {
+ ZS_PARM_EQU(&v, zshow_term);
+ ZS_STR_OUT(&v,dollarc_text);
+ first = TRUE;
+ for ( i = 0; i < 8 ;i++)
{
- ZS_PARM_EQU(&v, zshow_term);
- ZS_STR_OUT(&v,dollarc_text);
- first = TRUE;
- for ( i = 0; i < 8 ;i++)
- {
- for ( j = 0; j < 32; j++)
- if (mask_out->mask[i] & (1 << j))
+ for ( j = 0; j < 32; j++)
+ if (mask_out->mask[i] & (1 << j))
+ {
+ if (!first)
{
- if (!first)
- {
- ZS_ONE_OUT(&v, comma_text);
- } else
- first = FALSE;
- MV_FORCE_MVAL(&m,i * 32 + j);
- mval_write(output,&m,FALSE);
- }
- }
- ZS_ONE_OUT(&v, rparen_text);
- ZS_ONE_OUT(&v, space_text);
+ ZS_ONE_OUT(&v, comma_text);
+ } else
+ first = FALSE;
+ MV_FORCE_MVAL(&m,i * 32 + j);
+ mval_write(output,&m,FALSE);
+ }
}
- ZS_PARM_EQU(&v, zshow_width);
- MV_FORCE_MVAL(&m,(int)l->iod->width);
- mval_write(output, &m, FALSE);
+ ZS_ONE_OUT(&v, rparen_text);
ZS_ONE_OUT(&v, space_text);
- ZS_PARM_EQU(&v, zshow_leng);
- MV_FORCE_MVAL(&m,(int)l->iod->pair.out->length);
- mval_write(output, &m, FALSE);
- ZS_ONE_OUT(&v, space_text);
- if (l->iod->write_filter)
- {
- bool twoparms = FALSE;
+ }
+ ZS_PARM_EQU(&v, zshow_width);
+ MV_FORCE_MVAL(&m,(int)tiod->width);
+ mval_write(output, &m, FALSE);
+ ZS_ONE_OUT(&v, space_text);
+ ZS_PARM_EQU(&v, zshow_leng);
+ MV_FORCE_MVAL(&m,(int)tiod->pair.out->length);
+ mval_write(output, &m, FALSE);
+ ZS_ONE_OUT(&v, space_text);
+ if (tiod->write_filter)
+ {
+ bool twoparms = FALSE;
- ZS_PARM_EQU(&v, zshow_fil);
- if (l->iod->write_filter & CHAR_FILTER)
+ ZS_PARM_EQU(&v, zshow_fil);
+ if (tiod->write_filter & CHAR_FILTER)
+ {
+ if (tiod->write_filter & ESC1)
{
- if (l->iod->write_filter & ESC1)
- {
- twoparms = TRUE;
- ZS_ONE_OUT(&v,lparen_text);
- }
- ZS_STR_OUT(&v,filchar_text);
- if (twoparms)
- {
- ZS_ONE_OUT(&v, comma_text);
- ZS_ONE_OUT(&v, space_text);
- }
+ twoparms = TRUE;
+ ZS_ONE_OUT(&v,lparen_text);
}
- if (l->iod->write_filter & ESC1)
- ZS_STR_OUT(&v,filesc_text);
+ ZS_STR_OUT(&v,filchar_text);
if (twoparms)
- ZS_ONE_OUT(&v,rparen_text);
- ZS_ONE_OUT(&v, space_text);
+ {
+ ZS_ONE_OUT(&v, comma_text);
+ ZS_ONE_OUT(&v, space_text);
+ }
}
- if (TT_EDITING & tt_ptr->ext_cap)
- ZS_PARM_SP(&v, zshow_edit);
- if (TT_NOINSERT & tt_ptr->ext_cap)
- ZS_PARM_SP(&v, zshow_noinse);
- if (TT_EMPTERM & tt_ptr->ext_cap)
- ZS_PARM_SP(&v, zshow_empterm);
- if (tt_ptr->canonical)
- ZS_STR_OUT(&v, "CANONICAL ");
- switch(l->iod->ichset)
+ if (tiod->write_filter & ESC1)
+ ZS_STR_OUT(&v,filesc_text);
+ if (twoparms)
+ ZS_ONE_OUT(&v,rparen_text);
+ ZS_ONE_OUT(&v, space_text);
+ }
+ if (TT_EDITING & tt_ptr->ext_cap)
+ ZS_PARM_SP(&v, zshow_edit);
+ if (TT_NOINSERT & tt_ptr->ext_cap)
+ ZS_PARM_SP(&v, zshow_noinse);
+ if (TT_EMPTERM & tt_ptr->ext_cap)
+ ZS_PARM_SP(&v, zshow_empterm);
+ if (tt_ptr->canonical)
+ ZS_STR_OUT(&v, "CANONICAL ");
+ switch(tiod->ichset)
+ {
+ case CHSET_M:
+ if (gtm_utf8_mode)
{
- case CHSET_M:
- if (gtm_utf8_mode)
- {
- ZS_STR_OUT(&v, ichset_text);
- zshow_output(output, &chset_names[l->iod->ichset]);
- ZS_ONE_OUT(&v, space_text);
- }
- break;
- case CHSET_UTF8:
- assert(gtm_utf8_mode);
- break;
- default:
- assertpro(l->iod->ichset != l->iod->ichset);
+ ZS_STR_OUT(&v, ichset_text);
+ zshow_output(output, &chset_names[tiod->ichset]);
+ ZS_ONE_OUT(&v, space_text);
}
- switch(l->iod->ochset)
+ break;
+ case CHSET_UTF8:
+ assert(gtm_utf8_mode);
+ break;
+ default:
+ assertpro(tiod->ichset != tiod->ichset);
+ }
+ switch(tiod->ochset)
+ {
+ case CHSET_M:
+ if (gtm_utf8_mode)
{
- case CHSET_M:
- if (gtm_utf8_mode)
- {
- ZS_STR_OUT(&v, ochset_text);
- zshow_output(output, &chset_names[l->iod->ochset]);
- ZS_ONE_OUT(&v, space_text);
- }
- break;
- case CHSET_UTF8:
- assert(gtm_utf8_mode);
- break;
- default:
- assertpro(l->iod->ochset != l->iod->ochset);
+ ZS_STR_OUT(&v, ochset_text);
+ zshow_output(output, &chset_names[tiod->ochset]);
+ ZS_ONE_OUT(&v, space_text);
}
- if (tt_ptr->mupintr)
- ZS_STR_OUT(&v, interrupt_text);
break;
- case rm:
- /* we go to rm_ptr above for the rm type */
+ case CHSET_UTF8:
+ assert(gtm_utf8_mode);
+ break;
+ default:
+ assertpro(tiod->ochset != tiod->ochset);
+ }
+ if (tt_ptr->mupintr)
+ ZS_STR_OUT(&v, interrupt_text);
+ break;
+ case rm:
+ /* we go to rm_ptr above for the rm type */
- if (rm_ptr->fifo)
- ZS_STR_OUT(&v,fifo_text);
- else if (!rm_ptr->pipe)
+ if (rm_ptr->fifo)
+ ZS_STR_OUT(&v,fifo_text);
+ else if (!rm_ptr->pipe)
+ {
+ ZS_STR_OUT(&v,rmsfile_text);
+ if (rm_ptr->follow)
{
- ZS_STR_OUT(&v,rmsfile_text);
- if (rm_ptr->follow)
- {
- ZS_PARM_SP(&v, zshow_follow);
- }
+ ZS_PARM_SP(&v, zshow_follow);
}
- else
+ }
+ else
+ {
+ ZS_STR_OUT(&v,pipe_text);
+ if (rm_ptr->dev_param_pairs.num_pairs)
{
- ZS_STR_OUT(&v,pipe_text);
- if (rm_ptr->dev_param_pairs.num_pairs)
- {
- int ignore_stderr = FALSE;
- /* if one of the dev_param_pairs[i]->name is the
- STDERR then we don't want to output it if the
- device is closed. We'll check them all even though
- it is currently the last one - just to be safe. */
- if (rm_ptr->stderr_child && (dev_open !=
- rm_ptr->stderr_child->state))
- ignore_stderr = TRUE;
+ int ignore_stderr = FALSE;
+ /* if one of the dev_param_pairs[i]->name is the
+ STDERR then we don't want to output it if the
+ device is closed. We'll check them all even though
+ it is currently the last one - just to be safe. */
+ if (rm_ptr->stderr_child && (dev_open !=
+ rm_ptr->stderr_child->state))
+ ignore_stderr = TRUE;
- for ( i = 0; i < rm_ptr->dev_param_pairs.num_pairs; i++ )
- {
- if (TRUE == ignore_stderr &&
- 0 == STRCMP(rm_ptr->dev_param_pairs.pairs[i].name,
- "STDERR="))
- continue;
- ZS_VAR_STR_OUT(
- &v,rm_ptr->dev_param_pairs.pairs[i].name);
- ZS_VAR_STR_OUT(
- &v,rm_ptr->dev_param_pairs.pairs[i].definition);
- ZS_ONE_OUT(&v, space_text);
- }
- }
- if (rm_ptr->independent)
- {
- ZS_PARM_SP(&v, zshow_independent);
- }
- if (rm_ptr->parse)
+ for ( i = 0; i < rm_ptr->dev_param_pairs.num_pairs; i++ )
{
- ZS_PARM_SP(&v, zshow_parse);
+ if (TRUE == ignore_stderr &&
+ 0 == STRCMP(rm_ptr->dev_param_pairs.pairs[i].name,
+ "STDERR="))
+ continue;
+ ZS_VAR_STR_OUT(
+ &v,rm_ptr->dev_param_pairs.pairs[i].name);
+ ZS_VAR_STR_OUT(
+ &v,rm_ptr->dev_param_pairs.pairs[i].definition);
+ ZS_ONE_OUT(&v, space_text);
}
}
- if (rm_ptr->fixed)
+ if (rm_ptr->independent)
{
- ZS_PARM_SP(&v, zshow_fixed);
+ ZS_PARM_SP(&v, zshow_independent);
}
-# ifdef UNIX
- else if (rm_ptr->stream)
+ if (rm_ptr->parse)
{
- ZS_PARM_SP(&v, zshow_stream);
+ ZS_PARM_SP(&v, zshow_parse);
}
+ }
+ if (rm_ptr->fixed)
+ {
+ ZS_PARM_SP(&v, zshow_fixed);
+ }
+# ifdef UNIX
+ else if (rm_ptr->stream)
+ {
+ ZS_PARM_SP(&v, zshow_stream);
+ }
# endif
- if (rm_ptr->read_only)
- {
- ZS_PARM_SP(&v, zshow_read);
- }
- if (gtm_utf8_mode && (IS_UTF_CHSET(l->iod->ichset) || IS_UTF_CHSET(l->iod->ochset)))
- {
- if (!rm_ptr->def_recsize)
- {
- ZS_PARM_EQU(&v, zshow_rec);
- MV_FORCE_MVAL(&m, (int)rm_ptr->recordsize);
- mval_write(output, &m, FALSE);
- ZS_ONE_OUT(&v, space_text);
- }
- if (!rm_ptr->def_width)
- {
- ZS_PARM_EQU(&v, zshow_width);
- MV_FORCE_MVAL(&m, (int)l->iod->width);
- mval_write(output, &m, FALSE);
- ZS_ONE_OUT(&v, space_text);
- }
- }
- else if (l->iod->width != DEF_RM_WIDTH)
+ if (rm_ptr->read_only)
+ {
+ ZS_PARM_SP(&v, zshow_read);
+ }
+ if (gtm_utf8_mode && (IS_UTF_CHSET(tiod->ichset) || IS_UTF_CHSET(tiod->ochset)))
+ {
+ if (!rm_ptr->def_recsize)
{
ZS_PARM_EQU(&v, zshow_rec);
- MV_FORCE_MVAL(&m,(int)l->iod->width);
+ MV_FORCE_MVAL(&m, (int)rm_ptr->recordsize);
mval_write(output, &m, FALSE);
ZS_ONE_OUT(&v, space_text);
}
- if (!l->iod->wrap)
+ if (!rm_ptr->def_width)
{
- ZS_PARM_SP(&v, zshow_nowrap);
+ ZS_PARM_EQU(&v, zshow_width);
+ MV_FORCE_MVAL(&m, (int)tiod->width);
+ mval_write(output, &m, FALSE);
+ ZS_ONE_OUT(&v, space_text);
}
- switch(l->iod->ichset)
+ }
+ else if (tiod->width != DEF_RM_WIDTH)
+ {
+ ZS_PARM_EQU(&v, zshow_rec);
+ MV_FORCE_MVAL(&m,(int)tiod->width);
+ mval_write(output, &m, FALSE);
+ ZS_ONE_OUT(&v, space_text);
+ }
+ if (!tiod->wrap)
+ {
+ ZS_PARM_SP(&v, zshow_nowrap);
+ }
+ switch(tiod->ichset)
+ {
+ case CHSET_M:
+ if (gtm_utf8_mode)
{
- case CHSET_M:
- if (gtm_utf8_mode)
- {
- ZS_STR_OUT(&v, ichset_text);
- zshow_output(output, &chset_names[l->iod->ichset]);
- ZS_ONE_OUT(&v, space_text);
- }
- break;
- case CHSET_UTF8:
- assert(gtm_utf8_mode);
- break;
- case CHSET_UTF16:
- case CHSET_UTF16BE:
- case CHSET_UTF16LE:
- assert(gtm_utf8_mode);
- ZS_STR_OUT(&v, ichset_text);
- zshow_output(output, &chset_names[l->iod->ichset]);
- ZS_ONE_OUT(&v, space_text);
- break;
- default:
- assertpro(l->iod->ichset != l->iod->ichset);
+ ZS_STR_OUT(&v, ichset_text);
+ zshow_output(output, &chset_names[tiod->ichset]);
+ ZS_ONE_OUT(&v, space_text);
}
- switch(l->iod->ochset)
+ break;
+ case CHSET_UTF8:
+ assert(gtm_utf8_mode);
+ break;
+ case CHSET_UTF16:
+ case CHSET_UTF16BE:
+ case CHSET_UTF16LE:
+ assert(gtm_utf8_mode);
+ ZS_STR_OUT(&v, ichset_text);
+ zshow_output(output, &chset_names[tiod->ichset]);
+ ZS_ONE_OUT(&v, space_text);
+ break;
+ default:
+ assertpro(tiod->ichset != tiod->ichset);
+ }
+ switch(tiod->ochset)
+ {
+ case CHSET_M:
+ if (gtm_utf8_mode)
{
- case CHSET_M:
- if (gtm_utf8_mode)
- {
- ZS_STR_OUT(&v, ochset_text);
- zshow_output(output, &chset_names[l->iod->ochset]);
- ZS_ONE_OUT(&v, space_text);
- }
- break;
- case CHSET_UTF8:
- assert(gtm_utf8_mode);
- break;
- case CHSET_UTF16:
- case CHSET_UTF16BE:
- case CHSET_UTF16LE:
- assert(gtm_utf8_mode);
- ZS_STR_OUT(&v, ochset_text);
- zshow_output(output, &chset_names[l->iod->ochset]);
- ZS_ONE_OUT(&v, space_text);
- break;
- default:
- assertpro(l->iod->ochset != l->iod->ochset);
+ ZS_STR_OUT(&v, ochset_text);
+ zshow_output(output, &chset_names[tiod->ochset]);
+ ZS_ONE_OUT(&v, space_text);
}
+ break;
+ case CHSET_UTF8:
+ assert(gtm_utf8_mode);
+ break;
+ case CHSET_UTF16:
+ case CHSET_UTF16BE:
+ case CHSET_UTF16LE:
+ assert(gtm_utf8_mode);
+ ZS_STR_OUT(&v, ochset_text);
+ zshow_output(output, &chset_names[tiod->ochset]);
+ ZS_ONE_OUT(&v, space_text);
+ break;
+ default:
+ assertpro(tiod->ochset != tiod->ochset);
+ }
#ifdef __MVS__
- if (TAG_ASCII != l->iod->file_tag)
+ if (TAG_ASCII != tiod->file_tag)
+ {
+ ZS_STR_OUT(&v, filetag_text);
+ switch ((unsigned int)tiod->file_tag)
{
- ZS_STR_OUT(&v, filetag_text);
- switch ((unsigned int)l->iod->file_tag)
- {
- case TAG_UNTAGGED:
- ZS_STR_OUT(&v, untagged_text);
- break;
- case TAG_EBCDIC:
- ZS_STR_OUT(&v, ebcdic_text);
- break;
- case TAG_BINARY:
- ZS_STR_OUT(&v, binary_text);
- break;
- default:
- if (-1 == __toCSName((__ccsid_t)l->iod->file_tag, csname))
- { /* no name so output number */
- csptr = (char *)i2asc((uchar_ptr_t)csname,
- (unsigned int)l->iod->file_tag);
- *csptr = '\0'; /* terminate */
- }
- ZS_VAR_STR_OUT(&v, csname);
+ case TAG_UNTAGGED:
+ ZS_STR_OUT(&v, untagged_text);
+ break;
+ case TAG_EBCDIC:
+ ZS_STR_OUT(&v, ebcdic_text);
+ break;
+ case TAG_BINARY:
+ ZS_STR_OUT(&v, binary_text);
+ break;
+ default:
+ if (-1 == __toCSName((__ccsid_t)tiod->file_tag, csname))
+ { /* no name so output number */
+ csptr = (char *)i2asc((uchar_ptr_t)csname,
+ (unsigned int)tiod->file_tag);
+ *csptr = '\0'; /* terminate */
}
- if (l->iod->text_flag)
- ZS_STR_OUT(&v, text_text);
- ZS_ONE_OUT(&v, space_text);
- }
- if (l->iod->file_chset != l->iod->process_chset &&
- (!(0 == l->iod->file_chset && CHSET_ASCII == l->iod->process_chset) &&
- !(CHSET_ASCII == l->iod->file_chset && CHSET_M == l->iod->process_chset)))
- { /* suppress default cases */
- ZS_STR_OUT(&v, processchset_text);
- zshow_output(output, &chset_names[l->iod->process_chset]);
- ZS_ONE_OUT(&v, space_text);
+ ZS_VAR_STR_OUT(&v, csname);
}
+ if (tiod->text_flag)
+ ZS_STR_OUT(&v, text_text);
+ ZS_ONE_OUT(&v, space_text);
+ }
+ if (tiod->file_chset != tiod->process_chset &&
+ (!(0 == tiod->file_chset && CHSET_ASCII == tiod->process_chset) &&
+ !(CHSET_ASCII == tiod->file_chset && CHSET_M == tiod->process_chset)))
+ { /* suppress default cases */
+ ZS_STR_OUT(&v, processchset_text);
+ zshow_output(output, &chset_names[tiod->process_chset]);
+ ZS_ONE_OUT(&v, space_text);
+ }
#endif
- break;
- case gtmsocket:
- delim.addr = delim_mstr_buff;
- delim_len = 0;
+ break;
+ case gtmsocket:
+ delim.addr = delim_mstr_buff;
+ delim_len = 0;
+ ZS_STR_OUT(&v, socket_text);
+ dsocketptr = (d_socket_struct *)tiod->dev_sp;
+ ZS_ONE_OUT(&v, space_text);
+ if (!tiod->wrap)
+ {
+ ZS_PARM_SP(&v, zshow_nowrap);
+ }
+ ZS_STR_OUT(&v, total_text);
+ MV_FORCE_MVAL(&m, (int)dsocketptr->n_socket);
+ mval_write(output, &m, FALSE);
+ ZS_ONE_OUT(&v, space_text);
+ ZS_STR_OUT(&v, current_text);
+ MV_FORCE_MVAL(&m, (int)dsocketptr->current_socket);
+ mval_write(output, &m, FALSE);
+ ZS_ONE_OUT(&v, space_text);
+ if (dsocketptr->mupintr)
+ ZS_STR_OUT(&v, interrupt_text);
+ output->flush = TRUE;
+ zshow_output(output, 0);
+ for(ii = 0; ii < dsocketptr->n_socket; ii++)
+ {
+ /* output each socket */
+ socketptr = dsocketptr->socket[ii];
+ ZS_STR_OUT(&v, space8_text);
+ /* socket handle */
ZS_STR_OUT(&v, socket_text);
- dsocketptr = (d_socket_struct *)l->iod->dev_sp;
- ZS_ONE_OUT(&v, space_text);
- if (!l->iod->wrap)
- {
- ZS_PARM_SP(&v, zshow_nowrap);
- }
- ZS_STR_OUT(&v, total_text);
- MV_FORCE_MVAL(&m, (int)dsocketptr->n_socket);
+ ZS_ONE_OUT(&v, lb_text);
+ MV_FORCE_MVAL(&m, ii);
mval_write(output, &m, FALSE);
+ ZS_ONE_OUT(&v, rb_text);
+ ZS_ONE_OUT(&v, equal_text);
+ v.str.addr = socketptr->handle;
+ v.str.len = socketptr->handle_len;
+ zshow_output(output, &v.str);
ZS_ONE_OUT(&v, space_text);
- ZS_STR_OUT(&v, current_text);
- MV_FORCE_MVAL(&m, (int)dsocketptr->current_socket);
+ /* socket descriptor */
+ ZS_STR_OUT(&v, descriptor_text);
+ MV_FORCE_MVAL(&m, socketptr->sd);
mval_write(output, &m, FALSE);
ZS_ONE_OUT(&v, space_text);
- if (dsocketptr->mupintr)
- ZS_STR_OUT(&v, interrupt_text);
- output->flush = TRUE;
- zshow_output(output, 0);
- for(ii = 0; ii < dsocketptr->n_socket; ii++)
+ /* socket state */
+ ZS_STR_OUT(&v, zsh_socket_state[socketptr->state]);
+ ZS_ONE_OUT(&v, space_text);
+ /* socket IO mode */ switch(tiod->ichset)
{
- /* output each socket */
- socketptr = dsocketptr->socket[ii];
- ZS_STR_OUT(&v, space8_text);
- /* socket handle */
- ZS_STR_OUT(&v, socket_text);
- ZS_ONE_OUT(&v, lb_text);
- MV_FORCE_MVAL(&m, ii);
- mval_write(output, &m, FALSE);
- ZS_ONE_OUT(&v, rb_text);
- ZS_ONE_OUT(&v, equal_text);
- v.str.addr = socketptr->handle;
- v.str.len = socketptr->handle_len;
- zshow_output(output, &v.str);
- ZS_ONE_OUT(&v, space_text);
- /* socket descriptor */
- ZS_STR_OUT(&v, descriptor_text);
- MV_FORCE_MVAL(&m, socketptr->sd);
- mval_write(output, &m, FALSE);
- ZS_ONE_OUT(&v, space_text);
- /* socket state */
- ZS_STR_OUT(&v, zsh_socket_state[socketptr->state]);
- ZS_ONE_OUT(&v, space_text);
- /* socket IO mode */ switch(l->iod->ichset)
+ case CHSET_M:
+ if (gtm_utf8_mode)
{
- case CHSET_M:
- if (gtm_utf8_mode)
- {
- ZS_STR_OUT(&v, ichset_text);
- zshow_output(output, &chset_names[l->iod->ichset]);
- ZS_ONE_OUT(&v, space_text);
- }
- break;
- case CHSET_UTF8:
- assert(gtm_utf8_mode);
- break;
- case CHSET_UTF16:
- case CHSET_UTF16BE:
- case CHSET_UTF16LE:
- assert(gtm_utf8_mode);
- ZS_STR_OUT(&v, ichset_text);
- zshow_output(output, &chset_names[l->iod->ichset]);
- ZS_ONE_OUT(&v, space_text);
- break;
- default:
- assertpro(l->iod->ichset != l->iod->ichset);
+ ZS_STR_OUT(&v, ichset_text);
+ zshow_output(output, &chset_names[tiod->ichset]);
+ ZS_ONE_OUT(&v, space_text);
}
- switch(l->iod->ochset)
+ break;
+ case CHSET_UTF8:
+ assert(gtm_utf8_mode);
+ break;
+ case CHSET_UTF16:
+ case CHSET_UTF16BE:
+ case CHSET_UTF16LE:
+ assert(gtm_utf8_mode);
+ ZS_STR_OUT(&v, ichset_text);
+ zshow_output(output, &chset_names[tiod->ichset]);
+ ZS_ONE_OUT(&v, space_text);
+ break;
+ default:
+ assertpro(tiod->ichset != tiod->ichset);
+ }
+ switch(tiod->ochset)
+ {
+ case CHSET_M:
+ if (gtm_utf8_mode)
{
- case CHSET_M:
- if (gtm_utf8_mode)
- {
- ZS_STR_OUT(&v, ochset_text);
- zshow_output(output, &chset_names[l->iod->ochset]);
- ZS_ONE_OUT(&v, space_text);
- }
- break;
- case CHSET_UTF8:
- assert(gtm_utf8_mode);
- break;
- case CHSET_UTF16:
- case CHSET_UTF16BE:
- case CHSET_UTF16LE:
- assert(gtm_utf8_mode);
- ZS_STR_OUT(&v, ochset_text);
- zshow_output(output, &chset_names[l->iod->ochset]);
- ZS_ONE_OUT(&v, space_text);
- break;
- default:
- assertpro(l->iod->ochset != l->iod->ochset);
+ ZS_STR_OUT(&v, ochset_text);
+ zshow_output(output, &chset_names[tiod->ochset]);
+ ZS_ONE_OUT(&v, space_text);
}
- /* socket type */
- if (socketptr->passive)
+ break;
+ case CHSET_UTF8:
+ assert(gtm_utf8_mode);
+ break;
+ case CHSET_UTF16:
+ case CHSET_UTF16BE:
+ case CHSET_UTF16LE:
+ assert(gtm_utf8_mode);
+ ZS_STR_OUT(&v, ochset_text);
+ zshow_output(output, &chset_names[tiod->ochset]);
+ ZS_ONE_OUT(&v, space_text);
+ break;
+ default:
+ assertpro(tiod->ochset != tiod->ochset);
+ }
+ /* socket type */
+ if (socketptr->passive)
+ {
+ ZS_STR_OUT(&v, passive_text);
+ } else
+ {
+ ZS_STR_OUT(&v, active_text);
+ }
+ ZS_ONE_OUT(&v, space_text);
+ /* error trapping */
+ if (socketptr->ioerror)
+ {
+ ZS_STR_OUT(&v, trap_text);
+ } else
+ {
+ ZS_STR_OUT(&v, notrap_text);
+ }
+ ZS_ONE_OUT(&v, space_text);
+ /* address + port */
+ if ((socket_local != socketptr->protocol) && socketptr->passive)
+ {
+ ZS_STR_OUT(&v, port_text);
+ tmpport = (int)socketptr->local.port;
+ MV_FORCE_MVAL(&m, tmpport);
+ mval_write(output, &m, FALSE);
+ } else
+ {
+ ZS_STR_OUT(&v, remote_text);
+ if (NULL != socketptr->remote.saddr_ip)
{
- ZS_STR_OUT(&v, passive_text);
+ v.str.addr = socketptr->remote.saddr_ip;
+ v.str.len = STRLEN(socketptr->remote.saddr_ip);
} else
{
- ZS_STR_OUT(&v, active_text);
+ v.str.addr = "";
+ v.str.len = 0;
}
- ZS_ONE_OUT(&v, space_text);
- /* error trapping */
- if (socketptr->ioerror)
- {
- ZS_STR_OUT(&v, trap_text);
- } else
+ zshow_output(output, &v.str);
+ if (socket_local != socketptr->protocol)
{
- ZS_STR_OUT(&v, notrap_text);
+ ZS_ONE_OUT(&v, at_text);
+ tmpport = (int)socketptr->remote.port;
+ MV_FORCE_MVAL(&m, tmpport);
+ mval_write(output, &m, FALSE);
}
ZS_ONE_OUT(&v, space_text);
- /* address + port */
- if ((socket_local != socketptr->protocol) && socketptr->passive)
+ if (NULL != socketptr->local.saddr_ip)
{
- ZS_STR_OUT(&v, port_text);
+ ZS_STR_OUT(&v, local_text);
+ v.str.addr = socketptr->local.saddr_ip;
+ v.str.len = STRLEN(socketptr->local.saddr_ip);
+ zshow_output(output, &v.str);
+ ZS_ONE_OUT(&v, at_text);
tmpport = (int)socketptr->local.port;
MV_FORCE_MVAL(&m, tmpport);
mval_write(output, &m, FALSE);
- } else
+ } else if (socket_local == socketptr->protocol)
{
- ZS_STR_OUT(&v, remote_text);
- if (NULL != socketptr->remote.saddr_ip)
- {
- v.str.addr = socketptr->remote.saddr_ip;
- v.str.len = STRLEN(socketptr->remote.saddr_ip);
- } else
- {
- v.str.addr = "";
- v.str.len = 0;
- }
- zshow_output(output, &v.str);
- if (socket_local != socketptr->protocol)
+ ZS_STR_OUT(&v, local_text);
+ if (NULL != socketptr->local.sa)
{
- ZS_ONE_OUT(&v, at_text);
- tmpport = (int)socketptr->remote.port;
- MV_FORCE_MVAL(&m, tmpport);
- mval_write(output, &m, FALSE);
- }
- ZS_ONE_OUT(&v, space_text);
- if (NULL != socketptr->local.saddr_ip)
- {
- ZS_STR_OUT(&v, local_text);
- v.str.addr = socketptr->local.saddr_ip;
- v.str.len = STRLEN(socketptr->local.saddr_ip);
- zshow_output(output, &v.str);
- ZS_ONE_OUT(&v, at_text);
- tmpport = (int)socketptr->local.port;
- MV_FORCE_MVAL(&m, tmpport);
- mval_write(output, &m, FALSE);
- } else if (socket_local == socketptr->protocol)
- {
- ZS_STR_OUT(&v, local_text);
- if (NULL != socketptr->local.sa)
- {
- charptr = ((struct sockaddr_un *)
- (socketptr->local.sa))->sun_path;
- ZS_VAR_STR_OUT(&v, charptr);
- } else if (NULL != socketptr->remote.sa)
- { /* CONNECT shows remote path as LOCAL */
- charptr = ((struct sockaddr_un *)
- (socketptr->remote.sa))->sun_path;
- ZS_VAR_STR_OUT(&v, charptr);
- }
+ charptr = ((struct sockaddr_un *)
+ (socketptr->local.sa))->sun_path;
+ ZS_VAR_STR_OUT(&v, charptr);
+ } else if (NULL != socketptr->remote.sa)
+ { /* CONNECT shows remote path as LOCAL */
+ charptr = ((struct sockaddr_un *)
+ (socketptr->remote.sa))->sun_path;
+ ZS_VAR_STR_OUT(&v, charptr);
}
}
- ZS_ONE_OUT(&v, space_text);
+ }
+ ZS_ONE_OUT(&v, space_text);
+ output->flush = TRUE;
+ zshow_output(output, 0);
+ ZS_STR_OUT(&v, space8_text);
+ ZS_STR_OUT(&v, space8_text);
+ /* zdelay */
+ if (socketptr->nodelay)
+ {
+ ZS_STR_OUT(&v, znodelay_text);
+ } else
+ {
+ ZS_STR_OUT(&v, zdelay_text);
+ }
+ ZS_ONE_OUT(&v, space_text);
+ /* zbfsize */
+ ZS_STR_OUT(&v, zbfsize_text);
+ MV_FORCE_MVAL(&m, (int4)(socketptr->buffer_size));
+ mval_write(output, &m, FALSE);
+ ZS_ONE_OUT(&v, space_text);
+ /* izbfsize */
+ ZS_STR_OUT(&v, zibfsize_text);
+ MV_FORCE_MVAL(&m, socketptr->bufsiz);
+ mval_write(output, &m, FALSE);
+ ZS_ONE_OUT(&v, space_text);
+ if (socketptr->tlsenabled && (NULL != socketptr->tlssocket))
+ {
+ ZS_STR_OUT(&v, tls_text);
+ }
+ /* delimiters */
+ if (socketptr->n_delimiter > 0)
+ {
output->flush = TRUE;
zshow_output(output, 0);
ZS_STR_OUT(&v, space8_text);
ZS_STR_OUT(&v, space8_text);
- /* zdelay */
- if (socketptr->nodelay)
- {
- ZS_STR_OUT(&v, znodelay_text);
- } else
+ ZS_STR_OUT(&v, delimiter_text);
+ for (jj = 0; jj < socketptr->n_delimiter; jj++)
{
- ZS_STR_OUT(&v, zdelay_text);
+ delim_len_sm = socketptr->delimiter[jj].len;
+ memcpy(delim_buff_sm,
+ socketptr->delimiter[jj].addr, delim_len_sm);
+ format2zwr(delim_buff_sm, delim_len_sm,
+ (uchar_ptr_t)delim.addr, &delim_len);
+ delim.len = (unsigned short)delim_len;
+ assert(SIZEOF(delim_mstr_buff) >= delim_len);
+ zshow_output(output, &delim);
+ ZS_ONE_OUT(&v, space_text);
}
- ZS_ONE_OUT(&v, space_text);
- /* zbfsize */
- ZS_STR_OUT(&v, zbfsize_text);
- MV_FORCE_MVAL(&m, (int4)(socketptr->buffer_size));
- mval_write(output, &m, FALSE);
- ZS_ONE_OUT(&v, space_text);
- /* izbfsize */
- ZS_STR_OUT(&v, zibfsize_text);
- MV_FORCE_MVAL(&m, socketptr->bufsiz);
+ } else
+ {
+ ZS_STR_OUT(&v, nodelimiter_text);
+ }
+ /* readmoretime */
+ if (DEFAULT_MOREREAD_TIMEOUT != socketptr->moreread_timeout)
+ {
+ ZS_STR_OUT(&v, morereadtime_text);
+ MV_FORCE_MVAL(&m, (int)socketptr->moreread_timeout);
mval_write(output, &m, FALSE);
- ZS_ONE_OUT(&v, space_text);
- /* delimiters */
- if (socketptr->n_delimiter > 0)
- {
- output->flush = TRUE;
- zshow_output(output, 0);
- ZS_STR_OUT(&v, space8_text);
- ZS_STR_OUT(&v, space8_text);
- ZS_STR_OUT(&v, delimiter_text);
- for (jj = 0; jj < socketptr->n_delimiter; jj++)
- {
- delim_len_sm = socketptr->delimiter[jj].len;
- memcpy(delim_buff_sm,
- socketptr->delimiter[jj].addr, delim_len_sm);
- format2zwr(delim_buff_sm, delim_len_sm,
- (uchar_ptr_t)delim.addr, &delim_len);
- delim.len = (unsigned short)delim_len;
- assert(SIZEOF(delim_mstr_buff) >= delim_len);
- zshow_output(output, &delim);
- ZS_ONE_OUT(&v, space_text);
- }
- } else
- {
- ZS_STR_OUT(&v, nodelimiter_text);
- }
- /* readmoretime */
- if (DEFAULT_MOREREAD_TIMEOUT != socketptr->moreread_timeout)
- {
- ZS_STR_OUT(&v, morereadtime_text);
- MV_FORCE_MVAL(&m, (int)socketptr->moreread_timeout);
- mval_write(output, &m, FALSE);
- }
- output->flush = TRUE;
- zshow_output(output, 0);
}
- default:
- v.str.len = 0;
- break;
+ output->flush = TRUE;
+ zshow_output(output, 0);
+ }
+ default:
+ v.str.len = 0;
+ break;
}
- if (l->iod->error_handler.len)
+ if (tiod->error_handler.len)
{
ZS_PARM_EQU(&v, zshow_exce);
ZS_ONE_OUT(&v, quote_text);
- v.str = l->iod->error_handler;
+ v.str = tiod->error_handler;
zshow_output(output, &v.str);
output->flush = TRUE;
ZS_ONE_OUT(&v, quote_text);
diff --git a/sr_unix/zshow_rctldump.c b/sr_unix/zshow_rctldump.c
new file mode 100644
index 0000000..8136031
--- /dev/null
+++ b/sr_unix/zshow_rctldump.c
@@ -0,0 +1,96 @@
+/****************************************************************
+ * *
+ * Copyright 2014 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#ifdef AUTORELINK_SUPPORTED
+
+#include "gtm_string.h"
+
+#include "relinkctl.h"
+#include "util.h"
+#include "zshow.h"
+
+#define DUMP_ONE_LINE(OUTPUT, BUFF, NBYTES) \
+{ \
+ mstr line; \
+ \
+ if (NBYTES >= SIZEOF(BUFF)) \
+ NBYTES = SIZEOF(BUFF); /* Output from SNPRINTF was truncated. */ \
+ if (NULL != OUTPUT) \
+ { /* Caller is ZSHOW "R". Use zshow_output. */ \
+ line.len = NBYTES; \
+ line.addr = &BUFF[0]; \
+ OUTPUT->flush = TRUE; \
+ zshow_output(OUTPUT, &line); \
+ } else \
+ { /* Caller is MUPIP RCTLDUMP. Use util_out_print. */ \
+ util_out_print("!AD", FLUSH, NBYTES, BUFF); \
+ } \
+}
+
+void zshow_rctldump(zshow_out *output)
+{
+ open_relinkctl_sgm *linkctl;
+ relinkshm_hdr_t *shm_hdr;
+ relinkrec_t *linkrec;
+ relinkctl_data *hdr;
+ rtnobjshm_hdr_t *rtnobj_shm_hdr;
+ int i, j, recnum, n_records, nbytes;
+ char buff[OUT_BUFF_SIZE];
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ for (linkctl = TREF(open_relinkctl_list); NULL != linkctl; linkctl = linkctl->next)
+ {
+ hdr = linkctl->hdr;
+ nbytes = SNPRINTF(buff, SIZEOF(buff), "Object Directory : %.*s",
+ linkctl->zro_entry_name.len, linkctl->zro_entry_name.addr);
+ DUMP_ONE_LINE(output, buff, nbytes);
+ nbytes = SNPRINTF(buff, SIZEOF(buff), "Relinkctl filename : %s", linkctl->relinkctl_path);
+ DUMP_ONE_LINE(output, buff, nbytes);
+ n_records = hdr->n_records;
+ nbytes = SNPRINTF(buff, SIZEOF(buff), "# of routines : %d", n_records);
+ DUMP_ONE_LINE(output, buff, nbytes);
+ nbytes = SNPRINTF(buff, SIZEOF(buff), "# of attached processes : %d", hdr->nattached);
+ DUMP_ONE_LINE(output, buff, nbytes);
+ nbytes = SNPRINTF(buff, SIZEOF(buff), "Relinkctl shared memory : shmid: %d shmlen: 0x%llx",
+ hdr->relinkctl_shmid, hdr->relinkctl_shmlen);
+ DUMP_ONE_LINE(output, buff, nbytes);
+ shm_hdr = GET_RELINK_SHM_HDR(linkctl);
+ for (i = 0, j = 1; i < NUM_RTNOBJ_SHM_INDEX; i++)
+ {
+ rtnobj_shm_hdr = &shm_hdr->rtnobj_shmhdr[i];
+ if (INVALID_SHMID != rtnobj_shm_hdr->rtnobj_shmid)
+ {
+ nbytes = SNPRINTF(buff, SIZEOF(buff), "Rtnobj shared memory #%2.d : shmid: %u shmlen: 0x%llx"
+ " shmused: 0x%llx shmfree: 0x%llx objlen: 0x%llx",
+ j, rtnobj_shm_hdr->rtnobj_shmid, rtnobj_shm_hdr->shm_len,
+ rtnobj_shm_hdr->used_len,
+ rtnobj_shm_hdr->shm_len - rtnobj_shm_hdr->used_len,
+ rtnobj_shm_hdr->real_len);
+ DUMP_ONE_LINE(output, buff, nbytes);
+ j++;
+ }
+ }
+ for (linkrec = linkctl->rec_base, recnum = 1; recnum <= n_records; linkrec++, recnum++)
+ {
+ nbytes = SNPRINTF(buff, SIZEOF(buff), " rec#%d: rtnname: %.*s cycle: %d objhash: 0x%llx"
+ " numvers: %d objlen: 0x%llx shmlen: 0x%llx",
+ recnum, mid_len(&linkrec->rtnname_fixed), &linkrec->rtnname_fixed.c,
+ linkrec->cycle, linkrec->objhash, linkrec->numvers, linkrec->objLen,
+ linkrec->usedLen);
+ DUMP_ONE_LINE(output, buff, nbytes);
+ }
+ }
+}
+
+#endif
diff --git a/sr_unix_nsb/obj_code.c b/sr_unix_nsb/obj_code.c
index fce4e5c..b0c09f2 100644
--- a/sr_unix_nsb/obj_code.c
+++ b/sr_unix_nsb/obj_code.c
@@ -49,7 +49,9 @@ GBLREF char cg_phase; /* code generation phase */
GBLREF char cg_phase_last; /* previous code generation phase */
GBLREF int4 curr_addr, code_size;
GBLREF char object_file_name[];
+GBLREF int object_file_des;
+error_def(ERR_SYSCALL);
error_def(ERR_TEXT);
void cg_lab (mlabel *l, int4 base);
@@ -85,6 +87,7 @@ void cg_lab (mlabel *l, int4 base);
void obj_code (uint4 src_lines, void *checksum_ctx)
{
+ int status;
rhdtyp rhead;
mline *mlx, *mly;
var_tabent *vptr;
@@ -171,13 +174,16 @@ void obj_code (uint4 src_lines, void *checksum_ctx)
}
if (0 != lnr_pad_len) /* emit padding so literal text pool starts on proper boundary */
emit_immed(PADCHARS, lnr_pad_len);
-#if !defined(__MVS__) && !defined(__s390__) /* assert not valid for instructions on OS390 */
+# if !defined(__MVS__) && !defined(__s390__) /* assert not valid for instructions on OS390 */
assert(code_size == psect_use_tab[GTM_CODE]);
-#endif
+# endif
emit_literals();
- close_object_file();
+ finish_object_file();
+ CLOSE_OBJECT_FILE(object_file_des, status);
+ if (-1 == status)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("close()"), CALLFROM, errno);
/* Ready to make object visible. Rename from tmp name to real routine name */
- rename_tmp_object_file(object_file_name);
+ RENAME_TMP_OBJECT_FILE(object_file_name);
}
void cg_lab (mlabel *l, int4 base)
diff --git a/sr_unix_nsb/obj_filesp.h b/sr_unix_nsb/obj_filesp.h
index cf8526d..1055bc8 100644
--- a/sr_unix_nsb/obj_filesp.h
+++ b/sr_unix_nsb/obj_filesp.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2004 Sanchez Computer Associates, Inc. *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -12,14 +12,8 @@
#ifndef OBJ_FILESP_INCLUDED
#define OBJ_FILESP_INCLUDED
-#ifdef __sparc
- void emit_addr(int4 refaddr_upper, int4 refaddr_lower, int4 offset, int4 *result_upper, int4 *result_lower);
- void emit_reference(uint4 refaddr_upper, uint4 refaddr_lower, mstr *name, uint4 *result_upper, uint4 *result_lower);
-#else
- void emit_addr(int4 refaddr, int4 offset, int4 *result);
- void emit_reference(uint4 refaddr, mstr *name, uint4 *result);
-#endif
-
+void emit_addr(int4 refaddr, int4 offset, int4 *result);
+void emit_reference(uint4 refaddr, mstr *name, uint4 *result);
struct sym_table *define_symbol(unsigned char psect, mstr *name, int4 value);
void emit_pidr(int4 refoffset, int4 data_offset, int4 *result);
void buff_emit(void);
diff --git a/sr_unix_nsb/rtnhdr.h b/sr_unix_nsb/rtnhdr.h
index 295db6e..73e7ed6 100644
--- a/sr_unix_nsb/rtnhdr.h
+++ b/sr_unix_nsb/rtnhdr.h
@@ -95,7 +95,7 @@ typedef struct rhead_struct
# ifdef GTM_TRIGGER
void_ptr_t trigr_handle; /* Type is void to avoid needing gv_trigger.h to define gv_trigger_t addr */
# endif
- unsigned char checksum_md5[16]; /* 16-byte MD5 checksum of routine source code */
+ unsigned char checksum_128[16]; /* 16-byte MurmurHash3 checksum of routine source code */
routine_source *source_code; /* source code used by $TEXT */
uint4 routine_source_offset; /* (updated) when compiled with EMBED_SOURCE: offset of M source within literal text
* pool; becomes absolute address in incr_link
@@ -144,7 +144,7 @@ typedef struct
#define VERIFY TRUE
#define NOVERIFY FALSE
-int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_t verifytrig);
+int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, rhdtyp **rtn_vec);
void free_src_tbl(rhdtyp *rtn_vector);
unsigned char *find_line_start(unsigned char *in_addr, rhdtyp *routine);
int4 *find_line_addr(rhdtyp *routine, mstr *label, int4 offset, mident **lent_name);
diff --git a/sr_vvms/dbcertify_exit_handler.c b/sr_vvms/dbcertify_exit_handler.c
index ebc8ef4..92bf3bf 100644
--- a/sr_vvms/dbcertify_exit_handler.c
+++ b/sr_vvms/dbcertify_exit_handler.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2005, 2013 Fidelity Information Services, Inc *
+ * Copyright 2005, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -105,7 +105,7 @@ void dbcertify_exit_handler(void)
* But the commit phase (beginning from when early_tn is curr_tn + 1 to when they become equal) is a relatively
* finite window wherefrom we are guaranteed to return.
*/
- if (psa_gbl->dbc_critical)
+ if ((NULL != psa_gbl) && psa_gbl->dbc_critical)
{
EXIT_HANDLER(&exi_blk);
ESTABLISH(exi_ch);
@@ -117,8 +117,11 @@ void dbcertify_exit_handler(void)
print_exit_stats();
if (0 == exi_condition)
exi_condition = ERR_UNKNOWNFOREX;
- if (psa_gbl->phase_one)
- dbc_scan_phase_cleanup();
- else
- dbc_certify_phase_cleanup();
+ if (NULL != psa_gbl)
+ {
+ if (psa_gbl->phase_one)
+ dbc_scan_phase_cleanup();
+ else
+ dbc_certify_phase_cleanup();
+ }
}
diff --git a/sr_vvms/get_src_line.c b/sr_vvms/get_src_line.c
index 040f914..756ca4b 100644
--- a/sr_vvms/get_src_line.c
+++ b/sr_vvms/get_src_line.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -29,7 +29,7 @@
#define RT_TBL_SZ 20
-int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_t verifytrig)
+int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, rhdtyp **rtn_vec)
{
struct FAB fab;
struct RAB rab;
@@ -60,10 +60,20 @@ int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_
op_zlink(routine, NULL);
rtn_vector = find_rtn_hdr(&routine->str);
if (!rtn_vector)
+ {
+ if (NULL != rtn_vec)
+ *rtn_vec = NULL;
return OBJMODMISS;
+ }
}
if (!rtn_vector->src_full_name.len)
+ {
+ if (NULL != rtn_vec)
+ *rtn_vec = NULL;
return SRCNOTAVAIL;
+ }
+ if (NULL != rtn_vec)
+ *rtn_vec = rtn_vector;
rtnent.var_name = rtn_vector->routine_name;
COMPUTE_HASH_MNAME(&rtnent);
added = add_hashtab_mname(TADR(rt_name_tbl), &rtnent, NULL, &tabent);
diff --git a/sr_vvms/gt_timers.c b/sr_vvms/gt_timers.c
index 42b4963..c8e90bb 100644
--- a/sr_vvms/gt_timers.c
+++ b/sr_vvms/gt_timers.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2007 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -14,7 +14,7 @@
* Following routines are top level, user callable
* routines of this package:
*
- * void sys_get_cur_time(ABS_TIME atp)
+ * void sys_get_curr_time(ABS_TIME atp)
* fetch absolute time into stucture
*
* void hiber_start(uint4 hiber)
@@ -62,7 +62,7 @@ void sys_get_curr_time(ABS_TIME *atp)
atp->at_sec = (uint4)(((((double)systim[1]) * MAX_INT) + (double)systim[0]) / 10000000.0);
return;
}
- rts_error(VARLSTCNT(1) status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
}
static void hiber_start_ast(void)
diff --git a/sr_vvms/gtm$startup.c b/sr_vvms/gtm$startup.c
index 83e01c3..84ad838 100644
--- a/sr_vvms/gtm$startup.c
+++ b/sr_vvms/gtm$startup.c
@@ -259,7 +259,7 @@ void gtm$startup(struct startup_vector *svec, boolean_t is_dal)
if (0 != svec->user_spawn_flag)
{
if (SS$_NORMAL != (trust_status = sys$getjpiw(EFN$C_ENF, 0, 0, item_list, 0, 0, 0)))
- rts_error(VARLSTCNT(1) trust_status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) trust_status);
else if (imagpriv & PRV$M_CMEXEC)
trust = svec->user_spawn_flag;
}
@@ -351,7 +351,7 @@ void gtm$startup(struct startup_vector *svec, boolean_t is_dal)
} else
{
licensed = FALSE;
- rts_error(VARLSTCNT(1) status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
}
# endif
jobinterrupt_init();
@@ -416,6 +416,7 @@ void gtm$startup(struct startup_vector *svec, boolean_t is_dal)
assert(FALSE == curr_symval->alias_activity);
curr_symval->alias_activity = TRUE;
lvzwr_init(0, (mval *)NULL);
+ TREF(in_zwrite) = FALSE;
curr_symval->alias_activity = FALSE;
/* Initialize cache structure for $Piece function (except for Vax which does not use this) */
for (i = 0; FNPC_MAX > i; i++)
diff --git a/sr_vvms/gtm_logicals.h b/sr_vvms/gtm_logicals.h
index 6c70468..e167838 100644
--- a/sr_vvms/gtm_logicals.h
+++ b/sr_vvms/gtm_logicals.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -16,14 +16,15 @@
#define GTM_DIST_LOG "GTM$DIST"
/* Database */
-#define GTM_GBLDIR "GTM$GBLDIR"
#define GTM_BLKUPGRADE_FLAG "GTM_BLKUPGRADE_FLAG"
#define GTM_DBFILEXT_SYSLOG_DISABLE "GTM_DBFILEXT_SYSLOG_DISABLE"
#define GTM_ENV_XLATE "GTM_ENV_TRANSLATE"
#define GTM_FULLBLOCKWRITES "GTM_FULLBLOCKWRITES"
#define GTM_GDSCERT "GTM_GDSCERT"
+#define GTM_GBLDIR "GTM$GBLDIR"
#define GTM_GVDUPSETNOOP "GTM_GVDUPSETNOOP"
#define GTM_GVUNDEF_FATAL "GTM_GVUNDEF_FATAL"
+#define GTM_POOLLIMIT "GTM_POOLLIMIT"
#define GTM_TP_ALLOCATION_CLUE "GTM_TP_ALLOCATION_CLUE"
#define GTM_TPNOTACIDTIME "GTM_TPNOTACIDTIME"
#define GTM_TPRESTART_LOG_DELTA "GTM_TPRESTART_LOG_DELTA"
diff --git a/sr_vvms/gtmrecv_process.c b/sr_vvms/gtmrecv_process.c
index c750e41..41711df 100644
--- a/sr_vvms/gtmrecv_process.c
+++ b/sr_vvms/gtmrecv_process.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2006, 2013 Fidelity Information Services, Inc.*
+ * Copyright 2006, 2014 Fidelity Information Services, Inc.*
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -121,7 +121,6 @@ error_def(ERR_REPLCOMM);
error_def(ERR_REPLGBL2LONG);
error_def(ERR_REPLTRANS2BIG);
error_def(ERR_REPLWARN);
-error_def(ERR_SECNODZTRIGINTP);
error_def(ERR_TEXT);
error_def(ERR_UNIMPLOP);
@@ -672,9 +671,6 @@ static void process_tr_buff(void)
(unsigned int)jnl_dest_maxrectype);
else if (EREPL_INTLFILTER_REPLGBL2LONG == repl_errno)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REPLGBL2LONG);
- else if (EREPL_INTLFILTER_SECNODZTRIGINTP == repl_errno)
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_SECNODZTRIGINTP, 1,
- &recvpool_ctl->jnl_seqno);
else /* (EREPL_INTLFILTER_INCMPLREC == repl_errno) */
assertpro(repl_errno != repl_errno);
}
diff --git a/sr_port/lastchance1.c b/sr_vvms/lastchance1.c
similarity index 100%
rename from sr_port/lastchance1.c
rename to sr_vvms/lastchance1.c
diff --git a/sr_port/lastchance2.c b/sr_vvms/lastchance2.c
similarity index 95%
rename from sr_port/lastchance2.c
rename to sr_vvms/lastchance2.c
index 8a2f872..689ba51 100644
--- a/sr_port/lastchance2.c
+++ b/sr_vvms/lastchance2.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
diff --git a/sr_port/lastchance3.c b/sr_vvms/lastchance3.c
similarity index 94%
rename from sr_port/lastchance3.c
rename to sr_vvms/lastchance3.c
index 991e2cd..d53ea9c 100644
--- a/sr_port/lastchance3.c
+++ b/sr_vvms/lastchance3.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * Copyright 2001, 2014 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
diff --git a/sr_vvms/op_fnzsearch.c b/sr_vvms/op_fnzsearch.c
index 88cacb1..a70bf34 100644
--- a/sr_vvms/op_fnzsearch.c
+++ b/sr_vvms/op_fnzsearch.c
@@ -64,7 +64,7 @@ int op_fnzsearch(mval *file, mint strm, mint mcmd, mval *ret)
}
assert(fab_sea != 0);
index = (short)strm;
- if (mcmd && ((MAX_STRM_CT < index) || ( 0 > index))) /* Bypass stream check for internal uses */
+ if (mcmd && ((MAX_STRM_CT <= index) || ( 0 > index))) /* Bypass stream check for internal uses */
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZSRCHSTRMCT);
MV_FORCE_STR(file);
if (file->str.len > MAX_FN_LEN)
diff --git a/sr_port/op_setzbrk.c b/sr_vvms/op_setzbrk.c
similarity index 75%
copy from sr_port/op_setzbrk.c
copy to sr_vvms/op_setzbrk.c
index 7720e3e..aa6cf1f 100644
--- a/sr_port/op_setzbrk.c
+++ b/sr_vvms/op_setzbrk.c
@@ -30,9 +30,14 @@
#include "gtm_text_alloc.h"
#include "srcline.h"
#include "compiler.h"
+#include "min_max.h"
#ifdef GTM_TRIGGER
# include "trigger_source_read_andor_verify.h"
# include "gtm_trigger_trc.h"
+#else
+# define DBGIFTRIGR(x)
+# define DBGTRIGR(x)
+# define DBGTRIGR_ONLY(x)
#endif
GBLREF z_records zbrk_recs;
@@ -57,7 +62,7 @@ void op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
char *cp, zbloc_buff[MAX_ENTRYREF_LEN], *zbloc_end;
mident *lab_name, *dummy;
mident rname, lname;
- mstr *obj;
+ mstr *obj, tmprtnname;
rhdtyp *routine;
zb_code *addr, tmp_xf_code;
int4 *line_offset_addr, *next_line_offset_addr;
@@ -67,7 +72,8 @@ void op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
uint4 status;
int sstatus;
icode_str indir_src;
- boolean_t deleted, is_trigger;
+ boolean_t deleted;
+ GTMTRIG_ONLY(boolean_t is_trigger);
MV_FORCE_STR(rtn);
MV_FORCE_STR(lab);
@@ -83,18 +89,26 @@ void op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
else
{
GTMTRIG_ONLY(IS_TRIGGER_RTN(&rtn->str, is_trigger));
- GTMTRIG_ONLY(if (is_trigger) DBGTRIGR((stderr, "op_setzbrk: Setting/clearing a zbreak in a trigger\n")));
+ DBGIFTRIGR((stderr, "op_setzbrk: Setting/clearing a zbreak in a trigger\n"));
flush_pio();
if (WANT_CURRENT_RTN(rtn))
routine = CURRENT_RHEAD_ADR(frame_pointer->rvector);
else if (NULL == (routine = find_rtn_hdr(&rtn->str))) /* Note assignment */
{
# ifdef GTM_TRIGGER
+ /* trigger_source_read_andor_verify may alter the length part of the mstr to remove the +BREG
+ * region-name specification (the string component is unmodified). Pass in a copy of the mstr
+ * struct to avoid modification to routine->str as it affects the caller which relies on this
+ * variable being untouched.
+ */
+ tmprtnname = rtn->str;
if (is_trigger)
{
- sstatus = trigger_source_read_andor_verify(&rtn->str, TRIGGER_COMPILE);
- if ((0 != sstatus) || (NULL == (routine = find_rtn_hdr(&rtn->str)))) /* Note assignment */
+ DEBUG_ONLY(routine = NULL;)
+ sstatus = trigger_source_read_andor_verify(&tmprtnname, TRIGGER_COMPILE, &routine);
+ if (0 != sstatus)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TRIGNAMENF, 2, rtn->str.len, rtn->str.addr);
+ assert(NULL != routine);
} else
# endif
{
@@ -108,26 +122,26 @@ void op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
lab_name = NULL;
if (NULL == (line_offset_addr = find_line_addr(routine, &lab->str, offset, &lab_name)))
dec_err(VARLSTCNT(1) ERR_NOPLACE);
- else if (CANCEL_ONE == cnt) /* cancel zbreak */
+ else if (CANCEL_ONE == cnt) /* Cancel ZBREAK */
{
addr = (zb_code *)LINE_NUMBER_ADDR(CURRENT_RHEAD_ADR(routine), line_offset_addr);
addr = find_line_call(addr);
if (NULL != (z_ptr = zr_find(&zbrk_recs, addr)))
- zr_put_free(&zbrk_recs, z_ptr);
+ zr_remove_zbreak(&zbrk_recs, z_ptr);
else
dec_err(VARLSTCNT(1) ERR_NOZBRK);
- } else if (0 <= cnt) /* set zbreak */
+ } else if (0 <= cnt) /* Set ZBREAK */
{
# ifdef ZB_AT_COMMENT_INFO
dummy = NULL;
next_line_offset_addr = find_line_addr(routine, &lab->str, offset + 1, &dummy);
if (NULL != next_line_offset_addr && *next_line_offset_addr == *line_offset_addr)
- { /* we don't recognize the case of last line comment 'coz that line generates LINESTART, RET code */
+ { /* We don't recognize the case of last line comment 'coz that line generates LINESTART, RET code */
dec_err(VARLSTCNT(1) ERR_COMMENT);
assert(lab_name == dummy);
}
# endif
- op_commarg(act, indir_linetail); /* This puts entry in stack and also increments refcnt field */
+ op_commarg(act, indir_linetail); /* This puts entry in stack and also increments refcnt field */
indir_src.str = act->str;
indir_src.code = indir_linetail;
obj = cache_get(&indir_src);
@@ -146,14 +160,14 @@ void op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
{
# ifdef USHBIN_SUPPORTED
if ((NULL != routine->shared_ptext_adr) && (routine->shared_ptext_adr == routine->ptext_adr))
- { /* setting a breakpoint in a shared routine, need to make a private copy */
+ { /* Setting a breakpoint in a shared routine, need to make a private copy */
addr_off = (unsigned char *)addr - routine->ptext_adr;
if (SS_NORMAL == (status = cre_private_code_copy(routine)))
addr = (zb_code *)(routine->ptext_adr + addr_off);
else
{
assert(UNIX_ONLY(ERR_MEMORY) VMS_ONLY(ERR_VMSMEMORY) == status);
- /* convert to label+offset^routine to be presented to the user */
+ /* Convert to label+offset^routine to be presented to the user */
rname.len = rtn->str.len;
rname.addr = rtn->str.addr;
lname.len = lab->str.len;
@@ -164,15 +178,21 @@ void op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
}
}
# endif
- z_ptr = zr_get_free(&zbrk_recs, addr);
+ z_ptr = zr_add_zbreak(&zbrk_recs, addr);
NON_USHBIN_ONLY(fix_pages((unsigned char *)addr, (unsigned char *)addr));
-
- /* save for later restore while cancelling breakpoint */
+ /* Modify the instruction at the ZBREAK site. See zbreaksp.h for description of how this works
+ * on a given platform.
+ *
+ * Save original instruction for later restore when cancelling this breakpoint.
+ */
# ifdef COMPLEX_INSTRUCTION_UPDATE
EXTRACT_OFFSET_TO_M_OPCODE(z_ptr->m_opcode, addr);
# else
- z_ptr->m_opcode = *addr; /* save for later restore while cancelling breakpoint */
+ z_ptr->m_opcode = *addr;
# endif
+ /* Modify op_linestart or op_linefetch transfer table reference instruction to the appropriate
+ * ZBREAK related flavor of instruction instead.
+ */
tmp_xf_code = (z_ptr->m_opcode & ZB_CODE_MASK) >> ZB_CODE_SHIFT;
if (xf_linefetch * SIZEOF(UINTPTR_T) == tmp_xf_code)
{
@@ -194,18 +214,21 @@ void op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
assertpro( ((xf_zbstart * SIZEOF(UINTPTR_T)) == tmp_xf_code)
|| ((xf_zbfetch * SIZEOF(UINTPTR_T)) == tmp_xf_code));
z_ptr->rtn = &(CURRENT_RHEAD_ADR(routine))->routine_name;
- assert(lab_name != NULL);
+ assert(NULL != lab_name);
z_ptr->lab = lab_name;
z_ptr->offset = offset;
z_ptr->mpc = (zb_code *)((unsigned char *)addr - SIZEOF_LA);
+ z_ptr->rtnhdr = routine;
+ USHBIN_ONLY(routine->has_ZBREAK = TRUE); /* USHBIN platforms know which rtns have ZBREAK */
inst_flush(addr, SIZEOF(INST_TYPE));
}
if (z_ptr->action)
- { /* A zbreak command was already set for this line */
- /* Note when new action is same as old action, no resultant changes in zb_refcnt */
- assert(z_ptr->action->zb_refcnt > 0);
+ { /* A ZBREAK command was already set for this line. Note when new action is same as
+ * old action, no resultant changes in zb_refcnt.
+ */
+ assert(0 <z_ptr->action->zb_refcnt);
z_ptr->action->zb_refcnt--;
- assert(z_ptr->action != csp || z_ptr->action->zb_refcnt > 0);
+ assert((z_ptr->action != csp) || (0 <z_ptr->action->zb_refcnt));
}
z_ptr->action = csp;
z_ptr->count = cnt;
diff --git a/sr_vvms/rtnhdr.h b/sr_vvms/rtnhdr.h
index 3bb5525..1343001 100644
--- a/sr_vvms/rtnhdr.h
+++ b/sr_vvms/rtnhdr.h
@@ -136,7 +136,7 @@ typedef struct
#define VERIFY TRUE
#define NOVERIFY FALSE
-int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_t verifytrig);
+int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, rhdtyp **rtn_vec);
void free_src_tbl(rhdtyp *rtn_vector);
unsigned char *find_line_start(unsigned char *in_addr, rhdtyp *routine);
int4 *find_line_addr(rhdtyp *routine, mstr *label, int4 offset, mident **lent_name);
diff --git a/sr_x86_64/merrors_ansi.h b/sr_x86_64/merrors_ansi.h
index 20e9320..f00646a 100644
--- a/sr_x86_64/merrors_ansi.h
+++ b/sr_x86_64/merrors_ansi.h
@@ -609,7 +609,7 @@ const static readonly int error_ansi[] = {
0, /* FREEZEID */
0, /* BLKWRITERR */
0, /* STOPTIMEOUT */
- 0, /* TRIGMODINTP */
+ 0, /* UNUSEDMSG776 */
0, /* BCKUPBUFLUSH */
0, /* NOFORKCORE */
0, /* JNLREAD */
@@ -731,7 +731,7 @@ const static readonly int error_ansi[] = {
0, /* SCNDDBNOUPD */
0, /* MUINFOUINT4 */
0, /* NLMISMATCHCALC */
- 0, /* UNUSEDMSG898 */
+ 0, /* RELINKCTLFULL */
0, /* UNUSEDMSG899 */
0, /* DBBADNSUB */
0, /* DBBADKYNM */
@@ -1200,13 +1200,13 @@ const static readonly int error_ansi[] = {
0, /* SSATTACHSHM */
0, /* TRIGDEFNOSYNC */
0, /* TRESTMAX */
- 0, /* UNUSEDMSG1367 */
+ 0, /* ZLINKBYPASS */
0, /* GBLEXPECTED */
0, /* GVZTRIGFAIL */
0, /* MUUSERLBK */
0, /* SETINSETTRIGONLY */
0, /* DZTRIGINTRIG */
- 0, /* SECNODZTRIGINTP */
+ 0, /* UNUSEDMSG1373 */
0, /* BOOLSIDEFFECT */
0, /* DBBADUPGRDSTATE */
0, /* WRITEWAITPID */
@@ -1218,7 +1218,7 @@ const static readonly int error_ansi[] = {
0, /* JNLORDBFLU */
0, /* ZCCLNUPRTNMISNG */
0, /* ZCINVALIDKEYWORD */
- 0, /* REPLNOMULTILINETRG */
+ 0, /* UNUSEDMSG1385 */
0, /* DBSHMNAMEDIFF */
0, /* SHMREMOVED */
0, /* DEVICEWRITEONLY */
@@ -1370,7 +1370,7 @@ const static readonly int error_ansi[] = {
0, /* ISSPANGBL */
0, /* TPNOSUPPORT */
0, /* GVSUBSERR */
- 0, /* TRIGNOSPANGBL */
+ 0, /* UNUSEDMSG1539 */
0, /* FILTERTIMEDOUT */
0, /* TLSDLLNOOPEN */
0, /* TLSINIT */
@@ -1407,4 +1407,19 @@ const static readonly int error_ansi[] = {
13, /* LABELNOTFND */
0, /* RELINKCTLERR */
0, /* INVLINKTMPDIR */
+ 0, /* NOEDITOR */
+ 0, /* UPDPROC */
+ 0, /* HLPPROC */
+ 0, /* REPLNOHASHTREC */
+ 0, /* REMOTEDBNOTRIG */
+ 0, /* NEEDTRIGUPGRD */
+ 0, /* REQRLNKCTLRNDWN */
+ 0, /* RLNKCTLRNDWNSUC */
+ 0, /* RLNKCTLRNDWNFL */
+ 0, /* MPROFRUNDOWN */
+ 0, /* ZPEEKNOJNLINFO */
+ 0, /* TLSPARAM */
+ 0, /* RLNKRECLATCH */
+ 0, /* RLNKSHMLATCH */
+ 0, /* JOBLVN2LONG */
};
diff --git a/sr_x86_64/merrors_ctl.c b/sr_x86_64/merrors_ctl.c
index 4c4ea08..fc01b83 100644
--- a/sr_x86_64/merrors_ctl.c
+++ b/sr_x86_64/merrors_ctl.c
@@ -330,7 +330,7 @@ LITDEF err_msg merrors[] = {
"FREEZE", "Region: !AD is already frozen", 2,
"NOSELECT", "None of the selected variables exist -- halting", 0,
"EXTRFAIL", "Extract failed for the global ^!AD. MUPIP INTEG should be run.", 2,
- "LDBINFMT", "Corrupt binary format header information", 0,
+ "LDBINFMT", "Unrecognized header for load file", 0,
"NOPREVLINK", "Journal file !AD has a null previous link", 2,
"CCEDUMPON", "", 0,
"CCEDMPQUALREQ", "A qualifier (DB,[NO]ON, or NOW) is required with the DUMP command", 0,
@@ -413,7 +413,7 @@ LITDEF err_msg merrors[] = {
"TEXT", "!AD", 2,
"ZWRSPONE", "Subscript patterns in ZWRITE are atomic; Invalid delimiter", 0,
"FILEDEL", "File !AD successfully deleted", 2,
- "JNLBADLABEL", "Journal file !AD does not have a GT.M Journal File Label", 2,
+ "JNLBADLABEL", "Journal file !AD has a bad GT.M Journal File Label. Expected !AD. Found !AD.", 6,
"JNLREADEOF", "End of journal file encountered for !AD", 2,
"JNLRECFMT", "Journal file record format error encountered", 0,
"BLKTOODEEP", "Block level too deep", 0,
@@ -611,7 +611,7 @@ LITDEF err_msg merrors[] = {
"FREEZEID", "Cache !AD on !AD by freeze id 0x!XL with match 0x!XL from 0x!XJ", 7,
"BLKWRITERR", "Unable to queue disk write for block 0x!XL. Will keep trying.", 1,
"STOPTIMEOUT", "Waited too long for stopped process to release. Region: !AD.", 2,
- "TRIGMODINTP", "Triggers for a given global cannot be both used and modified or removed in the same transaction", 0,
+ "UNUSEDMSG776", "TRIGMODINTP last used in V6.2-000", 0,
"BCKUPBUFLUSH", "Unable to flush buffer for online backup", 0,
"NOFORKCORE", "Unable to fork off process to create core. Core creation postponed.", 0,
"JNLREAD", "Error reading from journal file !AD at offset [0x!XL]", 3,
@@ -644,7 +644,7 @@ LITDEF err_msg merrors[] = {
"JNLRDONLY", "Journal file !AD read only", 2,
"ANCOMPTINC", "Deviceparameter !AD is not compatible with any other deviceparameters in the !AD command", 4,
"ABNCOMPTINC", "Deviceparameter !AD and deviceparameter !AD are not compatible in the !AD command", 6,
- "RECLOAD", "Error loading record number: !UL!/", 1,
+ "RECLOAD", "Error loading record number: !@UQ!/", 1,
"SOCKNOTFND", "Socket !AD not found", 2,
"CURRSOCKOFR", "Current socket of index !UL is out of range. There are only !UL sockets.", 2,
"SOCKETEXIST", "Socket !AD already exists", 2,
@@ -733,7 +733,7 @@ LITDEF err_msg merrors[] = {
"SCNDDBNOUPD", "Database Updates not allowed on the secondary", 0,
"MUINFOUINT4", "!AD : !UL [0x!XL]", 4,
"NLMISMATCHCALC", "Location of !AD expected at 0x!XL, but found at 0x!XL", 4,
- "UNUSEDMSG898", "GTMSECSHRLOGSWH last used in V5.5-000", 0,
+ "RELINKCTLFULL", "Relinkctl file for directory !AD is full (maximum entries !UL)", 3,
"UNUSEDMSG899", "GTMSECSHRDEFLOG last used in V5.5-000", 0,
"DBBADNSUB", "!AD Bad numeric subscript", 2,
"DBBADKYNM", "!AD Bad key name", 2,
@@ -1202,13 +1202,13 @@ LITDEF err_msg merrors[] = {
"SSATTACHSHM", "Error while attaching to shared memory identifier !UL", 1,
"TRIGDEFNOSYNC", "Global ^!AD has triggers defined on the !AD instance but none on the !AD instance. Current journal sequence number is 0x!16 at XQ", 7,
"TRESTMAX", "TRESTART not allowed in a final TP retry more than once", 0,
- "UNUSEDMSG1367", "TPLOCKRESTMAX : Last used in V5.5-000", 0,
+ "ZLINKBYPASS", "ZLINK of !AD bypassed - Identical routine already linked", 2,
"GBLEXPECTED", "Global variable reference expected in this context", 0,
"GVZTRIGFAIL", "ZTRIGGER of a global variable failed. Failure code: !AD.", 2,
"MUUSERLBK", "Abnormal shutdown of replication-enabled database !AD detected", 2,
"SETINSETTRIGONLY", "ISV !AD can only be modified in a 'SET' type trigger", 2,
"DZTRIGINTRIG", "$ZTRIGGER() is not allowed inside trigger context. Trigger name: !AD", 2,
- "SECNODZTRIGINTP", "Sequence number 0x!16 at XQ contains $ZTRIGGER() updates made inside a transaction which the current replicating instance does not support. The replicating instance must be upgraded to at least V5.4-002 to support this type of transaction. Cannot continue", 1,
+ "UNUSEDMSG1373", "SECNODZTRIGINTP : Last used in V6.2-000", 0,
"BOOLSIDEFFECT", "Extrinsic ($$), External call ($&) or $INCREMENT() with potential side effects in Boolean expression", 0,
"DBBADUPGRDSTATE", "Correcting conflicting values for fields describing database version upgrade state in the file header for region !AD (!AD) - make fresh backups with new journal files immediately.", 4,
"WRITEWAITPID", "PID !UL waited !UL minute(s) for PID !UL to finish writing block 0x!XL in database file !AD", 6,
@@ -1220,7 +1220,7 @@ LITDEF err_msg merrors[] = {
"JNLORDBFLU", "Error flushing database blocks to !AD. See related messages in the operator log", 2,
"ZCCLNUPRTNMISNG", "External call: Cleanup routine name missing. Cannot continue", 0,
"ZCINVALIDKEYWORD", "External call: Invalid keyword found. Cannot continue", 0,
- "REPLNOMULTILINETRG", "Sequence number 0x!16 at XQ contains a trigger definition too large for transmission to the current replicating instance, which does not support multi-line triggers - stopping replication", 1,
+ "UNUSEDMSG1385", "REPLNOMULTILINETRG : Last used in V6.2-000", 0,
"DBSHMNAMEDIFF", "Database file !AD points to shared memory (id = !UL) which points to a different database file !AZ", 4,
"SHMREMOVED", "Removed Shared Memory id !UL corresponding to file !AD", 3,
"DEVICEWRITEONLY", "Cannot read from a write-only device", 0,
@@ -1240,7 +1240,7 @@ LITDEF err_msg merrors[] = {
"JIUNHNDINT", "An error during $ZINTERRUPT processing was not handled: !AD", 2,
"GTMASSERT2", "!AD - Assert failed !AD line !UL for expression (!AD)", 7,
"ZTRIGNOTRW", "ZTRIGGER cannot operate on read-only region !AD", 2,
- "TRIGMODREGNOTRW", "Trigger(s) cannot be added/changed/deleted because region !AD is read-only", 2,
+ "TRIGMODREGNOTRW", "Trigger(s) cannot be added/changed/deleted/upgraded because region !AD is read-only", 2,
"INSNOTJOINED", "Replicating Instance !AD is not a member of the same Group as Instance !AD", 4,
"INSROLECHANGE", "Supplementary Instance !AD and non-Supplementary Instance !AD belong to the same Group", 4,
"INSUNKNOWN", "Supplementary Instance !AD has no instance definition for non-Supplementary Instance !AD", 4,
@@ -1372,7 +1372,7 @@ LITDEF err_msg merrors[] = {
"ISSPANGBL", "Operation cannot be performed on global ^!AD as it spans multiple regions in current global directory", 2,
"TPNOSUPPORT", "Operation cannot be performed while inside of a TP transaction", 0,
"GVSUBSERR", "Invalid subscripted global name specification in $VIEW() function", 0,
- "TRIGNOSPANGBL", "Triggers cannot be installed/deleted for global name !AD as it spans multiple regions in current global directory", 2,
+ "UNUSEDMSG1539", "TRIGNOSPANBL : Last used in V6.2-000", 0,
"FILTERTIMEDOUT", "Replication server timed out attempting to read seqno !16 at XQ from external filter", 1,
"TLSDLLNOOPEN", "Failed to load GT.M TLS/SSL library for secure communication", 0,
"TLSINIT", "Failed to initialize GT.M TLS/SSL library for secure communication", 0,
@@ -1409,6 +1409,21 @@ LITDEF err_msg merrors[] = {
"LABELNOTFND", "GOTO referenced a label that does not exist", 0,
"RELINKCTLERR", "Error with relink control structure for $ZROUTINES directory !AD", 2,
"INVLINKTMPDIR", "Value for $gtm_linktmpdir is either not found or not a directory: !AD", 2,
+ "NOEDITOR", "Can't find an executable editor: !AD", 2,
+ "UPDPROC", "Update Process error", 0,
+ "HLPPROC", "Helper Process error", 0,
+ "REPLNOHASHTREC", "Sequence number 0x!16 at XQ contains trigger definition updates. !AD side must be at least V6.2-000 for replication to continue", 3,
+ "REMOTEDBNOTRIG", "Trigger operations on global !AD not supported as it maps to database region !AD that points to a remote file", 4,
+ "NEEDTRIGUPGRD", "Cannot do trigger operation on database file !AD until it is upgraded; Run MUPIP TRIGGER -UPGRADE first", 2,
+ "REQRLNKCTLRNDWN", "Error accessing relinkctl file for $ZROUTINES directory !AD. Must be rundown", 2,
+ "RLNKCTLRNDWNSUC", "Relinkctl file for $ZROUTINES directory !AD successfully rundown", 2,
+ "RLNKCTLRNDWNFL", "Relinkctl file for $ZROUTINES directory !AD failed to rundown as it is open by !UL process(es)", 3,
+ "MPROFRUNDOWN", "Error during M-profiling rundown", 0,
+ "ZPEEKNOJNLINFO", "$ZPEEK() unable to access requested journal structure - region !AD is not currently journaled", 2,
+ "TLSPARAM", "TLS parameter !AD !AD", 4,
+ "RLNKRECLATCH", "Failed to get latch on relinkctl record for routine name !AZ in $ZROUTINES directory !AD", 3,
+ "RLNKSHMLATCH", "Failed to get latch on relinkctl shared memory for $ZROUTINES directory !AD", 2,
+ "JOBLVN2LONG", "The zwrite representation of a local variable transferred to a JOB'd process can not exceed !UL. Encountered size: !UL", 2,
};
LITDEF int ERR_ACK = 150372361;
@@ -2009,7 +2024,7 @@ LITDEF int ERR_MEMORYRECURSIVE = 150377116;
LITDEF int ERR_FREEZEID = 150377123;
LITDEF int ERR_BLKWRITERR = 150377131;
LITDEF int ERR_STOPTIMEOUT = 150377138;
-LITDEF int ERR_TRIGMODINTP = 150377146;
+LITDEF int ERR_UNUSEDMSG776 = 150377146;
LITDEF int ERR_BCKUPBUFLUSH = 150377154;
LITDEF int ERR_NOFORKCORE = 150377160;
LITDEF int ERR_JNLREAD = 150377170;
@@ -2131,7 +2146,7 @@ LITDEF int ERR_SECONDAHEAD = 150378090;
LITDEF int ERR_SCNDDBNOUPD = 150378098;
LITDEF int ERR_MUINFOUINT4 = 150378107;
LITDEF int ERR_NLMISMATCHCALC = 150378114;
-LITDEF int ERR_UNUSEDMSG898 = 150378122;
+LITDEF int ERR_RELINKCTLFULL = 150378122;
LITDEF int ERR_UNUSEDMSG899 = 150378131;
LITDEF int ERR_DBBADNSUB = 150378138;
LITDEF int ERR_DBBADKYNM = 150378146;
@@ -2600,13 +2615,13 @@ LITDEF int ERR_TCOMMITDISALLOW = 150381842;
LITDEF int ERR_SSATTACHSHM = 150381850;
LITDEF int ERR_TRIGDEFNOSYNC = 150381856;
LITDEF int ERR_TRESTMAX = 150381866;
-LITDEF int ERR_UNUSEDMSG1367 = 150381874;
+LITDEF int ERR_ZLINKBYPASS = 150381875;
LITDEF int ERR_GBLEXPECTED = 150381882;
LITDEF int ERR_GVZTRIGFAIL = 150381890;
LITDEF int ERR_MUUSERLBK = 150381898;
LITDEF int ERR_SETINSETTRIGONLY = 150381906;
LITDEF int ERR_DZTRIGINTRIG = 150381914;
-LITDEF int ERR_SECNODZTRIGINTP = 150381922;
+LITDEF int ERR_UNUSEDMSG1373 = 150381922;
LITDEF int ERR_BOOLSIDEFFECT = 150381928;
LITDEF int ERR_DBBADUPGRDSTATE = 150381936;
LITDEF int ERR_WRITEWAITPID = 150381946;
@@ -2618,7 +2633,7 @@ LITDEF int ERR_GTMSECSHRCHDIRF = 150381986;
LITDEF int ERR_JNLORDBFLU = 150381994;
LITDEF int ERR_ZCCLNUPRTNMISNG = 150382002;
LITDEF int ERR_ZCINVALIDKEYWORD = 150382010;
-LITDEF int ERR_REPLNOMULTILINETRG = 150382018;
+LITDEF int ERR_UNUSEDMSG1385 = 150382018;
LITDEF int ERR_DBSHMNAMEDIFF = 150382026;
LITDEF int ERR_SHMREMOVED = 150382035;
LITDEF int ERR_DEVICEWRITEONLY = 150382042;
@@ -2770,7 +2785,7 @@ LITDEF int ERR_GBLNOMAPTOREG = 150383202;
LITDEF int ERR_ISSPANGBL = 150383210;
LITDEF int ERR_TPNOSUPPORT = 150383218;
LITDEF int ERR_GVSUBSERR = 150383226;
-LITDEF int ERR_TRIGNOSPANGBL = 150383234;
+LITDEF int ERR_UNUSEDMSG1539 = 150383234;
LITDEF int ERR_FILTERTIMEDOUT = 150383242;
LITDEF int ERR_TLSDLLNOOPEN = 150383250;
LITDEF int ERR_TLSINIT = 150383258;
@@ -2807,9 +2822,24 @@ LITDEF int ERR_CRYPTBADWRTPOS = 150383498;
LITDEF int ERR_LABELNOTFND = 150383506;
LITDEF int ERR_RELINKCTLERR = 150383514;
LITDEF int ERR_INVLINKTMPDIR = 150383522;
+LITDEF int ERR_NOEDITOR = 150383530;
+LITDEF int ERR_UPDPROC = 150383538;
+LITDEF int ERR_HLPPROC = 150383546;
+LITDEF int ERR_REPLNOHASHTREC = 150383554;
+LITDEF int ERR_REMOTEDBNOTRIG = 150383562;
+LITDEF int ERR_NEEDTRIGUPGRD = 150383570;
+LITDEF int ERR_REQRLNKCTLRNDWN = 150383578;
+LITDEF int ERR_RLNKCTLRNDWNSUC = 150383587;
+LITDEF int ERR_RLNKCTLRNDWNFL = 150383594;
+LITDEF int ERR_MPROFRUNDOWN = 150383602;
+LITDEF int ERR_ZPEEKNOJNLINFO = 150383610;
+LITDEF int ERR_TLSPARAM = 150383618;
+LITDEF int ERR_RLNKRECLATCH = 150383626;
+LITDEF int ERR_RLNKSHMLATCH = 150383634;
+LITDEF int ERR_JOBLVN2LONG = 150383642;
GBLDEF err_ctl merrors_ctl = {
246,
"GTM",
&merrors[0],
- 1396};
+ 1411};
diff --git a/sr_x86_64/obj_filesp.c b/sr_x86_64/obj_filesp.c
index 5366dfd..625bf95 100644
--- a/sr_x86_64/obj_filesp.c
+++ b/sr_x86_64/obj_filesp.c
@@ -122,7 +122,7 @@ void create_object_file(rhdtyp *rhead)
/* Action instructions and marker are not kept in the same array since the type of the elements of
* the former (uint4) may be different from the type of the elements of the latter (char).
* 'tiz cleaner this way rather than converting one to the other type in order to be accommodated
- * in an array
+ * in an array.
*/
assert(JSB_ACTION_N_INS * SIZEOF(jsb_action[0]) == SIZEOF(jsb_action)); /* JSB_ACTION_N_INS maintained? */
assert(SIZEOF(jsb_action) <= SIZEOF(rhead->jsb)); /* Overflow check */
@@ -135,8 +135,9 @@ void create_object_file(rhdtyp *rhead)
/* At this point, we know only gtm_object has been written onto the file.
* Read that gtm_object and wrap it up in .text section, add remaining sections to native object(ELF)
- * Update the ELF, write it out to the object file and close the object file */
-void close_object_file(void)
+ * Update the ELF, write it out to the object file and close the object file.
+ */
+void finish_object_file(void)
{
int i, status;
size_t bufSize;
@@ -324,7 +325,5 @@ void close_object_file(void)
/* Free the memory malloc'ed above */
free(string_tbl);
free(gtm_obj_code);
- if ((off_t)-1 == lseek(object_file_des, (off_t)0, SEEK_SET))
- rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_OBJFILERR, 2, object_name_len, object_file_name, errno);
}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/fis-gtm.git
More information about the debian-med-commit
mailing list